<commit_before>package data

import (
	"hash/fnv"
	"io"
	"math"
	"sort"
)

type HashValue uint64

func Hash(v Value) HashValue {
	h := fnv.New64a()
	buffer := make([]byte, 0, 16)
	updateHash(v, h, buffer)
	return HashValue(h.Sum64())
}

func Equal(v1 Value, v2 Value) bool {
	lType := v1.Type()
	rType := v2.Type()
	// cases in which we need a byte array comparison
	if lType == rType || // same type
		(lType == TypeFloat && rType == TypeInt) || // float vs. int
		(lType == TypeInt && rType == TypeFloat) { // int vs. float
		return Hash(v1) == Hash(v2)
	}
	// if we arrive here, types are so different that the values
	// cannot possibly be equal
	return false
}

func appendInt32(b []byte, i int32) []byte {
	return append(b,
		byte(i&0xff),
		byte((i>>8)&0xff),
		byte((i>>16)&0xff),
		byte((i>>24)&0xff),
	)
}

func appendInt64(b []byte, i int64) []byte {
	return append(b,
		byte(i&0xff),
		byte((i>>8)&0xff),
		byte((i>>16)&0xff),
		byte((i>>24)&0xff),
		byte((i>>32)&0xff),
		byte((i>>40)&0xff),
		byte((i>>48)&0xff),
		byte((i>>56)&0xff),
	)
}

func updateHash(v Value, h io.Writer, buffer []byte) []byte {
	switch v.Type() {
	case TypeBlob:
		b, _ := v.asBlob()
		buffer = append(buffer, byte(TypeBlob))
		buffer = appendInt32(buffer, int32(len(b)))
		h.Write(buffer)
		h.Write(b)
	case TypeBool:
		b, _ := v.asBool()
		if b {
			buffer = append(buffer, byte(TypeBool), 1)
		} else {
			buffer = append(buffer, byte(TypeBool), 0)
		}
		h.Write(buffer)
	case TypeFloat:
		f, _ := v.asFloat()
		if float64(int64(f)) == f {
			return updateHash(Int(f), h, buffer)
		}
		buffer = append(buffer, byte(TypeFloat))
		buffer = appendInt64(buffer, int64(math.Float64bits(f)))
		h.Write(buffer)
	case TypeInt:
		i, _ := v.asInt()
		buffer = append(buffer, byte(TypeInt))
		buffer = appendInt64(buffer, i)
		h.Write(buffer)
	case TypeNull:
		buffer = append(buffer, byte(TypeNull))
		h.Write(buffer)
	case TypeString:
		s, _ := v.asString()
		buffer = append(buffer, byte(TypeString))
		buffer = appendInt32(buffer, int32(len(s)))
		h.Write(buffer)
		io.WriteString(h, s)
	case TypeTimestamp:
		t, _ := v.asTimestamp()
		buffer = append(buffer, byte(TypeTimestamp))
		buffer = appendInt64(buffer, t.Unix())
		buffer = appendInt32(buffer, int32(t.Nanosecond()/1000)) // Use microseconds
		h.Write(buffer)
	case TypeArray:
		a, _ := v.asArray()
		buffer = append(buffer, byte(TypeArray))
		buffer = appendInt32(buffer, int32(len(a)))
		h.Write(buffer)
		for _, item := range a {
			buffer = updateHash(item, h, buffer[:0])
		}
	case TypeMap:
		m, _ := v.asMap()
		buffer = append(buffer, byte(TypeMap))
		buffer = appendInt32(buffer, int32(len(m)))
		h.Write(buffer)

		// TODO: reduce this allocation
		keys := make(sort.StringSlice, 0, len(m))
		for key := range m {
			keys = append(keys, key)
		}
		keys.Sort()
		for _, key := range keys {
			buffer = updateHash(String(key), h, buffer[:0])
			buffer = updateHash(m[key], h, buffer[:0])
		}
	}
	return buffer
}
<commit_msg>Reduce number of appends<commit_after>package data

import (
	"hash/fnv"
	"io"
	"math"
	"sort"
)

type HashValue uint64

func Hash(v Value) HashValue {
	h := fnv.New64a()
	buffer := make([]byte, 0, 16)
	updateHash(v, h, buffer)
	return HashValue(h.Sum64())
}

func Equal(v1 Value, v2 Value) bool {
	lType := v1.Type()
	rType := v2.Type()
	// cases in which we need a byte array comparison
	if lType == rType || // same type
		(lType == TypeFloat && rType == TypeInt) || // float vs. int
		(lType == TypeInt && rType == TypeFloat) { // int vs. float
		return Hash(v1) == Hash(v2)
	}
	// if we arrive here, types are so different that the values
	// cannot possibly be equal
	return false
}

func appendInt32(b []byte, t TypeID, i int32) []byte {
	return append(b, byte(t),
		byte(i&0xff),
		byte((i>>8)&0xff),
		byte((i>>16)&0xff),
		byte((i>>24)&0xff),
	)
}

func appendInt64(b []byte, t TypeID, i int64) []byte {
	return append(b, byte(t),
		byte(i&0xff),
		byte((i>>8)&0xff),
		byte((i>>16)&0xff),
		byte((i>>24)&0xff),
		byte((i>>32)&0xff),
		byte((i>>40)&0xff),
		byte((i>>48)&0xff),
		byte((i>>56)&0xff),
	)
}

func updateHash(v Value, h io.Writer, buffer []byte) []byte {
	switch v.Type() {
	case TypeBlob:
		b, _ := v.asBlob()
		buffer = appendInt32(buffer, TypeBlob, int32(len(b)))
		h.Write(buffer)
		h.Write(b)
	case TypeBool:
		b, _ := v.asBool()
		if b {
			buffer = append(buffer, byte(TypeBool), 1)
		} else {
			buffer = append(buffer, byte(TypeBool), 0)
		}
		h.Write(buffer)
	case TypeFloat:
		f, _ := v.asFloat()
		if float64(int64(f)) == f {
			return updateHash(Int(f), h, buffer)
		}
		buffer = appendInt64(buffer, TypeFloat, int64(math.Float64bits(f)))
		h.Write(buffer)
	case TypeInt:
		i, _ := v.asInt()
		buffer = appendInt64(buffer, TypeInt, i)
		h.Write(buffer)
	case TypeNull:
		buffer = append(buffer, byte(TypeNull))
		h.Write(buffer)
	case TypeString:
		s, _ := v.asString()
		buffer = appendInt32(buffer, TypeString, int32(len(s)))
		h.Write(buffer)
		io.WriteString(h, s)
	case TypeTimestamp:
		t, _ := v.asTimestamp()
		buffer = appendInt64(buffer, TypeTimestamp, t.Unix())
		// TODO: This TypeInt isn't necessary.
		buffer = appendInt32(buffer, TypeInt, int32(t.Nanosecond()/1000)) // Use microseconds
		h.Write(buffer)
	case TypeArray:
		a, _ := v.asArray()
		buffer = appendInt32(buffer, TypeArray, int32(len(a)))
		h.Write(buffer)
		for _, item := range a {
			buffer = updateHash(item, h, buffer[:0])
		}
	case TypeMap:
		m, _ := v.asMap()
		buffer = appendInt32(buffer, TypeMap, int32(len(m)))
		h.Write(buffer)

		// TODO: reduce this allocation
		keys := make(sort.StringSlice, 0, len(m))
		for key := range m {
			keys = append(keys, key)
		}
		keys.Sort()
		for _, key := range keys {
			buffer = updateHash(String(key), h, buffer[:0])
			buffer = updateHash(m[key], h, buffer[:0])
		}
	}
	return buffer
}
<|endoftext|>


<commit_before>package rwap

import (
	"net/http"
	"strconv"
)

type ResponseWriter struct {
	http.ResponseWriter
	status        int
	contentLength int64
}

func (w *ResponseWriter) Write(p []byte) (int, error) {
	cl, err := w.ResponseWriter.Write(p)
	w.contentLength += int64(cl)

	return cl, err
}

func (w *ResponseWriter) WriteHeader(status int) {
	if w.status != 0 {
		return
	}

	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *ResponseWriter) Status() int {
	return w.status
}

func (w *ResponseWriter) ContentLength() int64 {
	if w.contentLength > 0 {
		return w.contentLength
	}

	cl, err := strconv.ParseInt(w.Header().Get("Content-Length"), 10, 64)
	if err != nil {
		return 0
	}

	return cl
}

func Wrap(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		nw := &ResponseWriter{ResponseWriter: w}
		next.ServeHTTP(nw, r)
	})
}
<commit_msg>Remove status write protection.<commit_after>package rwap

import (
	"net/http"
	"strconv"
)

type ResponseWriter struct {
	http.ResponseWriter
	status        int
	contentLength int64
}

func (w *ResponseWriter) Write(p []byte) (int, error) {
	cl, err := w.ResponseWriter.Write(p)
	w.contentLength += int64(cl)

	return cl, err
}

func (w *ResponseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *ResponseWriter) Status() int {
	return w.status
}

func (w *ResponseWriter) ContentLength() int64 {
	if w.contentLength > 0 {
		return w.contentLength
	}

	cl, err := strconv.ParseInt(w.Header().Get("Content-Length"), 10, 64)
	if err != nil {
		return 0
	}

	return cl
}

func Wrap(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		nw := &ResponseWriter{ResponseWriter: w}
		next.ServeHTTP(nw, r)
	})
}
<|endoftext|>


<commit_before>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"encoding/json"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      int64
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 8)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 8 {
			return
		}
		crId, _ := binary.Varint(b)

		room := &Room{crId, c1, c2}

		fmt.Println("ChatroomID: ", crId)

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	fmt.Println(session.Values)
	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

  	fmt.Println("uid: ", uid)
	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	fmt.Println("added ", uid, " to queue")
	chatroom := <- retChan

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":", chatroom.id, "}")
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	fmt.Fprint(w, uid)
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println(uid)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}-", message)
	} else {
		fmt.Fprint(w, "{\"status\":\"failure\"}-", message)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		fmt.Println("client found")
		select {
		case message, ok := <- clients[uid].in:
			fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Println("")
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Println("client not found")
		fmt.Fprint(w, "")
	}
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, "{\"status\":\"failure\"}")
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, "{\"status\":\"failure\"}")
					return
				}
			}

		}

		fmt.Println("session-id: ", iq.Id)

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Println(session.Values)

		fmt.Fprint(w, "{\"status\":\"success\"}")

	// 	if err == nil {
	// 		fmt.Fprint(w, "{\"status\":\"success\",\"uid\":", iq.Id, "}")
	// 	} else {
	// 		_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
	// 		if err == nil {
	// 			row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
	// 			err = row.Scan(&iq.Id)
	// 			if err == nil {
	// 				fmt.Fprint(w, "{\"status\":\"success\"},\"uid\":", iq.Id, "}")
	// 			} else {
	// 				fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 			}
	// 		} else {
	// 			fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 		}
	// 	}
	// } else {
	// 	fmt.Fprint(w, "{\"status\":\"failure\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

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

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>index.html<commit_after>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"encoding/json"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      int64
	client1 *Client
	client2 *Client
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 8)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 8 {
			return
		}
		crId, _ := binary.Varint(b)

		room := &Room{crId, c1, c2}

		fmt.Println("ChatroomID: ", crId)

		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

type IdQuery struct {
    Id            int64      `json:"id"`

}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}
	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":", chatroom.id, "}")
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	fmt.Fprint(w, uid)
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	message := r.FormValue("s")

	// message := r.PostFormValue("message")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}-", message)
	} else {
		fmt.Fprint(w, "{\"status\":\"failure\"}-", message)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- clients[uid].in:
			// fmt.Println("message pulled from channel")
			if ok {
				fmt.Fprint(w, message)
			} else {
				fmt.Fprint(w, "")
			}
		default:
			fmt.Fprint(w, "")
		}

	} else {
		fmt.Fprint(w, "")
	}
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		iq := new(IdQuery)
		err := row.Scan(&iq.Id)

		if err != nil {
			_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, "{\"status\":\"failure\"}")
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&iq.Id)
				if err != nil {
					fmt.Fprint(w, "{\"status\":\"failure\"}")
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = iq.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")

	// 	if err == nil {
	// 		fmt.Fprint(w, "{\"status\":\"success\",\"uid\":", iq.Id, "}")
	// 	} else {
	// 		_, err = db.Exec("insert into users (facebook_id, username, email, level, points) values (?, ?, ?, 0, 0)", uid, "", "")
	// 		if err == nil {
	// 			row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
	// 			err = row.Scan(&iq.Id)
	// 			if err == nil {
	// 				fmt.Fprint(w, "{\"status\":\"success\"},\"uid\":", iq.Id, "}")
	// 			} else {
	// 				fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 			}
	// 		} else {
	// 			fmt.Fprint(w, "{\"status\":\"failure\"}")
	// 		}
	// 	}
	// } else {
	// 	fmt.Fprint(w, "{\"status\":\"failure\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

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

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"os/exec"

	vc "github.com/containers/virtcontainers"
	"github.com/golang/glog"
)

// ShimConfig holds configuration data related to a shim.
type ShimConfig struct {
	Path string
}

func startShim(process *vc.Process, config ShimConfig, url string) (int, error) {
	if process.Token == "" {
		return -1, fmt.Errorf("Token cannot be empty")
	}

	if url == "" {
		return -1, fmt.Errorf("URL cannot be empty")
	}

	if config.Path == "" {
		config.Path = defaultShimPath
	}
	glog.Infof("Shim binary path: %s\n", config.Path)

	cmd := exec.Cmd{
		Path: config.Path,
		Args: []string{"-t", process.Token, "-u", url},
		Env:  os.Environ(),
	}

	if err := cmd.Start(); err != nil {
		return -1, err
	}

	return cmd.Process.Pid, nil
}

func startContainerShim(container *vc.Container, config ShimConfig, url string) (int, error) {
	process := container.Process()

	pid, err := startShim(&process, config, url)
	if err != nil {
		return -1, err
	}

	if err := container.SetPid(pid); err != nil {
		return -1, err
	}

	return pid, nil
}
<commit_msg>shim: Fix execution of cc-shim binary<commit_after>// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"os/exec"

	vc "github.com/containers/virtcontainers"
	"github.com/golang/glog"
)

// ShimConfig holds configuration data related to a shim.
type ShimConfig struct {
	Path string
}

func startShim(process *vc.Process, config ShimConfig, url string) (int, error) {
	if process.Token == "" {
		return -1, fmt.Errorf("Token cannot be empty")
	}

	if url == "" {
		return -1, fmt.Errorf("URL cannot be empty")
	}

	if config.Path == "" {
		config.Path = defaultShimPath
	}
	glog.Infof("Shim binary path: %s\n", config.Path)

	cmd := exec.Command(config.Path, "-t", process.Token, "-u", url)
	cmd.Env = os.Environ()

	if err := cmd.Start(); err != nil {
		return -1, err
	}

	return cmd.Process.Pid, nil
}

func startContainerShim(container *vc.Container, config ShimConfig, url string) (int, error) {
	process := container.Process()

	pid, err := startShim(&process, config, url)
	if err != nil {
		return -1, err
	}

	if err := container.SetPid(pid); err != nil {
		return -1, err
	}

	return pid, nil
}
<|endoftext|>


<commit_before>package main

import (
	"./skyd"
	"flag"
	"fmt"
	"runtime"
)

//------------------------------------------------------------------------------
//
// Constants
//
//------------------------------------------------------------------------------

const (
	defaultPort = 8585
	defaultDataDir = "/var/lib/sky"
)

const (
	portUsage = "the port to listen on"
	dataDirUsage = "the data directory"
)

//------------------------------------------------------------------------------
//
// Variables
//
//------------------------------------------------------------------------------

var port uint
var dataDir string

//------------------------------------------------------------------------------
//
// Functions
//
//------------------------------------------------------------------------------

func init() {
	flag.UintVar(&port, "port", defaultPort, portUsage)
	flag.UintVar(&port, "p", defaultPort, portUsage+"(shorthand)")
	flag.StringVar(&dataDir, "data-dir", defaultDataDir, dataDirUsage)
	flag.StringVar(&dataDir, "d", defaultDataDir, dataDirUsage+"(shorthand)")
}

func main() {
	// Parse the command line arguments.
	flag.Parse()

	// Hardcore parallelism right here.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Start the server up!
	c := make(chan bool)
	server := skyd.NewServer(port, dataDir)
	err := server.ListenAndServe(c)
	if err != nil {
		fmt.Printf("%v\n", err)
		return
	}
	<- c
}<commit_msg>Add pid file and signal handler.<commit_after>package main

import (
	"./skyd"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"os/signal"
)

//------------------------------------------------------------------------------
//
// Constants
//
//------------------------------------------------------------------------------

const (
	defaultPort = 8585
	defaultDataDir = "/var/lib/sky"
)

const (
	portUsage = "the port to listen on"
	dataDirUsage = "the data directory"
)

const (
	pidPath = "/var/run/skyd.pid"
)

//------------------------------------------------------------------------------
//
// Variables
//
//------------------------------------------------------------------------------

var port uint
var dataDir string

//------------------------------------------------------------------------------
//
// Functions
//
//------------------------------------------------------------------------------

//--------------------------------------
// Initialization
//--------------------------------------

func init() {
	flag.UintVar(&port, "port", defaultPort, portUsage)
	flag.UintVar(&port, "p", defaultPort, portUsage+"(shorthand)")
	flag.StringVar(&dataDir, "data-dir", defaultDataDir, dataDirUsage)
	flag.StringVar(&dataDir, "d", defaultDataDir, dataDirUsage+"(shorthand)")
}

//--------------------------------------
// Main
//--------------------------------------

func main() {
	// Parse the command line arguments.
	flag.Parse()

	// Hardcore parallelism right here.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Initialize
	server := skyd.NewServer(port, dataDir)
	writePidFile()
	setupSignalHandlers(server)

	// Start the server up!
	c := make(chan bool)
	err := server.ListenAndServe(c)
	if err != nil {
		fmt.Printf("%v\n", err)
		return
	}
	<- c

	// Remove PID file.
	deletePidFile()
}

//--------------------------------------
// Signals
//--------------------------------------

// Handles signals received from the OS.
func setupSignalHandlers(server *skyd.Server) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func(){
	    for _ = range c {
			fmt.Fprintln(os.Stderr, "Shutting down...")
			server.Shutdown()
			deletePidFile();
	    }
	}()
}

//--------------------------------------
// PID
//--------------------------------------

// Writes a file to /var/run that contains the current process id.
func writePidFile() {
	pid := fmt.Sprintf("%d", os.Getpid())
	if err := ioutil.WriteFile(pidPath, []byte(pid), 0644); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to write pid file: %v\n", err)
	}
}

// Deletes the pid file.
func deletePidFile() {
	if _, err := os.Stat(pidPath); !os.IsNotExist(err) {
		if err = os.Remove(pidPath); err != nil {
			fmt.Fprintf(os.Stderr, "Unable to remove pid file: %v\n", err)
		}
	}
}<|endoftext|>


<commit_before>package response

import (
    "reflect"
    "strings"
    "encoding/json"
)

func isSlice(i interface{}) bool {
    return reflect.TypeOf(i).Kind() == reflect.Slice
}

func hasLength(i interface{}) int {
    if !isSlice(i) {
        return -1
    }
    return reflect.ValueOf(i).Len()
}

func marshal(i interface{}) (string, error) {
    var jdata []byte
    var err error

    if respIndent < 1 {
        jdata, err = json.Marshal(i)
    } else {
        jdata, err = json.MarshalIndent(i, "", strings.Repeat(" ", respIndent))
    }

    if err != nil {
        return "ERROR", err
    }
    return string(jdata), nil
}
<commit_msg>Fixed error on record count being returned<commit_after>package response

import (
    "reflect"
    "strings"
    "encoding/json"
    //log "github.com/zdannar/flogger"
)

func isSlice(i interface{}) (bool, bool) {
    if reflect.TypeOf(i).Kind() == reflect.Ptr {
        // Get Indirect and check for slice
        return reflect.Indirect(reflect.ValueOf(i)).Kind() == reflect.Slice, true
    }

    return reflect.TypeOf(i).Kind() == reflect.Slice, false
}

func hasLength(i interface{}) int {
    is, indirectly := isSlice(i)
    if !is {
        return -1
    }
    if indirectly {
        return reflect.Indirect(reflect.ValueOf(i)).Len()
    }
    return reflect.ValueOf(i).Len()
}

func marshal(i interface{}) (string, error) {
    var jdata []byte
    var err error

    if respIndent < 1 {
        jdata, err = json.Marshal(i)
    } else {
        jdata, err = json.MarshalIndent(i, "", strings.Repeat(" ", respIndent))
    }

    if err != nil {
        return "ERROR", err
    }
    return string(jdata), nil
}
<|endoftext|>


<commit_before>/*
 * Go Solr, a Solr library written in Go.
 * Original author Rich Taylor, 2012 - http://rsty.org/, http://github.com/rtt/
 * Released under the "do whatever the fuck you want" license. http://sam.zoy.org/wtfpl/
 */

package solr

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

/*
 * Represents a "connection"; actually just a host and port
 * (and probably at some point a Solr Core name)
 */
type Connection struct {
	Host    string
	Port    int
	Core    string
	Version []int
}

/*
 * Represents a Solr document, as returned by Select queries
 */
type Document struct {
	Fields map[string]interface{}
}

/*
 * Represents a FacetCount for a Facet
 */
type FacetCount struct {
	Value string
	Count int
}

/* chunked size of facet solr return format */
var facet_chunk_size int = 2

/*
 * Represents a Facet with a name and count
 */
type Facet struct {
	Name   string       // accepts_4x4s
	Counts []FacetCount // a set of values
}

/*
 * Represents a collection of solr documents
 * and various other metrics
 */
type DocumentCollection struct {
	Facets     []Facet
	Collection []Document
	NumFacets  int // convenience...
	NumFound   int
	Start      int
}

/*
 * Represents a Solr response
 */
type SelectResponse struct {
	Results *DocumentCollection
	Status  int
	QTime   int
	// TODO: Debug info as well?
}

/*
 * Represents an error from Solr
 */
type ErrorResponse struct {
	Message string
	Status  int
}

type UpdateResponse struct {
	Success bool
}

/*
 * Holds URL parameters
 */
type URLParamMap map[string][]string

/*
 * Query represents a query with various params
 */
type Query struct {
	Params     URLParamMap
	Rows       int
	Start      int
	Sort       string
	DefType    string
	Debug      bool
	OmitHeader bool
}

/*
 * Query.String() returns the Query in solr query string format
 */
func (q *Query) String() string {
	// TODO: this is kinda ugly
	s := []string{}

	if len(q.Params) > 0 {
		s = append(s, EncodeURLParamMap(&q.Params))
	}

	if q.Rows != 0 {
		s = append(s, fmt.Sprintf("rows=%d", q.Rows))
	}

	if q.Start != 0 {
		s = append(s, fmt.Sprintf("start=%d", q.Start))
	}

	if q.Sort != "" {
		s = append(s, fmt.Sprintf("sort=%s", q.Sort))
	}

	if q.DefType != "" {
		s = append(s, fmt.Sprintf("deftype=%s", q.DefType))
	}

	if q.Debug {
		s = append(s, fmt.Sprintf("debugQuery=true"))
	}

	if q.OmitHeader {
		s = append(s, fmt.Sprintf("omitHeader=true"))
	}

	return strings.Join(s, "&")
}

/*
 * DocumentCollection.Get() returns the document in the collection
 * at position i
 */
func (d *DocumentCollection) Get(i int) *Document {
	return &d.Collection[i]
}

/*
 * DocumentCollection.Len() returns the amount of documents
 * in the collection
 */
func (d *DocumentCollection) Len() int {
	return len(d.Collection)
}

/*
 * Document.Field() returns the value of the given field name in the document
 */
func (document Document) Field(field string) interface{} {
	r, _ := document.Fields[field]
	return r
}

/*
 * Document.Doc() returns the raw document (map)
 */
func (document Document) Doc() map[string]interface{} {
	return document.Fields
}

func (r SelectResponse) String() string {
	return fmt.Sprintf("SelectResponse: %d Results, Status: %d, QTime: %d", r.Results.Len(), r.Status, r.QTime)
}

func (r ErrorResponse) String() string {
	return fmt.Sprintf("Solr Error: [code: %d, msg: \"%s\"]", r.Status, r.Message)
}

func (r UpdateResponse) String() string {
	if r.Success {
		return fmt.Sprintf("UpdateResponse: OK")
	}
	return fmt.Sprintf("UpdateResponse: FAIL")
}

/*
 * Performs a GET request to the given url
 * Returns a []byte containing the response body
 */
func HTTPGet(url string) ([]byte, error) {

	r, err := http.Get(url)

	if err != nil {
		return nil, err
	}

	defer r.Body.Close()

	if err != nil {
		return nil, fmt.Errorf("GET failed (%s)", url)
	}

	// read the response and check
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("Response read failed")
	}

	return body, nil
}

/*
 * Performs a HTTP Post request. Takes:
 * * A url
 * * Headers, in the format [][]string{} (e.g., [[key, val], [key, val], ...])
 * * A payload (post request body) which can be nil
 * * Returns the body of the response and an error if necessary
 */
func HTTPPost(url string, headers [][]string, payload *[]byte) ([]byte, error) {
	// setup post client
	client := &http.Client{}
	req, err := http.NewRequest("POST", url, bytes.NewReader(*payload))

	// add headers
	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	// perform request
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if err != nil {
		return nil, fmt.Errorf(fmt.Sprintf("POST request failed: %s", err))
	}

	// read response, check & return
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

/*
 * Returns a URLEncoded version of a Param Map
 * E.g., ParamMap[foo:bar omg:wtf] => "foo=bar&omg=wtf"
 * TODO: This isn't exactly safe and there's probably a library pkg to do this already...
 */
func EncodeURLParamMap(m *URLParamMap) string {
	r := []string{}

	for k, v := range *m {
		l := len(v)
		for x := 0; x < l; x++ {
			r = append(r, fmt.Sprintf("%s=%s", k, v[x]))
		}
	}

	return strings.Join(r, "&")
}

/*
 * Generates a Solr query string from a connection and a query string
 */
func SolrSelectString(c *Connection, q string) string {
	return fmt.Sprintf("http://%s:%d/solr/select?wt=json&%s", c.Host, c.Port, q)
}

/*
 * Generates a Solr update query string. Adds ?commit=true
 * if commit arg is true.
 */
func SolrUpdateString(c *Connection, commit bool) string {
	s := fmt.Sprintf("http://%s:%d/solr/update", c.Host, c.Port)
	if commit {
		return fmt.Sprintf("%s?commit=true", s)
	}
	return s
}

/*
 * Decodes a json formatted []byte into an interface{} type
 */
func BytesToJSON(b *[]byte) (*interface{}, error) {
	var container interface{}
	err := json.Unmarshal(*b, &container)

	if err != nil {
		return nil, fmt.Errorf("Response decode error")
	}

	return &container, nil
}

/*
 * Encodes a map[string]interface{} to bytes and returns
 * a pointer to said bytes
 */
func JSONToBytes(m map[string]interface{}) (*[]byte, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode JSON")
	}

	return &b, nil
}

/*
 * Takes a JSON formatted Solr response (interface{}, not []byte)
 * And returns a *Response
 */
func BuildResponse(j *interface{}) (*SelectResponse, error) {

	// look for a response element, bail if not present
	response_root := (*j).(map[string]interface{})
	response := response_root["response"]
	if response == nil {
		return nil, fmt.Errorf("Supplied interface appears invalid (missing response)")
	}

	// begin Response creation
	r := SelectResponse{}

	// do status & qtime, if possible
	r_header := (*j).(map[string]interface{})["responseHeader"].(map[string]interface{})
	if r_header != nil {
		r.Status = int(r_header["status"].(float64))
		r.QTime = int(r_header["QTime"].(float64))
	}

	// now do docs, if they exist in the response
	docs := response.(map[string]interface{})["docs"].([]interface{})
	if docs != nil {
		// the total amount of results, irrespective of the amount returned in the response
		num_found := int(response.(map[string]interface{})["numFound"].(float64))

		// and the amount actually returned
		num_results := len(docs)

		coll := DocumentCollection{}
		coll.NumFound = num_found

		ds := []Document{}

		for i := 0; i < num_results; i++ {
			ds = append(ds, Document{docs[i].(map[string]interface{})})
		}

		coll.Collection = ds
		r.Results = &coll
	}

	// facets
	facet_response, ok := response_root["facet_counts"].(interface{})
	if ok == true {
		facet_counts := facet_response.(map[string]interface{})
		if facet_counts != nil {
			// do counts if they exist
			facet_fields := facet_counts["facet_fields"].(map[string]interface{})
			facets := []Facet{}
			if facet_fields != nil {
				// iterate over each facet field, create facet & counts for each field
				for k, v := range facet_fields {
					f := Facet{Name: k}
					chunked := chunk(v.([]interface{}), facet_chunk_size)
					lc := len(chunked)
					for i := 0; i < lc; i++ {
						f.Counts = append(f.Counts, FacetCount{
							Value: chunked[i][0].(string),
							Count: int(chunked[i][1].(float64)),
						})
					}
					facets = append(facets, f)
				}
			}

			// add Facets to collection
			r.Results.Facets = facets
			r.Results.NumFacets = len(facets)

		}
	}

	return &r, nil
}

/*
 * Decodes a HTTP (Solr) response and returns a Response
 */
func SelectResponseFromHTTPResponse(b []byte) (*SelectResponse, error) {
	j, err := BytesToJSON(&b)
	if err != nil {
		return nil, fmt.Errorf("Unable to decode")
	}

	resp, err := BuildResponse(j)
	if err != nil {
		return nil, fmt.Errorf("Error building response")
	}

	return resp, nil
}

/*
 * Determines whether a decoded response from Solr
 * is an error response or not. Returns a bool (true if error)
 * and an ErrorResponse (if the response is an error response)
 * otherwise nil
 */
func SolrErrorResponse(m map[string]interface{}) (bool, *ErrorResponse) {
	// check for existance of "error" key
	if _, found := m["error"]; found {
		error := m["error"].(map[string]interface{})
		return true, &ErrorResponse{
			Message: error["msg"].(string),
			Status:  int(error["code"].(float64)),
		}
	}
	return false, nil
}

/*
 * Similar to python's itertools.izip_longest;
 * takes an array and chunks it according to a given splice size
 * eg: chnunk([1,2,3,4,5,6], 2) == [[1,2], [3,4], [5,6]]
 */
func chunk(s []interface{}, sz int) [][]interface{} {
	r := [][]interface{}{}
	j := len(s)
	for i := 0; i < j; i += sz {
		r = append(r, s[i:i+sz])
	}
	return r
}

/*
 * Inits a new Connection to a Solr instance
 * Note: this doesn't actually hold a connection, its just
 *       a container for holding a hostname & port
 */
func Init(host string, port int) (*Connection, error) {

	if len(host) == 0 {
		return nil, fmt.Errorf("Invalid hostname (must be length >= 1)")
	}

	if port <= 0 || port > 65535 {
		return nil, fmt.Errorf("Invalid port (must be 1..65535")
	}

	return &Connection{Host: host, Port: port}, nil
}

/*
 * Performs a Select query given a Query
 */
func (c *Connection) Select(q *Query) (*SelectResponse, error) {
	body, err := HTTPGet(SolrSelectString(c, q.String()))

	if err != nil {
		return nil, fmt.Errorf("Some sort of http failure") // TODO: investigate how net/http fails
	}

	r, err := SelectResponseFromHTTPResponse(body)

	if err != nil {
		return nil, err
	}

	return r, nil
}

/*
 * Performs a raw Select query given a raw query string
 */
func (c *Connection) SelectRaw(q string) (*SelectResponse, error) {
	body, err := HTTPGet(SolrSelectString(c, q))

	if err != nil {
		return nil, fmt.Errorf("Some sort of http failure") // TODO: investigate how net/http fails
	}

	r, err := SelectResponseFromHTTPResponse(body)

	if err != nil {
		return nil, err
	}

	return r, nil
}

/*
 * Performs a Solr Update query against a given update document
 * specified in a map[string]interface{} type
 * NOTE: Requires JSON updates to be enabled, see;
 * http://wiki.apache.org/solr/UpdateJSON
 * FUTURE: Will ask for solr version details in Connection and
 * act appropriately
 */
func (c *Connection) Update(m map[string]interface{}, commit bool) (*UpdateResponse, error) {

	// encode "json" to a byte array & check
	payload, err := JSONToBytes(m)
	if err != nil {
		return nil, err
	}

	// perform request
	resp, err := HTTPPost(
		SolrUpdateString(c, commit),
		[][]string{{"Content-Type", "application/json"}},
		payload)

	if err != nil {
		return nil, err
	}

	// decode the response & check
	decoded, err := BytesToJSON(&resp)
	if err != nil {
		return nil, err
	}

	error, report := SolrErrorResponse((*decoded).(map[string]interface{}))
	if error {
		return nil, fmt.Errorf(fmt.Sprintf("%s", *report))
	}

	return &UpdateResponse{true}, nil
}

// func (c *Connection) Commit() (*UpdateResponse, error) {

// }
<commit_msg>Make the library SOLR-CORE aware.<commit_after>/*
 * Go Solr, a Solr library written in Go.
 * Original author Rich Taylor, 2012 - http://rsty.org/, http://github.com/rtt/
 * Released under the "do whatever the fuck you want" license. http://sam.zoy.org/wtfpl/
 */

package solr

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

/*
 * Represents a "connection"; actually just a host and port
 * (and probably at some point a Solr Core name)
 */
type Connection struct {
	Host    string
	Port    int
	Core    string
	Version []int
}

/*
 * Represents a Solr document, as returned by Select queries
 */
type Document struct {
	Fields map[string]interface{}
}

/*
 * Represents a FacetCount for a Facet
 */
type FacetCount struct {
	Value string
	Count int
}

/* chunked size of facet solr return format */
var facet_chunk_size int = 2

/*
 * Represents a Facet with a name and count
 */
type Facet struct {
	Name   string       // accepts_4x4s
	Counts []FacetCount // a set of values
}

/*
 * Represents a collection of solr documents
 * and various other metrics
 */
type DocumentCollection struct {
	Facets     []Facet
	Collection []Document
	NumFacets  int // convenience...
	NumFound   int
	Start      int
}

/*
 * Represents a Solr response
 */
type SelectResponse struct {
	Results *DocumentCollection
	Status  int
	QTime   int
	// TODO: Debug info as well?
}

/*
 * Represents an error from Solr
 */
type ErrorResponse struct {
	Message string
	Status  int
}

type UpdateResponse struct {
	Success bool
}

/*
 * Holds URL parameters
 */
type URLParamMap map[string][]string

/*
 * Query represents a query with various params
 */
type Query struct {
	Params     URLParamMap
	Rows       int
	Start      int
	Sort       string
	DefType    string
	Debug      bool
	OmitHeader bool
}

/*
 * Query.String() returns the Query in solr query string format
 */
func (q *Query) String() string {
	// TODO: this is kinda ugly
	s := []string{}

	if len(q.Params) > 0 {
		s = append(s, EncodeURLParamMap(&q.Params))
	}

	if q.Rows != 0 {
		s = append(s, fmt.Sprintf("rows=%d", q.Rows))
	}

	if q.Start != 0 {
		s = append(s, fmt.Sprintf("start=%d", q.Start))
	}

	if q.Sort != "" {
		s = append(s, fmt.Sprintf("sort=%s", q.Sort))
	}

	if q.DefType != "" {
		s = append(s, fmt.Sprintf("deftype=%s", q.DefType))
	}

	if q.Debug {
		s = append(s, fmt.Sprintf("debugQuery=true"))
	}

	if q.OmitHeader {
		s = append(s, fmt.Sprintf("omitHeader=true"))
	}

	return strings.Join(s, "&")
}

/*
 * DocumentCollection.Get() returns the document in the collection
 * at position i
 */
func (d *DocumentCollection) Get(i int) *Document {
	return &d.Collection[i]
}

/*
 * DocumentCollection.Len() returns the amount of documents
 * in the collection
 */
func (d *DocumentCollection) Len() int {
	return len(d.Collection)
}

/*
 * Document.Field() returns the value of the given field name in the document
 */
func (document Document) Field(field string) interface{} {
	r, _ := document.Fields[field]
	return r
}

/*
 * Document.Doc() returns the raw document (map)
 */
func (document Document) Doc() map[string]interface{} {
	return document.Fields
}

func (r SelectResponse) String() string {
	return fmt.Sprintf("SelectResponse: %d Results, Status: %d, QTime: %d", r.Results.Len(), r.Status, r.QTime)
}

func (r ErrorResponse) String() string {
	return fmt.Sprintf("Solr Error: [code: %d, msg: \"%s\"]", r.Status, r.Message)
}

func (r UpdateResponse) String() string {
	if r.Success {
		return fmt.Sprintf("UpdateResponse: OK")
	}
	return fmt.Sprintf("UpdateResponse: FAIL")
}

/*
 * Performs a GET request to the given url
 * Returns a []byte containing the response body
 */
func HTTPGet(url string) ([]byte, error) {

	r, err := http.Get(url)

	if err != nil {
		return nil, err
	}

	defer r.Body.Close()

	if err != nil {
		return nil, fmt.Errorf("GET failed (%s)", url)
	}

	// read the response and check
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("Response read failed")
	}

	return body, nil
}

/*
 * Performs a HTTP Post request. Takes:
 * * A url
 * * Headers, in the format [][]string{} (e.g., [[key, val], [key, val], ...])
 * * A payload (post request body) which can be nil
 * * Returns the body of the response and an error if necessary
 */
func HTTPPost(url string, headers [][]string, payload *[]byte) ([]byte, error) {
	// setup post client
	client := &http.Client{}
	req, err := http.NewRequest("POST", url, bytes.NewReader(*payload))

	// add headers
	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	// perform request
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	if err != nil {
		return nil, fmt.Errorf(fmt.Sprintf("POST request failed: %s", err))
	}

	// read response, check & return
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

/*
 * Returns a URLEncoded version of a Param Map
 * E.g., ParamMap[foo:bar omg:wtf] => "foo=bar&omg=wtf"
 * TODO: This isn't exactly safe and there's probably a library pkg to do this already...
 */
func EncodeURLParamMap(m *URLParamMap) string {
	r := []string{}

	for k, v := range *m {
		l := len(v)
		for x := 0; x < l; x++ {
			r = append(r, fmt.Sprintf("%s=%s", k, v[x]))
		}
	}

	return strings.Join(r, "&")
}

/*
 * Generates a Solr query string from a connection and a query string
 */
func SolrSelectString(c *Connection, q string) string {
	fmt.Sprintf("http://%s:%d/solr/%s/select?wt=json&%s", c.Host, c.Port,c.Core, q)
	return fmt.Sprintf("http://%s:%d/solr/%s/select?wt=json&%s", c.Host, c.Port,c.Core, q)
}

/*
 * Generates a Solr update query string. Adds ?commit=true
 * if commit arg is true.
 */
func SolrUpdateString(c *Connection, commit bool) string {
	s := fmt.Sprintf("http://%s:%d/solr/update", c.Host, c.Port)
	if commit {
		return fmt.Sprintf("%s?commit=true", s)
	}
	return s
}

/*
 * Decodes a json formatted []byte into an interface{} type
 */
func BytesToJSON(b *[]byte) (*interface{}, error) {
	var container interface{}
	err := json.Unmarshal(*b, &container)

	if err != nil {
		return nil, fmt.Errorf("Response decode error")
	}

	return &container, nil
}

/*
 * Encodes a map[string]interface{} to bytes and returns
 * a pointer to said bytes
 */
func JSONToBytes(m map[string]interface{}) (*[]byte, error) {
	b, err := json.Marshal(m)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode JSON")
	}

	return &b, nil
}

/*
 * Takes a JSON formatted Solr response (interface{}, not []byte)
 * And returns a *Response
 */
func BuildResponse(j *interface{}) (*SelectResponse, error) {

	// look for a response element, bail if not present
	response_root := (*j).(map[string]interface{})
	response := response_root["response"]
	if response == nil {
		return nil, fmt.Errorf("Supplied interface appears invalid (missing response)")
	}

	// begin Response creation
	r := SelectResponse{}

	// do status & qtime, if possible
	r_header := (*j).(map[string]interface{})["responseHeader"].(map[string]interface{})
	if r_header != nil {
		r.Status = int(r_header["status"].(float64))
		r.QTime = int(r_header["QTime"].(float64))
	}

	// now do docs, if they exist in the response
	docs := response.(map[string]interface{})["docs"].([]interface{})
	if docs != nil {
		// the total amount of results, irrespective of the amount returned in the response
		num_found := int(response.(map[string]interface{})["numFound"].(float64))

		// and the amount actually returned
		num_results := len(docs)

		coll := DocumentCollection{}
		coll.NumFound = num_found

		ds := []Document{}

		for i := 0; i < num_results; i++ {
			ds = append(ds, Document{docs[i].(map[string]interface{})})
		}

		coll.Collection = ds
		r.Results = &coll
	}

	// facets
	facet_response, ok := response_root["facet_counts"].(interface{})
	if ok == true {
		facet_counts := facet_response.(map[string]interface{})
		if facet_counts != nil {
			// do counts if they exist
			facet_fields := facet_counts["facet_fields"].(map[string]interface{})
			facets := []Facet{}
			if facet_fields != nil {
				// iterate over each facet field, create facet & counts for each field
				for k, v := range facet_fields {
					f := Facet{Name: k}
					chunked := chunk(v.([]interface{}), facet_chunk_size)
					lc := len(chunked)
					for i := 0; i < lc; i++ {
						f.Counts = append(f.Counts, FacetCount{
							Value: chunked[i][0].(string),
							Count: int(chunked[i][1].(float64)),
						})
					}
					facets = append(facets, f)
				}
			}

			// add Facets to collection
			r.Results.Facets = facets
			r.Results.NumFacets = len(facets)

		}
	}

	return &r, nil
}

/*
 * Decodes a HTTP (Solr) response and returns a Response
 */
func SelectResponseFromHTTPResponse(b []byte) (*SelectResponse, error) {
	j, err := BytesToJSON(&b)
	if err != nil {
		return nil, fmt.Errorf("Unable to decode")
	}

	resp, err := BuildResponse(j)
	if err != nil {
		return nil, fmt.Errorf("Error building response")
	}

	return resp, nil
}

/*
 * Determines whether a decoded response from Solr
 * is an error response or not. Returns a bool (true if error)
 * and an ErrorResponse (if the response is an error response)
 * otherwise nil
 */
func SolrErrorResponse(m map[string]interface{}) (bool, *ErrorResponse) {
	// check for existance of "error" key
	if _, found := m["error"]; found {
		error := m["error"].(map[string]interface{})
		return true, &ErrorResponse{
			Message: error["msg"].(string),
			Status:  int(error["code"].(float64)),
		}
	}
	return false, nil
}

/*
 * Similar to python's itertools.izip_longest;
 * takes an array and chunks it according to a given splice size
 * eg: chnunk([1,2,3,4,5,6], 2) == [[1,2], [3,4], [5,6]]
 */
func chunk(s []interface{}, sz int) [][]interface{} {
	r := [][]interface{}{}
	j := len(s)
	for i := 0; i < j; i += sz {
		r = append(r, s[i:i+sz])
	}
	return r
}

/*
 * Inits a new Connection to a Solr instance
 * Note: this doesn't actually hold a connection, its just
 *       a container for holding a hostname & port
 */
func Init(host string, port int,core string) (*Connection, error) {

	if len(host) == 0 {
		return nil, fmt.Errorf("Invalid hostname (must be length >= 1)")
	}

	if port <= 0 || port > 65535 {
		return nil, fmt.Errorf("Invalid port (must be 1..65535")
	}

	return &Connection{Host: host, Port: port, Core: core}, nil
}

/*
 * Performs a Select query given a Query
 */
func (c *Connection) Select(q *Query) (*SelectResponse, error) {
	body, err := HTTPGet(SolrSelectString(c, q.String()))

	if err != nil {
		return nil, fmt.Errorf("Some sort of http failure") // TODO: investigate how net/http fails
	}

	r, err := SelectResponseFromHTTPResponse(body)

	if err != nil {
		return nil, err
	}

	return r, nil
}

/*
 * Performs a raw Select query given a raw query string
 */
func (c *Connection) SelectRaw(q string) (*SelectResponse, error) {
	body, err := HTTPGet(SolrSelectString(c, q))

	if err != nil {
		return nil, fmt.Errorf("Some sort of http failure") // TODO: investigate how net/http fails
	}

	r, err := SelectResponseFromHTTPResponse(body)

	if err != nil {
		return nil, err
	}

	return r, nil
}

/*
 * Performs a Solr Update query against a given update document
 * specified in a map[string]interface{} type
 * NOTE: Requires JSON updates to be enabled, see;
 * http://wiki.apache.org/solr/UpdateJSON
 * FUTURE: Will ask for solr version details in Connection and
 * act appropriately
 */
func (c *Connection) Update(m map[string]interface{}, commit bool) (*UpdateResponse, error) {

	// encode "json" to a byte array & check
	payload, err := JSONToBytes(m)
	if err != nil {
		return nil, err
	}

	// perform request
	resp, err := HTTPPost(
		SolrUpdateString(c, commit),
		[][]string{{"Content-Type", "application/json"}},
		payload)

	if err != nil {
		return nil, err
	}

	// decode the response & check
	decoded, err := BytesToJSON(&resp)
	if err != nil {
		return nil, err
	}

	error, report := SolrErrorResponse((*decoded).(map[string]interface{}))
	if error {
		return nil, fmt.Errorf(fmt.Sprintf("%s", *report))
	}

	return &UpdateResponse{true}, nil
}

// func (c *Connection) Commit() (*UpdateResponse, error) {

// }
<|endoftext|>


<commit_before>package client_test

import (
	"github.com/nelhage/livegrep/client"
	. "launchpad.net/gocheck"
	"net"
	"strings"
	"testing"
)

// We assume a codesearch running on localhost:9999. This could be
// improved.

func Test(t *testing.T) { TestingT(t) }

type ClientSuite struct {
	client client.Client
}

var _ = Suite(&ClientSuite{})

func (s *ClientSuite) SetUpTest(c *C) {
	var err error
	s.client, err = client.Dial("tcp", "localhost:9999")
	if err != nil {
		panic(err.Error())
	}
}

func (s *ClientSuite) TestQuery(c *C) {
	search, err := s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	var n int
	for r := range search.Results() {
		n++
		c.Assert(r.Line, Not(Equals), "")
	}
	c.Assert(n, Not(Equals), 0)
	st, e := search.Close()
	c.Assert(st, Not(IsNil))
	c.Assert(e, IsNil)
}

func (s *ClientSuite) TestTwoQueries(c *C) {
	search, err := s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	_, err = search.Close()
	c.Assert(err, IsNil)

	search, err = s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	n := 0
	for _ = range search.Results() {
		n++
	}
	_, err = search.Close()
	if err != nil {
		c.Fatalf("Unexpected error: %s", err.Error())
	}
	c.Assert(n, Not(Equals), 0)
}

func (s *ClientSuite) TestBadRegex(c *C) {
	search, err := s.client.Query(&client.Query{"(", "", ""})
	c.Assert(err, IsNil)
	for _ = range search.Results() {
		c.Fatal("Got back a result from an erroneous query!")
	}
	st, e := search.Close()
	c.Assert(st, IsNil)
	if e == nil {
		c.Fatal("Didn't get back an error")
	}
	if q, ok := e.(client.QueryError); ok {
		c.Assert(q.Query.Line, Equals, "(")
		if strings.HasPrefix(q.Err, "FATAL") {
			c.Errorf("Error includes FATAL prefix: %s", q.Err)
		}
	} else {
		c.Fatalf("Error %v wasn't a QueryError", e)
	}
}

func mockServerShutdown() <-chan string {
	ready := make(chan string, 1)
	go func() {
		ln, err := net.Listen("tcp", ":0")
		if err != nil {
			panic(err.Error())
		}
		defer ln.Close()
		ready <- ln.Addr().String()
		conn, err := ln.Accept()
		if err != nil {
			panic(err.Error())
		}
		conn.Write([]byte("READY {}\n"))
		conn.Close()
	}()
	return ready
}

func (s *ClientSuite) TestShutdown(c *C) {
	ready := mockServerShutdown()
	addr := <-ready

	cl, err := client.Dial("tcp", addr)
	c.Assert(err, IsNil)

	search, err := cl.Query(&client.Query{Line: "l"})
	c.Assert(err, IsNil)
	c.Assert(search, Not(IsNil))

	results := search.Results()
	c.Assert(results, Not(IsNil))
	for r := range results {
		c.Errorf("Got a result back: %+v", r)
	}
	st, err := search.Close()
	c.Assert(st, IsNil)
	c.Assert(err, Not(IsNil))

	search, err = cl.Query(&client.Query{Line: "l"})
	c.Assert(err, Not(IsNil))
	c.Assert(search, IsNil)
}
<commit_msg>more test factoring<commit_after>package client_test

import (
	"github.com/nelhage/livegrep/client"
	. "launchpad.net/gocheck"
	"net"
	"strings"
	"testing"
)

// We assume a codesearch running on localhost:9999. This could be
// improved.

func Test(t *testing.T) { TestingT(t) }

type ClientSuite struct {
	client client.Client
}

var _ = Suite(&ClientSuite{})

type MockServer struct {
}

func (s *ClientSuite) connect(c *C, addr string) {
	var err error
	s.client, err = client.Dial("tcp", addr)
	if err != nil {
		c.Fatalf("connecting to %s: %s", addr, err.Error())
	}
}

func (s *ClientSuite) TestQuery(c *C) {
	s.connect(c, "localhost:9999")
	search, err := s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	var n int
	for r := range search.Results() {
		n++
		c.Assert(r.Line, Not(Equals), "")
	}
	c.Assert(n, Not(Equals), 0)
	st, e := search.Close()
	c.Assert(st, Not(IsNil))
	c.Assert(e, IsNil)
}

func (s *ClientSuite) TestTwoQueries(c *C) {
	s.connect(c, "localhost:9999")
	search, err := s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	_, err = search.Close()
	c.Assert(err, IsNil)

	search, err = s.client.Query(&client.Query{".", "", ""})
	c.Assert(err, IsNil)
	n := 0
	for _ = range search.Results() {
		n++
	}
	_, err = search.Close()
	if err != nil {
		c.Fatalf("Unexpected error: %s", err.Error())
	}
	c.Assert(n, Not(Equals), 0)
}

func (s *ClientSuite) TestBadRegex(c *C) {
	s.connect(c, "localhost:9999")
	search, err := s.client.Query(&client.Query{"(", "", ""})
	c.Assert(err, IsNil)
	for _ = range search.Results() {
		c.Fatal("Got back a result from an erroneous query!")
	}
	st, e := search.Close()
	c.Assert(st, IsNil)
	if e == nil {
		c.Fatal("Didn't get back an error")
	}
	if q, ok := e.(client.QueryError); ok {
		c.Assert(q.Query.Line, Equals, "(")
		if strings.HasPrefix(q.Err, "FATAL") {
			c.Errorf("Error includes FATAL prefix: %s", q.Err)
		}
	} else {
		c.Fatalf("Error %v wasn't a QueryError", e)
	}
}

func mockServerShutdown() <-chan string {
	ready := make(chan string, 1)
	go func() {
		ln, err := net.Listen("tcp", ":0")
		if err != nil {
			panic(err.Error())
		}
		defer ln.Close()
		ready <- ln.Addr().String()
		conn, err := ln.Accept()
		if err != nil {
			panic(err.Error())
		}
		conn.Write([]byte("READY {}\n"))
		conn.Close()
	}()
	return ready
}

func (s *ClientSuite) TestShutdown(c *C) {
	addr := <-mockServerShutdown()

	s.connect(c, addr)

	search, err := s.client.Query(&client.Query{Line: "l"})
	c.Assert(err, IsNil)
	c.Assert(search, Not(IsNil))

	results := search.Results()
	c.Assert(results, Not(IsNil))
	for r := range results {
		c.Errorf("Got a result back: %+v", r)
	}
	st, err := search.Close()
	c.Assert(st, IsNil)
	c.Assert(err, Not(IsNil))

	search, err = s.client.Query(&client.Query{Line: "l"})
	c.Assert(err, Not(IsNil))
	c.Assert(search, IsNil)
}
<|endoftext|>


<commit_before>// +build windows

package open

import (
	"os/exec"
	"strings"

	"github.com/getlantern/runhide"
)

func cleaninput(input string) string {
	r := strings.NewReplacer("&", "^&")
	return r.Replace(input)
}

func open(input string) *exec.Cmd {
	return runhide.Command("cmd", "/C", "start", "", cleaninput(input))
}

func openWith(input string, appName string) *exec.Cmd {
	return runhide.Command("cmd", "/C", "start", "", appName, cleaninput(input))
}
<commit_msg>use rundll32 to open url on windows<commit_after>// +build windows

package open

import (
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	cmd       = "url.dll,FileProtocolHandler"
	runDll32  = filepath.Join(os.Getenv("SYSTEMROOT"), "System32", "rundll32.exe")
)

func cleaninput(input string) string {
	r := strings.NewReplacer("&", "^&")
	return r.Replace(input)
}

func open(input string) *exec.Cmd {
	return exec.Command(runDll32, cmd, input)
}

func openWith(input string, appName string) *exec.Cmd {
	return exec.Command("cmd", "/C", "start", "", appName, cleaninput(input))
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// NomadServer is connection parameters to a nomad server
type NomadServer struct {
	Address string
	Port    int
}

// Details represents a json object in a nomad job
type Details struct {
	Running int `json:"running"`
}

// Summary represents a json object in a nomad job
type Summary struct {
	Details *Details `json:"server"`
}

// JobSummary represents a json object in a nomad job
type JobSummary struct {
	Summary *Summary `json:"Summary"`
}

// Job is a representation of nomad job
type Job struct {
	Name       string      `json:"Name"`
	Priority   int         `json:"Priority"`
	Status     string      `json:"status"`
	JobSummary *JobSummary `json:"JobSummary"`
}

// Task represents an allocated nomad task
type Task struct {
	State string `json:"State"`
}

// Alloc is a representation of a nomad allocation
type Alloc struct {
	ID            string          `json:"ID"`
	JobID         string          `json:"JobID"`
	NodeID        string          `json:"NodeID"`
	Name          string          `json:"Name"`
	ClientStatus  string          `json:"ClientStatus"`
	DesiredStatus string          `json:"DesiredStatus"`
	Tasks         map[string]Task `json:"TaskStates"`
}

// Host is a representation of a nomad client node
type Host struct {
	ID        string         `json:"ID"`
	Name      string         `json:"Name"`
	Drain     bool           `json:"Drain"`
	Resources *NodeResources `json:"Resources,omitempty"`
}

// NodeResources represents the resources of a nomad node
type NodeResources struct {
	Networks *Networks `json:"Networks"`
}

// Networks represents the network available on a nomad node
type Networks struct {
	IP string `json:"IP"`
}

// JobNotFound indicates that a Job search failed
type JobNotFound struct {
	Name string
}

// AllocNotFound indicates a missing allocation for a Job
type AllocNotFound struct {
	Jobname  string
	Hostname string
}

var httpClient = &http.Client{Timeout: 5 * time.Second}

// Jobs will parse the json representation from the nomad rest api
// /v1/jobs
func Jobs(nomad *NomadServer) ([]Job, int, error) {
	jobs := make([]Job, 0)
	status, err := decodeJSON(url(nomad)+"/v1/jobs", &jobs)
	return jobs, status, err
}

// FindJob will parse the json representation and find the supplied job name
func FindJob(nomad *NomadServer, name string) (*Job, error) {
	jobs, _, _ := Jobs(nomad)
	for _, job := range jobs {
		if job.Name == name {
			return &job, nil
		}
	}
	return &Job{}, &JobNotFound{Name: name}
}

func (e *JobNotFound) Error() string {
	return fmt.Sprintf("Unable to find job name: %v", e.Name)
}

// Hosts will parse the json representation from the nomad rest api
// /v1/nodes
func Hosts(nomad *NomadServer) ([]Host, int, error) {
	hosts := make([]Host, 0)
	status, err := decodeJSON(url(nomad)+"/v1/nodes", &hosts)
	return hosts, status, err
}

// Drain will inform nomad to add/remove all allocations from that host
// depending on the value of enable
// Returns the http status code or an error
func Drain(nomad *NomadServer, id string, enable bool) (int, error) {
	resp, err := httpClient.Post(url(nomad)+"/v1/node/"+id+"/drain?enable="+strconv.FormatBool(enable), "application/json", nil)
	if resp != nil && resp.Body != nil {
		defer resp.Body.Close()
		return resp.StatusCode, err
	}
	return http.StatusInternalServerError, err
}

// SubmitJob requests that nomade run a json launch file located at the supplied path
// Returns an http status code or error
func SubmitJob(nomad *NomadServer, launchFilePath string) (int, error) {
	file, err := ioutil.ReadFile(launchFilePath)
	if err != nil {
		return http.StatusBadRequest, err
	}
	resp, err := httpClient.Post(url(nomad)+"/v1/jobs", "application/json", bytes.NewBuffer(file))
	if resp != nil && resp.Body != nil {
		defer resp.Body.Close()
		return resp.StatusCode, err
	}
	return http.StatusInternalServerError, err
}

// Allocs will parse the json representation from the nomad rest api
// /v1/allocations
func Allocs(nomad *NomadServer) []Alloc {
	allocs := make([]Alloc, 0)
	decodeJSON(url(nomad)+"/v1/allocations", &allocs)
	return allocs
}

// FindAlloc will search through the Allocs on a provided Host to look for the
// allocations that match the provided Job
func FindAlloc(nomad *NomadServer, job *Job, host *Host) (*Alloc, error) {
	allocs := Allocs(nomad)
	for _, alloc := range allocs {
		if alloc.NodeID == host.ID && strings.Contains(alloc.Name, job.Name) {
			// We may be looking at a stale allocation and a newer one exists
			if alloc.DesiredStatus == "stop" && len(allocs) > 1 {
				continue
			}
			return &alloc, nil
		}
	}
	return &Alloc{}, &AllocNotFound{Hostname: host.Name, Jobname: job.Name}
}

// CheckTaskStates will return whether all of the tasks for an Alloc are
// in the state provided
func (alloc *Alloc) CheckTaskStates(state string) bool {
	for k := range alloc.Tasks {
		task := alloc.Tasks[k]
		if task.State != state {
			return false
		}
	}
	return true
}

// HostID finds a nomad Host that matches the provided hostname
func HostID(nomad *NomadServer, hostname *string) (*Host, error) {
	hosts, _, err := Hosts(nomad)
	if err != nil {
		return &Host{}, err
	}
	for _, host := range hosts {
		if *hostname == host.Name {
			return &host, nil
		}
	}
	// {"event": "node_not_found", "hostname": "server-1"}
	return &Host{}, errors.New("{\"event\": \"node_not_found\", \"hostname\"" + *hostname + "}")

}

func (e *AllocNotFound) Error() string {
	return fmt.Sprintf("Unable to find '%v' job on '%v' host.", e.Jobname, e.Hostname)
}

func url(nomad *NomadServer) string {
	return fmt.Sprintf("http://%v:%v", nomad.Address, nomad.Port)
}

func decodeJSON(url string, target interface{}) (int, error) {
	r, err := httpClient.Get(url)
	if err != nil && r != nil && r.Body != nil {
		defer r.Body.Close()
		return r.StatusCode, err
	} else if err != nil {
		return http.StatusInternalServerError, err
	}
	return http.StatusOK, json.NewDecoder(r.Body).Decode(target)
}
<commit_msg>Added StopJob; retryable http calls<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	kitlog "github.com/go-kit/kit/log"
	retryablehttp "github.com/hashicorp/go-retryablehttp"
)

// NomadServer is connection parameters to a nomad server
type NomadServer struct {
	Address string
	Port    int
}

// Details represents a json object in a nomad job
type Details struct {
	Running int `json:"running"`
}

// Summary represents a json object in a nomad job
type Summary struct {
	Details *Details `json:"server"`
}

// JobSummary represents a json object in a nomad job
type JobSummary struct {
	Summary *Summary `json:"Summary"`
}

// Job is a representation of nomad job
type Job struct {
	Name       string      `json:"Name"`
	Priority   int         `json:"Priority"`
	Status     string      `json:"status"`
	JobSummary *JobSummary `json:"JobSummary"`
}

// Task represents an allocated nomad task
type Task struct {
	State string `json:"State"`
}

// Alloc is a representation of a nomad allocation
type Alloc struct {
	ID            string          `json:"ID"`
	JobID         string          `json:"JobID"`
	NodeID        string          `json:"NodeID"`
	Name          string          `json:"Name"`
	ClientStatus  string          `json:"ClientStatus"`
	DesiredStatus string          `json:"DesiredStatus"`
	Tasks         map[string]Task `json:"TaskStates"`
}

// Host is a representation of a nomad client node
type Host struct {
	ID        string         `json:"ID"`
	Name      string         `json:"Name"`
	Drain     bool           `json:"Drain"`
	Resources *NodeResources `json:"Resources,omitempty"`
}

// NodeResources represents the resources of a nomad node
type NodeResources struct {
	Networks *Networks `json:"Networks"`
}

// Networks represents the network available on a nomad node
type Networks struct {
	IP string `json:"IP"`
}

// AllocNotFound indicates a missing allocation for a Job
type AllocNotFound struct {
	Jobname  string
	Hostname string
}

func log(keyvals ...interface{}) *bytes.Buffer {
	w := new(bytes.Buffer)
	kitlog.NewJSONLogger(w).Log(keyvals)
	return w
}

// Jobs will parse the json representation from the nomad rest api
// /v1/jobs
func Jobs(nomad *NomadServer) ([]Job, int, error) {
	jobs := make([]Job, 0)
	status, err := decodeJSON(url(nomad)+"/v1/jobs", &jobs)
	return jobs, status, err
}

// FindJob will parse the json representation and find the supplied job name
func FindJob(nomad *NomadServer, name string) (*Job, error) {
	jobs, _, _ := Jobs(nomad)
	for _, job := range jobs {
		if job.Name == name {
			return &job, nil
		}
	}
	return &Job{}, errors.New("job not found")
}

// Hosts will parse the json representation from the nomad rest api
// /v1/nodes
func Hosts(nomad *NomadServer) ([]Host, int, error) {
	hosts := make([]Host, 0)
	status, err := decodeJSON(url(nomad)+"/v1/nodes", &hosts)
	return hosts, status, err
}

// Drain will inform nomad to add/remove all allocations from that host
// depending on the value of enable
// Returns the http status code or an error
func Drain(nomad *NomadServer, id string, enable bool) (int, error) {
	resp, err := retryablehttp.Post(url(nomad)+"/v1/node/"+id+"/drain?enable="+strconv.FormatBool(enable), "application/json", nil)
	if resp != nil && resp.Body != nil {
		defer resp.Body.Close()
		return resp.StatusCode, err
	}
	return http.StatusInternalServerError, err
}

// StopJob will send a delete request to a nomad server to stop the provided job
func StopJob(nomad *NomadServer, job *Job) (int, error) {
	url := fmt.Sprintf("http://%v:%v/v1/job/%v", nomad.Address, nomad.Port, job.Name)
	req, err := retryablehttp.NewRequest(http.MethodDelete, url, bytes.NewReader([]byte{}))
	if err != nil {
		buf := log("event", "stop_job_request_error", "jobname", job.Name, "error", err.Error())
		return http.StatusInternalServerError, errors.New(buf.String())
	}
	resp, err := retryablehttp.NewClient().Do(req)
	if err != nil {
		buf := log("event", "stop_job_client_error", "jobname", job.Name, "error", err.Error())
		return resp.StatusCode, errors.New(buf.String())
	}
	return resp.StatusCode, nil
}

// SubmitJob requests that nomade run a json launch file located at the supplied path
// Returns an http status code or error
func SubmitJob(nomad *NomadServer, launchFilePath string) (int, error) {
	file, err := ioutil.ReadFile(launchFilePath)
	if err != nil {
		return http.StatusBadRequest, err
	}
	resp, err := retryablehttp.Post(url(nomad)+"/v1/jobs", "application/json", bytes.NewReader(file))
	defer resp.Body.Close()
	return resp.StatusCode, err
}

// Allocs will parse the json representation from the nomad rest api
// /v1/allocations
func Allocs(nomad *NomadServer) []Alloc {
	allocs := make([]Alloc, 0)
	decodeJSON(url(nomad)+"/v1/allocations", &allocs)
	return allocs
}

// FindAlloc will search through the Allocs on a provided Host to look for the
// allocations that match the provided Job
func FindAlloc(nomad *NomadServer, job *Job, host *Host) (*Alloc, error) {
	allocs := Allocs(nomad)
	for _, alloc := range allocs {
		if alloc.NodeID == host.ID && strings.Contains(alloc.Name, job.Name) {
			// We may be looking at a stale allocation and a newer one exists
			if alloc.DesiredStatus == "stop" && len(allocs) > 1 {
				continue
			}
			return &alloc, nil
		}
	}
	return &Alloc{}, &AllocNotFound{Hostname: host.Name, Jobname: job.Name}
}

// CheckTaskStates will return whether all of the tasks for an Alloc are
// in the state provided
func (alloc *Alloc) CheckTaskStates(state string) bool {
	for k := range alloc.Tasks {
		task := alloc.Tasks[k]
		if task.State != state {
			return false
		}
	}
	return true
}

// HostID finds a nomad Host that matches the provided hostname
func HostID(nomad *NomadServer, hostname *string) (*Host, error) {
	hosts, _, err := Hosts(nomad)
	if err != nil {
		return &Host{}, err
	}
	for _, host := range hosts {
		if *hostname == host.Name {
			return &host, nil
		}
	}
	buf := log("event", "node_not_found", "hostname", hostname)
	return &Host{}, errors.New(buf.String())

}

func (e *AllocNotFound) Error() string {
	return fmt.Sprintf("Unable to find '%v' job on '%v' host.", e.Jobname, e.Hostname)
}

func url(nomad *NomadServer) string {
	return fmt.Sprintf("http://%v:%v", nomad.Address, nomad.Port)
}

func decodeJSON(url string, target interface{}) (int, error) {
	r, err := retryablehttp.Get(url)
	if err != nil && r != nil && r.Body != nil {
		defer r.Body.Close()
		return r.StatusCode, err
	} else if err != nil {
		return http.StatusInternalServerError, err
	}
	return http.StatusOK, json.NewDecoder(r.Body).Decode(target)
}
<|endoftext|>


<commit_before>package client

import (
	"crypto/tls"
	"fmt"
	"github.com/ActiveState/httpapi/client"
	"net/http"
)

type RestClient struct {
	TargetURL string
	Token     string
	Space     string
	client    *client.Client
}

func NewRestClient(targetUrl, token, space string) *RestClient {
	if token == "" {
		panic("empty Token")
	}
	return &RestClient{targetUrl, token, space, getInsecureHttpRestClient()}
}

type App struct {
	GUID              string
	Name              string
	URLs              []string
	Instances         int
	RunningInstances  *int
	Version           string
	Buildpack         string
	DetectedBuildpack string
	Memory            int
	DiskQuota         int
}

func (c *RestClient) GetLogs(appGUID string, num int) ([]AppLogLine, error) {
	path := fmt.Sprintf("/v2/apps/%s/stackato_logs?num=%d&monolith=1", appGUID, num)
	var response struct {
		Lines []AppLogLine `json:"lines"`
	}
	err := c.MakeRequest("GET", path, nil, &response)
	return response.Lines, err
}

func (c *RestClient) GetLogsRaw(appGUID string, num int) ([]string, error) {
	path := fmt.Sprintf(
		"/v2/apps/%s/stackato_logs?num=%d&as_is=1&monolith=1", appGUID, num)
	var response struct {
		Lines []string `json:"lines"`
	}
	err := c.MakeRequest("GET", path, nil, &response)
	return response.Lines, err
}

func (c *RestClient) ListApps() (apps []App, err error) {
	if c.Space == "" {
		panic("empty Space")
	}
	path := fmt.Sprintf("/v2/spaces/%s/summary", c.Space)
	var response struct {
		GUID string
		Name string
		Apps []App
	}
	response.Apps = apps
	err = c.MakeRequest("GET", path, nil, &response)
	return
}

// CreateApp only creates the application. It is an equivalent of `s
// create-app --json`.
func (c *RestClient) CreateApp(name string) (string, error) {
	// Ensure that app name is unique for this user. We do this as
	// unfortunately the server doesn't enforce it.
	apps, err := c.ListApps()
	if err != nil {
		return "", err
	}
	for _, app := range apps {
		if app.Name == name {
			return "", fmt.Errorf("App by that name (%s) already exists", name)
		}
	}

	// The CC requires that a POST on /apps sends, at minimum, these
	// fields. The values for framework/runtime doesn't matter for our
	// purpose (they will get overwritten by a subsequent app push).
	createArgs := map[string]interface{}{
		"name":       name,
		"space_guid": c.Space,
	}

	var resp struct {
		Metadata struct {
			GUID string
		}
	}
	err = c.MakeRequest("POST", "/v2/apps", createArgs, &resp)
	if err != nil {
		return "", err
	}

	if resp.Metadata.GUID == "" {
		return "", fmt.Errorf("Missing App GUID from CC")
	}

	return resp.Metadata.GUID, nil
}

func (c *RestClient) MakeRequest(method string, path string, params interface{}, response interface{}) error {
	req, err := client.NewRequest(method, c.TargetURL+path, params)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", c.Token)
	err = c.client.DoRequest(req, response)
	if err != nil {
		return fmt.Errorf("CC API %v %v failed: %v", method, path, err)
	}
	return nil
}

// emulate `curl -k ...`
func getInsecureHttpRestClient() *client.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	return &client.Client{Transport: tr}
}
<commit_msg>300262 Provide memory parameter to CC API.<commit_after>package client

import (
	"crypto/tls"
	"fmt"
	"github.com/ActiveState/httpapi/client"
	"net/http"
)

type RestClient struct {
	TargetURL string
	Token     string
	Space     string
	client    *client.Client
}

func NewRestClient(targetUrl, token, space string) *RestClient {
	if token == "" {
		panic("empty Token")
	}
	return &RestClient{targetUrl, token, space, getInsecureHttpRestClient()}
}

type App struct {
	GUID              string
	Name              string
	URLs              []string
	Instances         int
	RunningInstances  *int
	Version           string
	Buildpack         string
	DetectedBuildpack string
	Memory            int
	DiskQuota         int
}

func (c *RestClient) GetLogs(appGUID string, num int) ([]AppLogLine, error) {
	path := fmt.Sprintf("/v2/apps/%s/stackato_logs?num=%d&monolith=1", appGUID, num)
	var response struct {
		Lines []AppLogLine `json:"lines"`
	}
	err := c.MakeRequest("GET", path, nil, &response)
	return response.Lines, err
}

func (c *RestClient) GetLogsRaw(appGUID string, num int) ([]string, error) {
	path := fmt.Sprintf(
		"/v2/apps/%s/stackato_logs?num=%d&as_is=1&monolith=1", appGUID, num)
	var response struct {
		Lines []string `json:"lines"`
	}
	err := c.MakeRequest("GET", path, nil, &response)
	return response.Lines, err
}

func (c *RestClient) ListApps() (apps []App, err error) {
	if c.Space == "" {
		panic("empty Space")
	}
	path := fmt.Sprintf("/v2/spaces/%s/summary", c.Space)
	var response struct {
		GUID string
		Name string
		Apps []App
	}
	response.Apps = apps
	err = c.MakeRequest("GET", path, nil, &response)
	return
}

// CreateApp only creates the application. It is an equivalent of `s
// create-app --json`.
func (c *RestClient) CreateApp(name string, memory int) (string, error) {
	// Ensure that app name is unique for this user. We do this as
	// unfortunately the server doesn't enforce it.
	apps, err := c.ListApps()
	if err != nil {
		return "", err
	}
	for _, app := range apps {
		if app.Name == name {
			return "", fmt.Errorf("App by that name (%s) already exists", name)
		}
	}

	// The CC requires that a POST on /apps sends, at minimum, these
	// fields. The values for framework/runtime doesn't matter for our
	// purpose (they will get overwritten by a subsequent app push).
	createArgs := map[string]interface{}{
		"name":       name,
		"space_guid": c.Space,
		"memory":     memory,
	}

	var resp struct {
		Metadata struct {
			GUID string
		}
	}
	err = c.MakeRequest("POST", "/v2/apps", createArgs, &resp)
	if err != nil {
		return "", err
	}

	if resp.Metadata.GUID == "" {
		return "", fmt.Errorf("Missing App GUID from CC")
	}

	return resp.Metadata.GUID, nil
}

func (c *RestClient) MakeRequest(method string, path string, params interface{}, response interface{}) error {
	req, err := client.NewRequest(method, c.TargetURL+path, params)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", c.Token)
	err = c.client.DoRequest(req, response)
	if err != nil {
		return fmt.Errorf("CC API %v %v failed: %v", method, path, err)
	}
	return nil
}

// emulate `curl -k ...`
func getInsecureHttpRestClient() *client.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	return &client.Client{Transport: tr}
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// Marshal map[int]... to JSON {"id": { ... }}
func marshalJSONMap(colMap interface{}) ([]byte, error) {
	mapValue := reflect.ValueOf(colMap)
	mapType := mapValue.Type()

	if mapType.Kind() != reflect.Map || mapType.Key().Kind() != reflect.Int {
		panic(fmt.Errorf("colMap must be *map[int]..."))
	}

	jsonMap := make(map[string]interface{})

	for _, idValue := range mapValue.MapKeys() {
		itemValue := mapValue.MapIndex(idValue)

		jsonMap[fmt.Sprintf("%d", idValue.Int())] = itemValue.Interface()
	}

	return json.Marshal(jsonMap)
}
<commit_msg>client: fix support for non-int keys in marshalJSONMap<commit_after>package client

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// Marshal map[int]... to JSON {"id": { ... }}
func marshalJSONMap(colMap interface{}) ([]byte, error) {
	mapValue := reflect.ValueOf(colMap)
	mapType := mapValue.Type()

	if mapType.Kind() != reflect.Map {
		panic(fmt.Errorf("colMap must be *map[...]..."))
	}

	jsonMap := make(map[string]interface{})

	for _, idValue := range mapValue.MapKeys() {
		itemValue := mapValue.MapIndex(idValue)

		jsonMap[fmt.Sprintf("%v", idValue.Interface())] = itemValue.Interface()
	}

	return json.Marshal(jsonMap)
}
<|endoftext|>


<commit_before>// Copyright 2018 Sean.ZH

package clients

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

// AliyunClient defines a client
type AliyunClient struct {
	KeyId string
	KeySecret string
}

// NewAliyunClient returns a new client
func NewAliyunClient(id, secret string) *AliyunClient {
	return &AliyunClient{KeyId:id, KeySecret: secret}
}

// AliKeyValuePair to sort arguments
type AliKeyValuePair struct {
	Key   string
	Value string
}

// ByKey implements sort.Sort
type ByKey []AliKeyValuePair

func (a ByKey) Len() int           { return len(a) }
func (a ByKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKey) Less(i, j int) bool { return a[i].Key < a[j].Key }

func generateSignature(method string, params map[string]string, accessKeySecret string) (signature string) {
	pairs := make([]AliKeyValuePair, 0)
	for k, v := range params {
		pairs = append(pairs, KeyValuePair{
			Key:   k,
			Value: v,
		})
	}
	sort.Sort(ByKey(pairs))
	urlParams := ""
	for _, item := range pairs {
		if len(urlParams) > 0 {
			urlParams += "&"
		}
		urlParams += item.Key + "=" + strings.Replace(url.QueryEscape(item.Value), "+", "%20", -1)
	}
	encodedUrlParams := url.QueryEscape(urlParams)
	StringToSign := method + "&" + url.QueryEscape("/") + "&" + encodedUrlParams
	// fmt.Println("string to sign is", StringToSign)
	hmacObj := hmac.New(sha1.New, []byte(accessKeySecret + "&"))
	hmacObj.Write([]byte(StringToSign))
	signature = base64.StdEncoding.EncodeToString(hmacObj.Sum(nil))
	// fmt.Println("signature is", signature)
	return
}

func generateUrlParam(method string, params map[string]string, accessKeySecret string) (ret string) {
	for k, v := range params {
		if len(ret) > 0 {
			ret += "&"
		}
		ret += k + "=" + url.QueryEscape(v)
	}
	ret += "&Signature=" + url.QueryEscape(generateSignature(method, params, accessKeySecret))
	return
}

type AliResponse struct {
	RequestId string `json:"RequestId"` // always return
	RecordId string `json:"RecordId"` // returned when ok
	HostId string `json:"HostId"` // returned when error
	Code string `json:"Code"` // returned when error
	Message string `json:"Message"` // returned when error
}

func (ali *AliyunClient) ModifyRecord(subDomain, domain, value, recordId string) error {
	ret := make(map[string]string)
	ret["Format"] = "JSON"
	ret["Version"] = "2015-01-09"
	ret["AccessKeyId"] = ali.KeyId
	ret["SignatureMethod"] = "HMAC-SHA1"
	ret["Timestamp"] = time.Now().UTC().Format("2006-01-02T15:04:05Z")
	ret["SignatureVersion"] = "1.0"
	rand.Seed(time.Now().UnixNano())
	ret["SignatureNonce"] = fmt.Sprintf("%v", rand.Int())
	ret["Action"] = "UpdateDomainRecord"
	ret["DomainName"] = domain
	ret["RR"] = subDomain
	ret["Type"] = "A"
	ret["Value"] = value
	ret["RecordId"] = recordId

	body := []byte(generateUrlParam(http.MethodPost, ret, KeySecret))
	ct := "application/x-www-form-urlencoded"
	buf:= bytes.NewBuffer(body)
	url := "https://alidns.aliyuncs.com"
	resp, err := http.Post(url, ct, buf)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	bt, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	var ret AliResponse
	err = json.Unmarshal(bt, &ret)
	if err != nil {
		return err
	}
	if ret.RecordId == "" {
		return errors.New(string(bt))
	}
	return nil
}
<commit_msg>fix bugs<commit_after>// Copyright 2018 Sean.ZH

package clients

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"encoding/base64"
	"strings"
	"crypto/hmac"
	"crypto/sha1"
	"time"
	"math/rand"
	"bytes"
)

// AliyunClient defines a client
type AliyunClient struct {
	KeyId string
	KeySecret string
}

// NewAliyunClient returns a new client
func NewAliyunClient(id, secret string) *AliyunClient {
	return &AliyunClient{KeyId:id, KeySecret: secret}
}

// AliKeyValuePair to sort arguments
type AliKeyValuePair struct {
	Key   string
	Value string
}

// ByKey implements sort.Sort
type ByKey []AliKeyValuePair

func (a ByKey) Len() int           { return len(a) }
func (a ByKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKey) Less(i, j int) bool { return a[i].Key < a[j].Key }

func generateSignature(method string, params map[string]string, accessKeySecret string) (signature string) {
	pairs := make([]AliKeyValuePair, 0)
	for k, v := range params {
		pairs = append(pairs, AliKeyValuePair{
			Key:   k,
			Value: v,
		})
	}
	sort.Sort(ByKey(pairs))
	urlParams := ""
	for _, item := range pairs {
		if len(urlParams) > 0 {
			urlParams += "&"
		}
		urlParams += item.Key + "=" + strings.Replace(url.QueryEscape(item.Value), "+", "%20", -1)
	}
	encodedUrlParams := url.QueryEscape(urlParams)
	StringToSign := method + "&" + url.QueryEscape("/") + "&" + encodedUrlParams
	// fmt.Println("string to sign is", StringToSign)
	hmacObj := hmac.New(sha1.New, []byte(accessKeySecret + "&"))
	hmacObj.Write([]byte(StringToSign))
	signature = base64.StdEncoding.EncodeToString(hmacObj.Sum(nil))
	// fmt.Println("signature is", signature)
	return
}

func generateUrlParam(method string, params map[string]string, accessKeySecret string) (ret string) {
	for k, v := range params {
		if len(ret) > 0 {
			ret += "&"
		}
		ret += k + "=" + url.QueryEscape(v)
	}
	ret += "&Signature=" + url.QueryEscape(generateSignature(method, params, accessKeySecret))
	return
}

type AliResponse struct {
	RequestId string `json:"RequestId"` // always return
	RecordId string `json:"RecordId"` // returned when ok
	HostId string `json:"HostId"` // returned when error
	Code string `json:"Code"` // returned when error
	Message string `json:"Message"` // returned when error
}

func (ali *AliyunClient) ModifyRecord(subDomain, domain, value, recordId string) error {
	ret := make(map[string]string)
	ret["Format"] = "JSON"
	ret["Version"] = "2015-01-09"
	ret["AccessKeyId"] = ali.KeyId
	ret["SignatureMethod"] = "HMAC-SHA1"
	ret["Timestamp"] = time.Now().UTC().Format("2006-01-02T15:04:05Z")
	ret["SignatureVersion"] = "1.0"
	rand.Seed(time.Now().UnixNano())
	ret["SignatureNonce"] = fmt.Sprintf("%v", rand.Int())
	ret["Action"] = "UpdateDomainRecord"
	ret["DomainName"] = domain
	ret["RR"] = subDomain
	ret["Type"] = "A"
	ret["Value"] = value
	ret["RecordId"] = recordId

	body := []byte(generateUrlParam(http.MethodPost, ret, ali.KeySecret))
	ct := "application/x-www-form-urlencoded"
	buf:= bytes.NewBuffer(body)
	url := "https://alidns.aliyuncs.com"
	resp, err := http.Post(url, ct, buf)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	bt, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	var aliResp AliResponse
	err = json.Unmarshal(bt, &aliResp)
	if err != nil {
		return err
	}
	if aliResp.RecordId == "" {
		return errors.New(string(bt))
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>net/http: make race detector happy for recently-added test<commit_after><|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 options

import (
	"github.com/spf13/pflag"

	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apiserver/pkg/server"
)

type FeatureOptions struct {
	EnableProfiling           bool
	EnableContentionProfiling bool
}

func NewFeatureOptions() *FeatureOptions {
	defaults := server.NewConfig(serializer.CodecFactory{})

	return &FeatureOptions{
		EnableProfiling:           defaults.EnableProfiling,
		EnableContentionProfiling: defaults.EnableContentionProfiling,
	}
}

func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
	if o == nil {
		return
	}

	fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling,
		"Enable profiling via web interface host:port/debug/pprof/")
	fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling,
		"Enable lock contention profiling, if profiling is enabled")
	dummy := false
	fs.BoolVar(&dummy, "enable-swagger-ui", dummy, "Enables swagger ui on the apiserver at /swagger-ui")
	fs.MarkDeprecated("enable-swagger-ui", "swagger 1.2 support has been removed")
}

func (o *FeatureOptions) ApplyTo(c *server.Config) error {
	if o == nil {
		return nil
	}

	c.EnableProfiling = o.EnableProfiling
	c.EnableContentionProfiling = o.EnableContentionProfiling

	return nil
}

func (o *FeatureOptions) Validate() []error {
	if o == nil {
		return nil
	}

	errs := []error{}
	return errs
}
<commit_msg>Remove args enable-swagger-ui since no effect from 1.14<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 options

import (
	"github.com/spf13/pflag"

	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apiserver/pkg/server"
)

type FeatureOptions struct {
	EnableProfiling           bool
	EnableContentionProfiling bool
}

func NewFeatureOptions() *FeatureOptions {
	defaults := server.NewConfig(serializer.CodecFactory{})

	return &FeatureOptions{
		EnableProfiling:           defaults.EnableProfiling,
		EnableContentionProfiling: defaults.EnableContentionProfiling,
	}
}

func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) {
	if o == nil {
		return
	}

	fs.BoolVar(&o.EnableProfiling, "profiling", o.EnableProfiling,
		"Enable profiling via web interface host:port/debug/pprof/")
	fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling,
		"Enable lock contention profiling, if profiling is enabled")
}

func (o *FeatureOptions) ApplyTo(c *server.Config) error {
	if o == nil {
		return nil
	}

	c.EnableProfiling = o.EnableProfiling
	c.EnableContentionProfiling = o.EnableContentionProfiling

	return nil
}

func (o *FeatureOptions) Validate() []error {
	if o == nil {
		return nil
	}

	errs := []error{}
	return errs
}
<|endoftext|>


<commit_before>package tcp

import (
	"context"
	gotls "crypto/tls"
	"net"
	"time"

	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/internet/tls"
)

var (
	ErrClosedListener = newError("Listener is closed.")
)

type TCPListener struct {
	ctx        context.Context
	listener   *net.TCPListener
	tlsConfig  *gotls.Config
	authConfig internet.ConnectionAuthenticator
	config     *Config
	conns      chan<- internet.Connection
}

func ListenTCP(ctx context.Context, address v2net.Address, port v2net.Port, conns chan<- internet.Connection) (internet.Listener, error) {
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   address.IP(),
		Port: int(port),
	})
	if err != nil {
		return nil, err
	}
	log.Trace(newError("listening TCP on ", address, ":", port))
	networkSettings := internet.TransportSettingsFromContext(ctx)
	tcpSettings := networkSettings.(*Config)

	l := &TCPListener{
		ctx:      ctx,
		listener: listener,
		config:   tcpSettings,
		conns:    conns,
	}
	if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
		tlsConfig, ok := securitySettings.(*tls.Config)
		if ok {
			l.tlsConfig = tlsConfig.GetTLSConfig()
		}
	}
	if tcpSettings.HeaderSettings != nil {
		headerConfig, err := tcpSettings.HeaderSettings.GetInstance()
		if err != nil {
			return nil, newError("invalid header settings").Base(err).AtError()
		}
		auth, err := internet.CreateConnectionAuthenticator(headerConfig)
		if err != nil {
			return nil, newError("invalid header settings.").Base(err).AtError()
		}
		l.authConfig = auth
	}
	go l.KeepAccepting()
	return l, nil
}

func (v *TCPListener) KeepAccepting() {
	for {
		select {
		case <-v.ctx.Done():
			return
		default:
		}
		var conn net.Conn
		err := retry.ExponentialBackoff(5, 200).On(func() error {
			rawConn, err := v.listener.Accept()
			if err != nil {
				return err
			}
			conn = rawConn
			return nil
		})
		if err != nil {
			log.Trace(newError("failed to accepted raw connections").Base(err).AtWarning())
			continue
		}

		if v.tlsConfig != nil {
			conn = tls.Server(conn, v.tlsConfig)
		}
		if v.authConfig != nil {
			conn = v.authConfig.Server(conn)
		}

		select {
		case v.conns <- internet.Connection(conn):
		case <-time.After(time.Second * 5):
			conn.Close()
		}
	}
}

func (v *TCPListener) Addr() net.Addr {
	return v.listener.Addr()
}

func (v *TCPListener) Close() error {
	v.listener.Close()
	return nil
}

func init() {
	common.Must(internet.RegisterTransportListener(internet.TransportProtocol_TCP, ListenTCP))
}
<commit_msg>cleanup<commit_after>package tcp

import (
	"context"
	gotls "crypto/tls"
	"net"
	"time"

	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/internet/tls"
)

type TCPListener struct {
	ctx        context.Context
	listener   *net.TCPListener
	tlsConfig  *gotls.Config
	authConfig internet.ConnectionAuthenticator
	config     *Config
	conns      chan<- internet.Connection
}

func ListenTCP(ctx context.Context, address v2net.Address, port v2net.Port, conns chan<- internet.Connection) (internet.Listener, error) {
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
		IP:   address.IP(),
		Port: int(port),
	})
	if err != nil {
		return nil, err
	}
	log.Trace(newError("listening TCP on ", address, ":", port))
	networkSettings := internet.TransportSettingsFromContext(ctx)
	tcpSettings := networkSettings.(*Config)

	l := &TCPListener{
		ctx:      ctx,
		listener: listener,
		config:   tcpSettings,
		conns:    conns,
	}
	if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
		tlsConfig, ok := securitySettings.(*tls.Config)
		if ok {
			l.tlsConfig = tlsConfig.GetTLSConfig()
		}
	}
	if tcpSettings.HeaderSettings != nil {
		headerConfig, err := tcpSettings.HeaderSettings.GetInstance()
		if err != nil {
			return nil, newError("invalid header settings").Base(err).AtError()
		}
		auth, err := internet.CreateConnectionAuthenticator(headerConfig)
		if err != nil {
			return nil, newError("invalid header settings.").Base(err).AtError()
		}
		l.authConfig = auth
	}
	go l.KeepAccepting()
	return l, nil
}

func (v *TCPListener) KeepAccepting() {
	for {
		select {
		case <-v.ctx.Done():
			return
		default:
		}
		var conn net.Conn
		err := retry.ExponentialBackoff(5, 200).On(func() error {
			rawConn, err := v.listener.Accept()
			if err != nil {
				return err
			}
			conn = rawConn
			return nil
		})
		if err != nil {
			log.Trace(newError("failed to accepted raw connections").Base(err).AtWarning())
			continue
		}

		if v.tlsConfig != nil {
			conn = tls.Server(conn, v.tlsConfig)
		}
		if v.authConfig != nil {
			conn = v.authConfig.Server(conn)
		}

		select {
		case v.conns <- internet.Connection(conn):
		case <-time.After(time.Second * 5):
			conn.Close()
		}
	}
}

func (v *TCPListener) Addr() net.Addr {
	return v.listener.Addr()
}

func (v *TCPListener) Close() error {
	return v.listener.Close()
}

func init() {
	common.Must(internet.RegisterTransportListener(internet.TransportProtocol_TCP, ListenTCP))
}
<|endoftext|>