<commit_before>// Copyright 2019 HenryYee.
//
// Licensed under the AGPL, Version 3.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.gnu.org/licenses/agpl-3.0.en.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package lib

import (
	"Yearning-go/src/model"
	"crypto/tls"
	"encoding/hex"
	"encoding/json"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/labstack/echo/v4"
	"gopkg.in/ldap.v3"
	"log"
	"math"
	"math/rand"
	"strconv"
	"time"
)

func SuperAuth(c echo.Context, r string) bool {
	var p model.CoreGrained
	var px model.PermissionList
	user, role := JwtParse(c)
	if role == "admin" {
		model.DB().Model(&model.CoreGrained{}).Where("username =?", user).First(&p)

		if err := json.Unmarshal(p.Permissions, &px); err != nil {
			c.Logger().Error(err.Error())
			return false
		}

		switch r {
		case "user":
			return px.User == "1"
		case "db":
			return px.Base == "1"
		}

	}
	return false
}

func ResearchDel(s []string, p string) []string {
	for in := 0; in < len(s); in++ {
		if s[in] == p {
			s = append(s[:in], s[in+1:]...)
			in--
		}
	}
	return s
}

func Paging(page interface{}, total int) (start int, end int) {
	var i int
	switch v := page.(type) {
	case string:
		i, _ = strconv.Atoi(v)
	case int:
		i = v
	}
	start = i*total - total
	end = total
	return
}

func LdapConnenct(c echo.Context, l *model.Ldap, user string, pass string, isTest bool) bool {

	var s string

	ld, err := ldap.Dial("tcp", l.Url)

	if l.Ldaps {
		if err := ld.StartTLS(&tls.Config{InsecureSkipVerify: true});err != nil {
			log.Println(err.Error())
		}
	}

	if err != nil {
		c.Logger().Error(err.Error())
		return false
	}

	defer ld.Close()

	if ld != nil {
		if err := ld.Bind(l.User, l.Password); err != nil {
			return false
		}
		if isTest {
			return true
		}

	}

	if l.Type == 1 {
		s = fmt.Sprintf("(sAMAccountName=%s)", user)
	} else if l.Type == 2 {
		s = fmt.Sprintf("(uid=%s)", user)
	} else {
		s = fmt.Sprintf("(cn=%s)", user)
	}

	searchRequest := ldap.NewSearchRequest(
		l.Sc,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=organizationalPerson)%s)", s),
		[]string{"dn"},
		nil,
	)

	sr, err := ld.Search(searchRequest)

	if err != nil {
		log.Println(err.Error())
		return false
	}

	if len(sr.Entries) != 1 {
		log.Println("User does not exist or too many entries returned")
		return false
	}

	userdn := sr.Entries[0].DN

	if err := ld.Bind(userdn, pass); err != nil {
		c.Logger().Error(err.Error())
		return false
	}
	return true
}

func Axis() []string {
	var s []string
	currentTime := time.Now()
	for a := 0; a < 7; a++ {
		oldTime := currentTime.AddDate(0, 0, -a)
		s = append(s, oldTime.Format("2006-01-02"))
	}
	return s
}

func GenWorkid() string {
	rand.Seed(time.Now().UnixNano())
	a := rand.Intn(1000)
	c := strconv.Itoa(a)
	now := time.Now()
	return now.Format("20060102150405") + c
}

func Intersect(o, n []string) []string {
	m := make(map[string]int)
	var arr []string
	for _, v := range o {
		m[v]++
	}
	for _, v := range n {
		m[v]++
		if m[v] > 1 {
			arr = append(arr, v)
		}
	}
	return arr
}

func NonIntersect(o, n []string) []string {
	m := make(map[string]int)
	var arr []string
	for _, v := range o {
		m[v]++
	}
	for _, v := range n {
		m[v]++
		if m[v] == 1 {
			arr = append(arr, v)
		}
	}
	return arr
}

func TimerEx(order *model.CoreSqlOrder) time.Duration {
	if order.Delay != "none" {
		now := time.Now()
		dt, _ := time.ParseInLocation("2006-01-02 15:04 ", order.Delay, time.Local)
		after := dt.Sub(now)
		if after+1 > 0 {
			return after
		}
	}
	return 0
}

func TimeDifference(t string) bool {
	dt, _ := time.ParseInLocation("2006-01-02 15:04 ", t, time.Local)
	f := dt.Sub(time.Now())
	if math.Abs(f.Minutes()) > float64(model.GloOther.ExQueryTime) && float64(model.GloOther.ExQueryTime) > 0 {
		return true
	}
	return false
}

type querydata struct {
	Field []map[string]string
	Data  []map[string]interface{}
}

func QueryMethod(source *model.CoreDataSource, req *model.Queryresults, wordList []string) (querydata, error) {

	var qd querydata

	ps := Decrypt(source.Password)

	db, err := sqlx.Connect("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&readTimeout=%ds", source.Username, ps, source.IP, source.Port, req.Basename,model.GloOther.QueryTimeout))

	if err != nil {
		return qd, err
	}

	defer db.Close()

	rows, err := db.Queryx(req.Sql)

	if err != nil {
		return qd, err
	}

	cols, err := rows.Columns()

	if err != nil {
		return qd, err
	}
	defer rows.Close()
	for rows.Next() {

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

		rows.MapScan(results)

		for idx := range results {
			switch r := results[idx].(type) {
			case []uint8:
				if len(r) > 10000 {
					results[idx] = "blob字段无法显示"
				} else {
					if hex.EncodeToString(r) == "01" {
						results[idx] = "true"
					} else if hex.EncodeToString(r) == "00" {
						results[idx] = "false"
					} else {
						results[idx] = string(r)
					}
				}
			}
		}

		if len(wordList) > 0 {
			for ok := range results {
				for _, exclude := range wordList {
					if ok == exclude {
						results[ok] = "****脱敏字段"
					}
				}
			}
		}

		qd.Data = append(qd.Data, results)
	}

	for _, cv := range cols {
		qd.Field = append(qd.Field, map[string]string{"title": cv, "key": cv, "width": "200"})
	}
	qd.Field[0]["fixed"] = "left"

	return qd, nil
}
<commit_msg>v2.2.1<commit_after>// Copyright 2019 HenryYee.
//
// Licensed under the AGPL, Version 3.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.gnu.org/licenses/agpl-3.0.en.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package lib

import (
	"Yearning-go/src/model"
	"crypto/tls"
	"encoding/hex"
	"encoding/json"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/labstack/echo/v4"
	"gopkg.in/ldap.v3"
	"log"
	"math"
	"math/rand"
	"strconv"
	"time"
)

func SuperAuth(c echo.Context, r string) bool {
	var p model.CoreGrained
	var px model.PermissionList
	user, role := JwtParse(c)
	if role == "admin" {
		model.DB().Model(&model.CoreGrained{}).Where("username =?", user).First(&p)

		if err := json.Unmarshal(p.Permissions, &px); err != nil {
			c.Logger().Error(err.Error())
			return false
		}

		switch r {
		case "user":
			return px.User == "1"
		case "db":
			return px.Base == "1"
		}

	}
	return false
}

func ResearchDel(s []string, p string) []string {
	for in := 0; in < len(s); in++ {
		if s[in] == p {
			s = append(s[:in], s[in+1:]...)
			in--
		}
	}
	return s
}

func Paging(page interface{}, total int) (start int, end int) {
	var i int
	switch v := page.(type) {
	case string:
		i, _ = strconv.Atoi(v)
	case int:
		i = v
	}
	start = i*total - total
	end = total
	return
}

func LdapConnenct(c echo.Context, l *model.Ldap, user string, pass string, isTest bool) bool {

	var s string

	ld, err := ldap.Dial("tcp", l.Url)

	if l.Ldaps {
		if err := ld.StartTLS(&tls.Config{InsecureSkipVerify: true});err != nil {
			log.Println(err.Error())
		}
	}

	if err != nil {
		c.Logger().Error(err.Error())
		return false
	}

	defer ld.Close()

	if ld != nil {
		if err := ld.Bind(l.User, l.Password); err != nil {
			return false
		}
		if isTest {
			return true
		}

	}

	if l.Type == 1 {
		s = fmt.Sprintf("(sAMAccountName=%s)", user)
	} else if l.Type == 2 {
		s = fmt.Sprintf("(uid=%s)", user)
	} else {
		s = fmt.Sprintf("(cn=%s)", user)
	}

	searchRequest := ldap.NewSearchRequest(
		l.Sc,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=organizationalPerson)%s)", s),
		[]string{"dn"},
		nil,
	)

	sr, err := ld.Search(searchRequest)

	if err != nil {
		log.Println(err.Error())
		return false
	}

	if len(sr.Entries) != 1 {
		log.Println("User does not exist or too many entries returned")
		return false
	}

	userdn := sr.Entries[0].DN

	if err := ld.Bind(userdn, pass); err != nil {
		c.Logger().Error(err.Error())
		return false
	}
	return true
}

func Axis() []string {
	var s []string
	currentTime := time.Now()
	for a := 0; a < 7; a++ {
		oldTime := currentTime.AddDate(0, 0, -a)
		s = append(s, oldTime.Format("2006-01-02"))
	}
	return s
}

func GenWorkid() string {
	rand.Seed(time.Now().UnixNano())
	a := rand.Intn(1000)
	c := strconv.Itoa(a)
	now := time.Now()
	return now.Format("20060102150405") + c
}

func Intersect(o, n []string) []string {
	m := make(map[string]int)
	var arr []string
	for _, v := range o {
		m[v]++
	}
	for _, v := range n {
		m[v]++
		if m[v] > 1 {
			arr = append(arr, v)
		}
	}
	return arr
}

func NonIntersect(o, n []string) []string {
	m := make(map[string]int)
	var arr []string
	for _, v := range o {
		m[v]++
	}
	for _, v := range n {
		m[v]++
		if m[v] == 1 {
			arr = append(arr, v)
		}
	}
	return arr
}

func TimerEx(order *model.CoreSqlOrder) time.Duration {
	if order.Delay != "none" {
		now := time.Now()
		dt, _ := time.ParseInLocation("2006-01-02 15:04 ", order.Delay, time.Local)
		after := dt.Sub(now)
		if after+1 > 0 {
			return after
		}
	}
	return 0
}

func TimeDifference(t string) bool {
	dt, _ := time.ParseInLocation("2006-01-02 15:04 ", t, time.Local)
	f := dt.Sub(time.Now())
	if math.Abs(f.Minutes()) > float64(model.GloOther.ExQueryTime) && float64(model.GloOther.ExQueryTime) > 0 {
		return true
	}
	return false
}

type querydata struct {
	Field []map[string]string
	Data  []map[string]interface{}
}

func QueryMethod(source *model.CoreDataSource, req *model.Queryresults, wordList []string) (querydata, error) {

	var qd querydata

	ps := Decrypt(source.Password)

	db, err := sqlx.Connect("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&readTimeout=%ds", source.Username, ps, source.IP, source.Port, req.Basename,model.GloOther.QueryTimeout))

	if err != nil {
		return qd, err
	}

	defer db.Close()

	rows, err := db.Queryx(req.Sql)

	if err != nil {
		return qd, err
	}

	cols, err := rows.Columns()

	if err != nil {
		return qd, err
	}
	defer rows.Close()
	for rows.Next() {

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

		rows.MapScan(results)

		for idx := range results {
			switch r := results[idx].(type) {
			case []uint8:
				if len(r) > 10000 {
					results[idx] = "blob字段无法显示"
				} else {
					if hex.EncodeToString(r) == "01" {
						results[idx] = "true"
					} else if hex.EncodeToString(r) == "00" {
						results[idx] = "false"
					} else {
						results[idx] = string(r)
					}
				}
			}
		}

		if len(wordList) > 0 {
			for ok := range results {
				for _, exclude := range wordList {
					if ok == exclude {
						results[ok] = "****脱敏字段"
					}
				}
			}
		}

		qd.Data = append(qd.Data, results)
	}

	ele := removeDuplicateElement(cols)

	for _, cv := range ele {
		qd.Field = append(qd.Field, map[string]string{"title": cv, "key": cv, "width": "200"})
	}
	qd.Field[0]["fixed"] = "left"

	return qd, nil
}

func removeDuplicateElement(slice []string) []string {
	result := make([]string, 0, len(slice))
	temp := map[string]struct{}{}
	idx := 0
	for _, item := range slice {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			result = append(result, item)
		} else {
			idx++
			item += fmt.Sprintf("(%v)", idx)
			result = append(result, item)
		}
	}
	return result
}<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
//
// 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 serial provides routines for interacting with serial ports.
// Currently it supports only OS X; see the readme file for details.

package serial

import "io"
import "os"

// Valid parity values.
type ParityMode int

const (
	PARITY_NONE = 0
	PARITY_ODD  = 1
	PARITY_EVEN = 2
)

// OpenOptions is the struct containing all of the options necessary for
// opening a serial port.
type OpenOptions struct {
	// The name of the port, e.g. "/dev/tty.usbserial-A8008HlV".
	PortName string

	// The baud rate for the port. The following values are supported:
	//
	//    50
	//    75
	//    110
	//    134
	//    150
	//    200
	//    300
	//    600
	//    1200
	//    1800
	//    2400
	//    4800
	//    7200
	//    9600
	//    14400
	//    19200
	//    28800
	//    38400
	//    57600
	//    76800
	//    115200
	//    230400
	//
	BaudRate uint

	// The number of data bits per frame. Legal values are 5, 6, 7, and 8.
	DataBits uint

	// The number of stop bits per frame. Legal values are 1 and 2.
	StopBits uint

	// The type of parity bits to use for the connection. Currently parity errors
	// are simply ignored; that is, bytes are delivered to the user no matter
	// whether they were received with a parity error or not.
	ParityMode ParityMode
}

// Open creates an io.ReadWriteCloser based on the supplied options struct.
func Open(options OpenOptions) (io.ReadWriteCloser, os.Error) {
	// Redirect to the OS-specific function.
	return openInternal(options)
}
<commit_msg>Added VMIN and VTIME fields, for #1.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
//
// 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 serial provides routines for interacting with serial ports.
// Currently it supports only OS X; see the readme file for details.

package serial

import "io"
import "os"

// Valid parity values.
type ParityMode int

const (
	PARITY_NONE = 0
	PARITY_ODD  = 1
	PARITY_EVEN = 2
)

// OpenOptions is the struct containing all of the options necessary for
// opening a serial port.
type OpenOptions struct {
	// The name of the port, e.g. "/dev/tty.usbserial-A8008HlV".
	PortName string

	// The baud rate for the port. The following values are supported:
	//
	//    50
	//    75
	//    110
	//    134
	//    150
	//    200
	//    300
	//    600
	//    1200
	//    1800
	//    2400
	//    4800
	//    7200
	//    9600
	//    14400
	//    19200
	//    28800
	//    38400
	//    57600
	//    76800
	//    115200
	//    230400
	//
	BaudRate uint

	// The number of data bits per frame. Legal values are 5, 6, 7, and 8.
	DataBits uint

	// The number of stop bits per frame. Legal values are 1 and 2.
	StopBits uint

	// The type of parity bits to use for the connection. Currently parity errors
	// are simply ignored; that is, bytes are delivered to the user no matter
	// whether they were received with a parity error or not.
	ParityMode ParityMode

	// An inter-character timeout value, in milliseconds, and a minimum number of
	// bytes to block for on each read. A call to Read() that otherwise may block
	// waiting for more data will return immediately if the specified amount of
	// time elapses between successive bytes received from the device or if the
	// minimum number of bytes has been exceeded.
	//
	// Note that the inter-character timeout value may be rounded to the nearest
	// 100 ms on some systems, and that behavior is undefined if calls to Read
	// supply a buffer whose length is less than the minimum read size.
	//
	// Behaviors for various settings for these values are described below. For
	// more information, see the discussion of VMIN and VTIME here:
	//
	//     http://www.unixwiz.net/techtips/termios-vmin-vtime.html
	//
	// InterCharacterTimeout = 0 and MinimumReadSize = 0 (the default):
	//     This arrangement is not legal; you must explicitly set at least one of
	//     these fields to a positive number. (If MinimumReadSize is zero then
	//     InterCharacterTimeout must be at least 100.)
	//
	// InterCharacterTimeout > 0 and MinimumReadSize = 0
	//     If data is already available on the read queue, it is transferred to
	//     the caller's buffer and the Read() call returns immediately.
	//     Otherwise, the call blocks until some data arrives or the
	//     InterCharacterTimeout milliseconds elapse from the start of the call.
	//
	// InterCharacterTimeout > 0 and MinimumReadSize > 0
	//     Calls to Read() return when at least MinimumReadSize bytes are
	//     available or when InterCharacterTimeout milliseconds elapse between
	//     received bytes. The inter-character timer is not started until the
	//     first byte arrives.
	//
	// InterCharacterTimeout = 0 and MinimumReadSize > 0
	//     Calls to Read() return only when at least MinimumReadSize bytes are
	//     available. The inter-character timer is not used.
	//
	InterCharacterTimeout uint
	MinimumReadSize uint
}

// Open creates an io.ReadWriteCloser based on the supplied options struct.
func Open(options OpenOptions) (io.ReadWriteCloser, os.Error) {
	// Redirect to the OS-specific function.
	return openInternal(options)
}
<|endoftext|>


<commit_before>package testique

import (
    "net"
    "flag"
    "strings"
    "warserver/logger"
    "warserver/PortMgmt"
    "warserver/connection"
)

const (
    RECV_BUF_LEN = 1024
)

var serverPort PortMgmt.PortInfo

var testHandlers = make(map [string]func(msg string) string)

func Main() {
    portString := flag.String("port", ":5269", "Test server port")
    flag.Parse()

    serverPort = PortMgmt.NewPortInfo(*portString)

    setupHandlers();

    // might as well go straight to std out for a testserver
    logger.SetupLoggerHelper("/dev/stdout")

    logger.Infof("Accepting testserver connections on port %s", serverPort)
    handleConnections(serverPort.Port)
}

func setupHandlers() {
    testHandlers["new"] = testNewGame
    testHandlers["view"] = testViewWorld
}

func testNewGame(msg string) string {
    return "new:success"
}

func testViewWorld(msg string) string {
    return "view:success:{\"world\":{\"terrain\":[[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]], \"units\": []}}"
}

func handleConnections(port string) {
    ln, err := net.Listen("tcp", port)
    if err != nil {
        logger.Fatalf("Could not open socket for listening: %s", err)
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            logger.Errorf("Could not accept connection from client: %s", err)
            continue
        }
        sconn := connection.NewSocketConn(conn)
        go serveConnection(sconn)
    }
}

func serveConnection(sock *connection.SocketConn) {
    logger.Info("Serving new test connection")
    for {
        msg, err := sock.Read()
        if err != nil {
            // Should gracefully shutdown someday on EOF or UnexpectedEOF
            logger.Errorf("Error reading from client: %s", err)
            break
        }
        resp := parseMessage(string(msg))
        err = sock.Write([]byte(resp))
        if err != nil {
            logger.Errorf("Error writing to client: %s", err)
            break
        }
    }
}

func parseMessage(msg string) string {
    cmds := strings.SplitN(msg, ":", 2)
    if len(cmds) == 2 {
        if fun, ok := testHandlers[cmds[0]]; ok {
            return fun(cmds[1])
        } else {
            logger.Warnf("Unrecognized command: %s", cmds[0])
            return "unrecognized:"
        }
    }
    return "malformed:"
}<commit_msg>Refactor view world for slightly nicer appearance<commit_after>package testique

import (
    "net"
    "flag"
    "strings"
    "warserver/logger"
    "warserver/PortMgmt"
    "warserver/connection"
)

const (
    RECV_BUF_LEN = 1024
)

var serverPort PortMgmt.PortInfo

var testHandlers = make(map [string]func(msg string) string)

func Main() {
    portString := flag.String("port", ":5269", "Test server port")
    flag.Parse()

    serverPort = PortMgmt.NewPortInfo(*portString)

    setupHandlers();

    // might as well go straight to std out for a testserver
    logger.SetupLoggerHelper("/dev/stdout")

    logger.Infof("Accepting testserver connections on port %s", serverPort)
    handleConnections(serverPort.Port)
}

func setupHandlers() {
    testHandlers["new"] = testNewGame
    testHandlers["view"] = testViewWorld
}

func testNewGame(msg string) string {
    return "new:success"
}

func testViewWorld(msg string) string {
    unit := "{\"unit\":{\"loc\":{\"x\": 1, \"y\": 2}," +
                       "\"name\": \"Tank\"," +
                       "\"nation\": \"0\"," +
                       "\"movement\":{" +
                            "\"speeds\":{\"0\":1}," +
                            "\"name\":\"treads\"" +
                                    "}" +
                     "}" +
            "}"
    return "view:success:{\"world\":{\"terrain\":[[0,0,0,0,0]," +
                                                 "[0,0,0,0,0]," +
                                                 "[0,0,0,0,0]," +
                                                 "[0,0,0,0,0]," +
                                                 "[0,0,0,0,0]]," +
                                    "\"units\": [" + unit + "]}}"
}

}

func handleConnections(port string) {
    ln, err := net.Listen("tcp", port)
    if err != nil {
        logger.Fatalf("Could not open socket for listening: %s", err)
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            logger.Errorf("Could not accept connection from client: %s", err)
            continue
        }
        sconn := connection.NewSocketConn(conn)
        go serveConnection(sconn)
    }
}

func serveConnection(sock *connection.SocketConn) {
    logger.Info("Serving new test connection")
    for {
        msg, err := sock.Read()
        if err != nil {
            // Should gracefully shutdown someday on EOF or UnexpectedEOF
            logger.Errorf("Error reading from client: %s", err)
            break
        }
        resp := parseMessage(string(msg))
        err = sock.Write([]byte(resp))
        if err != nil {
            logger.Errorf("Error writing to client: %s", err)
            break
        }
    }
}

func parseMessage(msg string) string {
    cmds := strings.SplitN(msg, ":", 2)
    if len(cmds) == 2 {
        if fun, ok := testHandlers[cmds[0]]; ok {
            return fun(cmds[1])
        } else {
            logger.Warnf("Unrecognized command: %s", cmds[0])
            return "unrecognized:"
        }
    }
    return "malformed:"
}<|endoftext|>


<commit_before>package ergo

import (
	"strings"

	"github.com/wlMalk/ergo/constants"
)

var (
	MaxMemory int64 = 32 << 20 // 32 MB
)

type OperationMap map[string]*Operation

func (om OperationMap) GetOperation(method string) (*Operation, bool) {
	o, ok := om[strings.ToUpper(method)]
	if !ok {
		o, ok = om[""]
	}
	return o, ok
}

// Operation

type Operation struct {
	root          *Ergo
	route         *Route
	method        string
	name          string
	description   string
	handler       Handler
	params        map[string]*Param
	schemes       []string
	consumes      []string
	produces      []string
	containsFiles bool
	bodyParams    bool
}

func NewOperation(handler Handler) *Operation {
	if handler == nil {
		panic("Handler cannot be nil")
	}
	return &Operation{
		handler: handler,
		params:  map[string]*Param{},
	}
}

func ANY(function HandlerFunc) *Operation {
	return HandleANY(HandlerFunc(function))
}

func HandleANY(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_ANY)
}

func GET(function HandlerFunc) *Operation {
	return HandleGET(HandlerFunc(function))
}

func HandleGET(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_GET)
}

func POST(function HandlerFunc) *Operation {
	return HandlePOST(HandlerFunc(function))
}

func HandlePOST(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_POST)
}

func PUT(function HandlerFunc) *Operation {
	return HandlePUT(HandlerFunc(function))
}

func HandlePUT(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_PUT)
}

func DELETE(function HandlerFunc) *Operation {
	return HandleDELETE(HandlerFunc(function))
}

func HandleDELETE(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_DELETE)
}

// Name sets the name of the operation.
func (o *Operation) Name(name string) *Operation {
	o.name = name
	return o
}

// GetName returns the name of the operation.
func (o *Operation) GetName() string {
	return o.name
}

// GetName returns the description of the operation.
func (o *Operation) GetDescription() string {
	return o.description
}

// Description sets the description of the operation.
func (o *Operation) Description(description string) *Operation {
	o.description = description
	return o
}

func (o *Operation) Method(method string) *Operation {
	if method == constants.METHOD_ANY ||
		method == constants.METHOD_GET ||
		method == constants.METHOD_POST ||
		method == constants.METHOD_PUT ||
		method == constants.METHOD_DELETE {
		o.method = method
	}
	return o
}

func (o *Operation) GetMethod() string {
	return o.method
}

// Schemes is not additive, meaning that it'll reset the schemes
// already defined with what it's been given if they are valid.
func (o *Operation) Schemes(s ...string) *Operation {
	schemes(o, s)
	return o
}

func (o *Operation) Consumes(mimes ...string) *Operation {
	consumes(o, mimes)
	return o
}

func (o *Operation) Produces(mimes ...string) *Operation {
	produces(o, mimes)
	return o
}

func (o *Operation) GetSchemes() []string {
	return o.schemes
}

func (o *Operation) GetConsumes() []string {
	return o.consumes
}

func (o *Operation) GetProduces() []string {
	return o.produces
}

func (o *Operation) Params(params ...*Param) *Operation {
	addParams(o, params...)
	return o
}

func (o *Operation) GetParams() map[string]*Param {
	return o.params
}

func (o *Operation) GetParamsSlice() []*Param {
	var params []*Param
	for _, p := range o.params {
		params = append(params, p)
	}
	return params
}

func (o *Operation) ResetParams(params ...*Param) *Operation {
	o.setParamsSlice(params...)
	return o
}

func (o *Operation) SetParams(params map[string]*Param) *Operation {
	o.setParams(params)
	return o
}

func (o *Operation) IgnoreParams(params ...string) *Operation {
	ignoreParams(o, params...)
	return o
}

func (o *Operation) IgnoreParamsBut(params ...string) *Operation {
	ignoreParamsBut(o, params...)
	return o
}

func (o *Operation) ServeHTTP(res *Response, req *Request) {
}

func (o *Operation) setSchemes(schemes []string) {
	o.schemes = schemes
}

func (o *Operation) setConsumes(mimes []string) {
	o.consumes = mimes
}

func (o *Operation) setProduces(mimes []string) {
	o.produces = mimes
}

func (o *Operation) setParams(params map[string]*Param) {
	if params == nil {
		params = make(map[string]*Param)
	}
	o.params = params
}

func (o *Operation) setParamsSlice(params ...*Param) {
	paramsMap := map[string]*Param{}
	for _, p := range params {
		o.params[p.name] = p
	}
	o.setParams(paramsMap)
}
<commit_msg>GetRoute function for Operation<commit_after>package ergo

import (
	"strings"

	"github.com/wlMalk/ergo/constants"
)

var (
	MaxMemory int64 = 32 << 20 // 32 MB
)

type OperationMap map[string]*Operation

func (om OperationMap) GetOperation(method string) (*Operation, bool) {
	o, ok := om[strings.ToUpper(method)]
	if !ok {
		o, ok = om[""]
	}
	return o, ok
}

// Operation

type Operation struct {
	root          *Ergo
	route         *Route
	method        string
	name          string
	description   string
	handler       Handler
	params        map[string]*Param
	schemes       []string
	consumes      []string
	produces      []string
	containsFiles bool
	bodyParams    bool
}

func NewOperation(handler Handler) *Operation {
	if handler == nil {
		panic("Handler cannot be nil")
	}
	return &Operation{
		handler: handler,
		params:  map[string]*Param{},
	}
}

func ANY(function HandlerFunc) *Operation {
	return HandleANY(HandlerFunc(function))
}

func HandleANY(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_ANY)
}

func GET(function HandlerFunc) *Operation {
	return HandleGET(HandlerFunc(function))
}

func HandleGET(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_GET)
}

func POST(function HandlerFunc) *Operation {
	return HandlePOST(HandlerFunc(function))
}

func HandlePOST(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_POST)
}

func PUT(function HandlerFunc) *Operation {
	return HandlePUT(HandlerFunc(function))
}

func HandlePUT(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_PUT)
}

func DELETE(function HandlerFunc) *Operation {
	return HandleDELETE(HandlerFunc(function))
}

func HandleDELETE(handler Handler) *Operation {
	return NewOperation(handler).Method(constants.METHOD_DELETE)
}

// Name sets the name of the operation.
func (o *Operation) Name(name string) *Operation {
	o.name = name
	return o
}

// GetName returns the name of the operation.
func (o *Operation) GetName() string {
	return o.name
}

// GetName returns the description of the operation.
func (o *Operation) GetDescription() string {
	return o.description
}

// Description sets the description of the operation.
func (o *Operation) Description(description string) *Operation {
	o.description = description
	return o
}

func (o *Operation) Method(method string) *Operation {
	if method == constants.METHOD_ANY ||
		method == constants.METHOD_GET ||
		method == constants.METHOD_POST ||
		method == constants.METHOD_PUT ||
		method == constants.METHOD_DELETE {
		o.method = method
	}
	return o
}

func (o *Operation) GetMethod() string {
	return o.method
}

// Schemes is not additive, meaning that it'll reset the schemes
// already defined with what it's been given if they are valid.
func (o *Operation) Schemes(s ...string) *Operation {
	schemes(o, s)
	return o
}

func (o *Operation) Consumes(mimes ...string) *Operation {
	consumes(o, mimes)
	return o
}

func (o *Operation) Produces(mimes ...string) *Operation {
	produces(o, mimes)
	return o
}

func (o *Operation) GetSchemes() []string {
	return o.schemes
}

func (o *Operation) GetConsumes() []string {
	return o.consumes
}

func (o *Operation) GetProduces() []string {
	return o.produces
}

func (o *Operation) GetRoute() Router {
	return o.route
}

func (o *Operation) Params(params ...*Param) *Operation {
	addParams(o, params...)
	return o
}

func (o *Operation) GetParams() map[string]*Param {
	return o.params
}

func (o *Operation) GetParamsSlice() []*Param {
	var params []*Param
	for _, p := range o.params {
		params = append(params, p)
	}
	return params
}

func (o *Operation) ResetParams(params ...*Param) *Operation {
	o.setParamsSlice(params...)
	return o
}

func (o *Operation) SetParams(params map[string]*Param) *Operation {
	o.setParams(params)
	return o
}

func (o *Operation) IgnoreParams(params ...string) *Operation {
	ignoreParams(o, params...)
	return o
}

func (o *Operation) IgnoreParamsBut(params ...string) *Operation {
	ignoreParamsBut(o, params...)
	return o
}

func (o *Operation) ServeHTTP(res *Response, req *Request) {
}

func (o *Operation) setSchemes(schemes []string) {
	o.schemes = schemes
}

func (o *Operation) setConsumes(mimes []string) {
	o.consumes = mimes
}

func (o *Operation) setProduces(mimes []string) {
	o.produces = mimes
}

func (o *Operation) setParams(params map[string]*Param) {
	if params == nil {
		params = make(map[string]*Param)
	}
	o.params = params
}

func (o *Operation) setParamsSlice(params ...*Param) {
	paramsMap := map[string]*Param{}
	for _, p := range params {
		o.params[p.name] = p
	}
	o.setParams(paramsMap)
}
<|endoftext|>


<commit_before>package ops

import (
	"bsearch/index"
	"container/heap"
)

type union []QueryOp

func NewUnion(n ...QueryOp) QueryContainer {
	var un union

	heap.Init(&un)

	un.Add(n...)
	return &un
}

func (un *union) Add(nodes ...QueryOp) {
	for _, n := range nodes {
		heap.Push(un, n)
	}
}

func (un *union) CurrentDoc() *index.IbDoc {
	h := un.peek()
	if h == nil {
		return nil
	}
	return h.CurrentDoc()
}

func (un *union) NextDoc(search *index.IbDoc) *index.IbDoc {
	d := un.CurrentDoc()
	// Chew up all documents bigger than search
	for d != nil && search.Cmp(d) < 0 {
		/*
		 * We could use a heap.UpdateHead here to avoid all those expensive
		 * Pop/Push. It is trivially implemented with heap.down(h, 0, h.Len()),
		 * but unfortunately that's not exposed to us. Another alternative is
		 * heap.Init, but that's too brutal too.
		 */
		n := heap.Pop(un).(QueryOp)

		/* Only put the element back into the heap if it's not empty. */
		if n.NextDoc(search) != nil {
			heap.Push(un, n)
		}
		d = un.CurrentDoc()
	}
	return d
}

// Len returns the number of elements in the union.
// Needed to implement heap.Interface.
func (un union) Len() int {
	return len(un)
}

// Compares two elements and returns which one is bigger than the other.
// Needed to implement heap.Interface.
// It's called Less because the heap is a min heap, but we want a max heap.
func (un union) Less(i, j int) bool {
	a := un[i].CurrentDoc()
	b := un[j].CurrentDoc()
	return a.Cmp(b) > 0 // we want a max-heap
}

// Swap to elements in the union.
// Needed to implement heap.Interface.
func (un union) Swap(i, j int) {
	un[i], un[j] = un[j], un[i]
}

// Add an element at the end of the union.
// Needed to implement heap.Interface.
func (un *union) Push(x interface{}) {
	*un = append(*un, x.(QueryOp))
}

// Remove one element from the end of the union.
// Needed to implement heap.Interface.
func (un *union) Pop() interface{} {
	l := len(*un)
	r := (*un)[l-1]
	*un = (*un)[:l-1]
	return r
}

// Peek at the head of the heap.
func (un union) peek() QueryOp {
	l := len(un)
	if l > 0 {
		return un[l-1]
	}
	return nil
}

func (un union) ProcessHeaders(hc HeaderCollector) {
	for _, n := range un {
		n.ProcessHeaders(hc)
	}
}
<commit_msg>Don't add empty nodes into the union.<commit_after>package ops

import (
	"bsearch/index"
	"container/heap"
)

type union []QueryOp

func NewUnion(n ...QueryOp) QueryContainer {
	var un union

	heap.Init(&un)

	un.Add(n...)
	return &un
}

func (un *union) Add(nodes ...QueryOp) {
	for _, n := range nodes {
		if n.CurrentDoc() != nil {
			heap.Push(un, n)
		}
	}
}

func (un *union) CurrentDoc() *index.IbDoc {
	h := un.peek()
	if h == nil {
		return nil
	}
	return h.CurrentDoc()
}

func (un *union) NextDoc(search *index.IbDoc) *index.IbDoc {
	d := un.CurrentDoc()
	// Chew up all documents bigger than search
	for d != nil && search.Cmp(d) < 0 {
		/*
		 * We could use a heap.UpdateHead here to avoid all those expensive
		 * Pop/Push. It is trivially implemented with heap.down(h, 0, h.Len()),
		 * but unfortunately that's not exposed to us. Another alternative is
		 * heap.Init, but that's too brutal too.
		 */
		n := heap.Pop(un).(QueryOp)

		/* Only put the element back into the heap if it's not empty. */
		if n.NextDoc(search) != nil {
			heap.Push(un, n)
		}
		d = un.CurrentDoc()
	}
	return d
}

// Len returns the number of elements in the union.
// Needed to implement heap.Interface.
func (un union) Len() int {
	return len(un)
}

// Compares two elements and returns which one is bigger than the other.
// Needed to implement heap.Interface.
// It's called Less because the heap is a min heap, but we want a max heap.
func (un union) Less(i, j int) bool {
	a := un[i].CurrentDoc()
	b := un[j].CurrentDoc()
	return a.Cmp(b) > 0 // we want a max-heap
}

// Swap to elements in the union.
// Needed to implement heap.Interface.
func (un union) Swap(i, j int) {
	un[i], un[j] = un[j], un[i]
}

// Add an element at the end of the union.
// Needed to implement heap.Interface.
func (un *union) Push(x interface{}) {
	*un = append(*un, x.(QueryOp))
}

// Remove one element from the end of the union.
// Needed to implement heap.Interface.
func (un *union) Pop() interface{} {
	l := len(*un)
	r := (*un)[l-1]
	*un = (*un)[:l-1]
	return r
}

// Peek at the head of the heap.
func (un union) peek() QueryOp {
	l := len(un)
	if l > 0 {
		return un[l-1]
	}
	return nil
}

func (un union) ProcessHeaders(hc HeaderCollector) {
	for _, n := range un {
		n.ProcessHeaders(hc)
	}
}
<|endoftext|>


<commit_before>package robots

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
)

type SlashCommand struct {
	Payload
	Command string `schema:"command"`
}

type Payload struct {
	Token       string  `schema:"token"`
	TeamID      string  `schema:"team_id"`
	TeamDomain  string  `schema:"team_domain,omitempty"`
	ChannelID   string  `schema:"channel_id"`
	ChannelName string  `schema:"channel_name"`
	Timestamp   float64 `schema:"timestamp,omitempty"`
	UserID      string  `schema:"user_id"`
	UserName    string  `schema:"user_name"`
	Text        string  `schema:"text,omitempty"`
	TriggerWord string  `schema:"trigger_word,omitempty"`
	ServiceID   string  `schema:"service_id,omitempty"`
	Robot       string
}

type OutgoingWebHook struct {
	Payload
	TriggerWord string `schema:"trigger_word"`
}

type OutgoingWebHookResponse struct {
	Text      string     `json:"text"`
	Parse     ParseStyle `json:"parse,omitempty"`
	LinkNames bool       `json:"link_names,omitempty"`
	Markdown  bool       `json:"mrkdwn,omitempty"`
}

type ParseStyle string

var (
	ParseStyleFull = ParseStyle("full")
	ParseStyleNone = ParseStyle("none")
)

type IncomingWebhook struct {
	Domain      string       `json:"domain"`
	Channel     string       `json:"channel"`
	Username    string       `json:"username"`
	Text        string       `json:"text"`
	IconEmoji   string       `json:"icon_emoji,omitempty"`
	IconURL     string       `json:"icon_url,omitempty"`
	Attachments []Attachment `json:"attachments,omitempty"`
	UnfurlLinks bool         `json:"unfurl_links,omitempty"`
	Parse       ParseStyle   `json:"parse,omitempty"`
	LinkNames   bool         `json:"link_names,omitempty"`
	Markdown    bool         `json:"mrkdwn,omitempty"`
}

type Attachment struct {
	Fallback   string            `json:"fallback"`
	Pretext    string            `json:"pretext,omitempty"`
	Text       string            `json:"text,omitempty"`
	Color      string            `json:"color,omitempty"`
	Fields     []AttachmentField `json:"fields,omitempty"`
	MarkdownIn []MarkdownField   `json:"mrkdown_in,omitempty"`
}

type MarkdownField string

var (
	MarkdownFieldPretext  = MarkdownField("pretext")
	MarkdownFieldText     = MarkdownField("text")
	MarkdownFieldTitle    = MarkdownField("title")
	MarkdownFieldFields   = MarkdownField("fields")
	MarkdownFieldFallback = MarkdownField("fallback")
)

type AttachmentField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short,omitempty"`
}

// Send uses the IncomingWebhook API to post a message to a slack channel
func (i *IncomingWebhook) Send() error {
	log.Println("Parsing incoming webhook...")
	u := os.Getenv(fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)))
	log.Printf("In URL for %s: %s", fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)), u)
	if u != "" {
		return fmt.Errorf("Slack incoming webhook url not found for domain %s (check %s)", i.Domain, fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)))
	}
	webhook, err := url.Parse(u)
	if err != nil {
		return err
	}

	log.Printf("Sending incoming webhook to %s", webhook.Path)

	p, err := json.Marshal(i)
	if err != nil {
		return err
	}

	data := url.Values{}
	data.Set("payload", string(p))

	webhook.RawQuery = data.Encode()
	log.Printf("Posting incoming webhook to %#v", webhook)
	resp, err := http.PostForm(webhook.String(), data)
	if resp.StatusCode != 200 {
		message := fmt.Sprintf("ERROR: Non-200 Response from Slack Incoming Webhook API: %s", resp.Status)
		log.Println(message)
	}
	return err
}
<commit_msg>more logging<commit_after>package robots

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
)

type SlashCommand struct {
	Payload
	Command string `schema:"command"`
}

type Payload struct {
	Token       string  `schema:"token"`
	TeamID      string  `schema:"team_id"`
	TeamDomain  string  `schema:"team_domain,omitempty"`
	ChannelID   string  `schema:"channel_id"`
	ChannelName string  `schema:"channel_name"`
	Timestamp   float64 `schema:"timestamp,omitempty"`
	UserID      string  `schema:"user_id"`
	UserName    string  `schema:"user_name"`
	Text        string  `schema:"text,omitempty"`
	TriggerWord string  `schema:"trigger_word,omitempty"`
	ServiceID   string  `schema:"service_id,omitempty"`
	Robot       string
}

type OutgoingWebHook struct {
	Payload
	TriggerWord string `schema:"trigger_word"`
}

type OutgoingWebHookResponse struct {
	Text      string     `json:"text"`
	Parse     ParseStyle `json:"parse,omitempty"`
	LinkNames bool       `json:"link_names,omitempty"`
	Markdown  bool       `json:"mrkdwn,omitempty"`
}

type ParseStyle string

var (
	ParseStyleFull = ParseStyle("full")
	ParseStyleNone = ParseStyle("none")
)

type IncomingWebhook struct {
	Domain      string       `json:"domain"`
	Channel     string       `json:"channel"`
	Username    string       `json:"username"`
	Text        string       `json:"text"`
	IconEmoji   string       `json:"icon_emoji,omitempty"`
	IconURL     string       `json:"icon_url,omitempty"`
	Attachments []Attachment `json:"attachments,omitempty"`
	UnfurlLinks bool         `json:"unfurl_links,omitempty"`
	Parse       ParseStyle   `json:"parse,omitempty"`
	LinkNames   bool         `json:"link_names,omitempty"`
	Markdown    bool         `json:"mrkdwn,omitempty"`
}

type Attachment struct {
	Fallback   string            `json:"fallback"`
	Pretext    string            `json:"pretext,omitempty"`
	Text       string            `json:"text,omitempty"`
	Color      string            `json:"color,omitempty"`
	Fields     []AttachmentField `json:"fields,omitempty"`
	MarkdownIn []MarkdownField   `json:"mrkdown_in,omitempty"`
}

type MarkdownField string

var (
	MarkdownFieldPretext  = MarkdownField("pretext")
	MarkdownFieldText     = MarkdownField("text")
	MarkdownFieldTitle    = MarkdownField("title")
	MarkdownFieldFields   = MarkdownField("fields")
	MarkdownFieldFallback = MarkdownField("fallback")
)

type AttachmentField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short,omitempty"`
}

// Send uses the IncomingWebhook API to post a message to a slack channel
func (i *IncomingWebhook) Send() error {
	log.Println("Parsing incoming webhook...")
	u := os.Getenv(fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)))
	log.Printf("In URL for %s: %s", fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)), u)
	if u != "" {
		log.Println("Slack incoming webhook URL not found...")
		return fmt.Errorf("Slack incoming webhook url not found for domain %s (check %s)", i.Domain, fmt.Sprintf("%s_IN_URL", strings.ToUpper(i.Domain)))
	}
	webhook, err := url.Parse(u)
	if err != nil {
		log.Printf("Error parsing incoming webhook URL: %v", err)
		return err
	}

	log.Printf("Sending incoming webhook to %s", webhook.Path)

	p, err := json.Marshal(i)
	if err != nil {
		return err
	}

	data := url.Values{}
	data.Set("payload", string(p))

	webhook.RawQuery = data.Encode()
	log.Printf("Posting incoming webhook to %#v", webhook)
	resp, err := http.PostForm(webhook.String(), data)
	if resp.StatusCode != 200 {
		message := fmt.Sprintf("ERROR: Non-200 Response from Slack Incoming Webhook API: %s", resp.Status)
		log.Println(message)
	}
	return err
}
<|endoftext|>


<commit_before>package hcsshim

import (
	"encoding/json"
	"fmt"
	"net"

	"github.com/Sirupsen/logrus"
)

type NatPolicy struct {
	Type         string
	Protocol     string
	InternalPort uint16
	ExternalPort uint16
}

type QosPolicy struct {
	Type                            string
	MaximumOutgoingBandwidthInBytes uint64
}

type VlanPolicy struct {
	Type string
	VLAN uint
}

type VsidPolicy struct {
	Type string
	VSID uint
}

type PaPolicy struct {
	Type string
	PA   string
}

// Subnet is assoicated with a network and represents a list
// of subnets available to the network
type Subnet struct {
	AddressPrefix  string            `json:",omitempty"`
	GatewayAddress string            `json:",omitempty"`
	Policies       []json.RawMessage `json:",omitempty"`
}

// MacPool is assoicated with a network and represents a list
// of macaddresses available to the network
type MacPool struct {
	StartMacAddress string `json:",omitempty"`
	EndMacAddress   string `json:",omitempty"`
}

// HNSNetwork represents a network in HNS
type HNSNetwork struct {
	Id                   string            `json:",omitempty"`
	Name                 string            `json:",omitempty"`
	Type                 string            `json:",omitempty"`
	NetworkAdapterName   string            `json:",omitempty"`
	SourceMac            string            `json:",omitempty"`
	Policies             []json.RawMessage `json:",omitempty"`
	MacPools             []MacPool         `json:",omitempty"`
	Subnets              []Subnet          `json:",omitempty"`
	DNSSuffix            string            `json:",omitempty"`
	DNSServerList        string            `json:",omitempty"`
	DNSServerCompartment uint32            `json:",omitempty"`
	ManagementIP         string            `json:",omitempty"`
}

// HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct {
	Id                 string            `json:",omitempty"`
	Name               string            `json:",omitempty"`
	VirtualNetwork     string            `json:",omitempty"`
	VirtualNetworkName string            `json:",omitempty"`
	Policies           []json.RawMessage `json:",omitempty"`
	MacAddress         string            `json:",omitempty"`
	IPAddress          net.IP            `json:",omitempty"`
	DNSSuffix          string            `json:",omitempty"`
	DNSServerList      string            `json:",omitempty"`
	GatewayAddress     string            `json:",omitempty"`
	EnableInternalDNS  bool              `json:",omitempty"`
	PrefixLength       uint8             `json:",omitempty"`
	IsRemoteEndpoint   bool              `json:",omitempty"`
}

type hnsNetworkResponse struct {
	Success bool
	Error   string
	Output  HNSNetwork
}

type hnsResponse struct {
	Success bool
	Error   string
	Output  json.RawMessage
}

func hnsCall(method, path, request string, returnResponse interface{}) error {
	var responseBuffer *uint16
	err := _hnsCall(method, path, request, &responseBuffer)
	if err != nil {
		return makeError(err, "hnsCall ", "")
	}
	response := convertAndFreeCoTaskMemString(responseBuffer)

	hnsresponse := &hnsResponse{}
	if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
		return err
	}

	if !hnsresponse.Success {
		return fmt.Errorf("HNS failed with error : %s", hnsresponse.Error)
	}

	if len(hnsresponse.Output) == 0 {
		return nil
	}

	logrus.Debugf("Network Response : %s", hnsresponse.Output)
	err = json.Unmarshal(hnsresponse.Output, returnResponse)
	if err != nil {
		return err
	}

	return nil
}

// HNSNetworkRequest makes a call into HNS to update/query a single network
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
	var network HNSNetwork
	err := hnsCall(method, "/networks/"+path, request, &network)
	if err != nil {
		return nil, err
	}

	return &network, nil
}

// HNSListNetworkRequest makes a HNS call to query the list of available networks
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
	var network []HNSNetwork
	err := hnsCall(method, "/networks/"+path, request, &network)
	if err != nil {
		return nil, err
	}

	return network, nil
}

// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
	endpoint := &HNSEndpoint{}
	err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
	if err != nil {
		return nil, err
	}

	return endpoint, nil
}
<commit_msg>Control path support to disable ICC<commit_after>package hcsshim

import (
	"encoding/json"
	"fmt"
	"net"

	"github.com/Sirupsen/logrus"
)

type NatPolicy struct {
	Type         string
	Protocol     string
	InternalPort uint16
	ExternalPort uint16
}

type QosPolicy struct {
	Type                            string
	MaximumOutgoingBandwidthInBytes uint64
}

type VlanPolicy struct {
	Type string
	VLAN uint
}

type VsidPolicy struct {
	Type string
	VSID uint
}

type PaPolicy struct {
	Type string
	PA   string
}

// Subnet is assoicated with a network and represents a list
// of subnets available to the network
type Subnet struct {
	AddressPrefix  string            `json:",omitempty"`
	GatewayAddress string            `json:",omitempty"`
	Policies       []json.RawMessage `json:",omitempty"`
}

// MacPool is assoicated with a network and represents a list
// of macaddresses available to the network
type MacPool struct {
	StartMacAddress string `json:",omitempty"`
	EndMacAddress   string `json:",omitempty"`
}

// HNSNetwork represents a network in HNS
type HNSNetwork struct {
	Id                   string            `json:"ID,omitempty"`
	Name                 string            `json:",omitempty"`
	Type                 string            `json:",omitempty"`
	NetworkAdapterName   string            `json:",omitempty"`
	SourceMac            string            `json:",omitempty"`
	Policies             []json.RawMessage `json:",omitempty"`
	MacPools             []MacPool         `json:",omitempty"`
	Subnets              []Subnet          `json:",omitempty"`
	DNSSuffix            string            `json:",omitempty"`
	DNSServerList        string            `json:",omitempty"`
	DNSServerCompartment uint32            `json:",omitempty"`
	ManagementIP         string            `json:",omitempty"`
}

// HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct {
	Id                 string            `json:"ID,omitempty"`
	Name               string            `json:",omitempty"`
	VirtualNetwork     string            `json:",omitempty"`
	VirtualNetworkName string            `json:",omitempty"`
	Policies           []json.RawMessage `json:",omitempty"`
	MacAddress         string            `json:",omitempty"`
	IPAddress          net.IP            `json:",omitempty"`
	DNSSuffix          string            `json:",omitempty"`
	DNSServerList      string            `json:",omitempty"`
	GatewayAddress     string            `json:",omitempty"`
	EnableInternalDNS  bool              `json:",omitempty"`
	DisableICS         bool              `json:",omitempty"`
	PrefixLength       uint8             `json:",omitempty"`
	IsRemoteEndpoint   bool              `json:",omitempty"`
}

type hnsNetworkResponse struct {
	Success bool
	Error   string
	Output  HNSNetwork
}

type hnsResponse struct {
	Success bool
	Error   string
	Output  json.RawMessage
}

func hnsCall(method, path, request string, returnResponse interface{}) error {
	var responseBuffer *uint16
	err := _hnsCall(method, path, request, &responseBuffer)
	if err != nil {
		return makeError(err, "hnsCall ", "")
	}
	response := convertAndFreeCoTaskMemString(responseBuffer)

	hnsresponse := &hnsResponse{}
	if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
		return err
	}

	if !hnsresponse.Success {
		return fmt.Errorf("HNS failed with error : %s", hnsresponse.Error)
	}

	if len(hnsresponse.Output) == 0 {
		return nil
	}

	logrus.Debugf("Network Response : %s", hnsresponse.Output)
	err = json.Unmarshal(hnsresponse.Output, returnResponse)
	if err != nil {
		return err
	}

	return nil
}

// HNSNetworkRequest makes a call into HNS to update/query a single network
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
	var network HNSNetwork
	err := hnsCall(method, "/networks/"+path, request, &network)
	if err != nil {
		return nil, err
	}

	return &network, nil
}

// HNSListNetworkRequest makes a HNS call to query the list of available networks
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
	var network []HNSNetwork
	err := hnsCall(method, "/networks/"+path, request, &network)
	if err != nil {
		return nil, err
	}

	return network, nil
}

// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
	endpoint := &HNSEndpoint{}
	err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
	if err != nil {
		return nil, err
	}

	return endpoint, nil
}
<|endoftext|>


<commit_before>package hostess

import (
	"io/ioutil"
	"os"
	"runtime"
	"strings"
)

const defaultOSX = `
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##

127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0     localhost
`

const defaultLinux = `
127.0.0.1   localhost
127.0.1.1   HOSTNAME

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
`

// Hostfile represents /etc/hosts (or a similar file, depending on OS), and
// includes a list of Hostnames. Hostfile includes
type Hostfile struct {
	Path  string
	Hosts Hostlist
	data  []byte
}

// NewHostfile creates a new Hostfile object from the specified file.
func NewHostfile() *Hostfile {
	return &Hostfile{GetHostsPath(), Hostlist{}, []byte{}}
}

// GetHostsPath returns the location of the hostfile; either env HOSTESS_PATH
// or /etc/hosts if HOSTESS_PATH is not set.
func GetHostsPath() string {
	path := os.Getenv("HOSTESS_PATH")
	if path == "" {
		if runtime.GOOS == "windows" {
			path = "C:\\Windows\\System32\\drivers\\etc\\hosts"
		} else {
			path = "/etc/hosts"
		}
	}
	return path
}

// TrimWS (Trim Whitespace) removes space, newline, and tabs from a string
// using strings.Trim()
func TrimWS(s string) string {
	return strings.TrimSpace(s)
}

// ParseLine parses an individual line in a hostfile, which may contain one
// (un)commented ip and one or more hostnames. For example
//
//	127.0.0.1 localhost mysite1 mysite2
func ParseLine(line string) Hostlist {
	var hostnames Hostlist

	if len(line) == 0 {
		return hostnames
	}

	// Parse leading # for disabled lines
	enabled := true
	if line[0:1] == "#" {
		enabled = false
		line = TrimWS(line[1:])
	}

	// Parse other #s for actual comments
	line = strings.Split(line, "#")[0]

	// Replace tabs and multispaces with single spaces throughout
	line = strings.Replace(line, "\t", " ", -1)
	for strings.Contains(line, "  ") {
		line = strings.Replace(line, "  ", " ", -1)
	}

	// Break line into words
	words := strings.Split(line, " ")

	// Separate the first bit (the ip) from the other bits (the domains)
	ip := words[0]
	domains := words[1:]

	if LooksLikeIPv4(ip) || LooksLikeIPv6(ip) {
		for _, v := range domains {
			hostname := NewHostname(v, ip, enabled)
			hostnames = append(hostnames, hostname)
		}
	}

	return hostnames
}

// Parse reads
func (h *Hostfile) Parse() []error {
	var errs []error
	for _, v := range strings.Split(string(h.data), "\n") {
		for _, hostname := range ParseLine(v) {
			err := h.Hosts.Add(hostname)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}
	return errs
}

// Read the contents of the hostfile from disk
func (h *Hostfile) Read() error {
	data, err := ioutil.ReadFile(h.Path)
	if err == nil {
		h.data = data
	}
	return err
}

// LoadHostfile creates a new Hostfile struct and tries to populate it from
// disk. Read and/or parse errors are returned as a slice.
func LoadHostfile() (hostfile *Hostfile, errs []error) {
	hostfile = NewHostfile()
	readErr := hostfile.Read()
	if readErr != nil {
		errs = []error{readErr}
		return
	}
	errs = hostfile.Parse()
	hostfile.Hosts.Sort()
	return
}

// GetData returns the internal snapshot of the hostfile we read when we loaded
// this hostfile from disk (if we ever did that). This is implemented for
// testing and you probably won't need to use it.
func (h *Hostfile) GetData() []byte {
	return h.data
}

// Format takes the current list of Hostnames in this Hostfile and turns it
// into a string suitable for use as an /etc/hosts file.
// Sorting uses the following logic:
// 1. List is sorted by IP address
// 2. Commented items are left in place
// 3. 127.* appears at the top of the list (so boot resolvers don't break)
// 4. When present, localhost will always appear first in the domain list
func (h *Hostfile) Format() []byte {
	return h.Hosts.Format()
}

// Save writes the Hostfile to disk to /etc/hosts or to the location specified
// by the HOSTESS_PATH environment variable (if set).
func (h *Hostfile) Save() error {
	file, err := os.OpenFile(h.Path, os.O_RDWR|os.O_APPEND|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}

	defer file.Close()
	_, err = file.Write(h.Format())

	return err
}
<commit_msg>Added some extra trims to remove whitespace mid-line<commit_after>package hostess

import (
	"io/ioutil"
	"os"
	"runtime"
	"strings"
)

const defaultOSX = `
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##

127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0     localhost
`

const defaultLinux = `
127.0.0.1   localhost
127.0.1.1   HOSTNAME

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
`

// Hostfile represents /etc/hosts (or a similar file, depending on OS), and
// includes a list of Hostnames. Hostfile includes
type Hostfile struct {
	Path  string
	Hosts Hostlist
	data  []byte
}

// NewHostfile creates a new Hostfile object from the specified file.
func NewHostfile() *Hostfile {
	return &Hostfile{GetHostsPath(), Hostlist{}, []byte{}}
}

// GetHostsPath returns the location of the hostfile; either env HOSTESS_PATH
// or /etc/hosts if HOSTESS_PATH is not set.
func GetHostsPath() string {
	path := os.Getenv("HOSTESS_PATH")
	if path == "" {
		if runtime.GOOS == "windows" {
			path = "C:\\Windows\\System32\\drivers\\etc\\hosts"
		} else {
			path = "/etc/hosts"
		}
	}
	return path
}

// TrimWS (Trim Whitespace) removes space, newline, and tabs from a string
// using strings.Trim()
func TrimWS(s string) string {
	return strings.TrimSpace(s)
}

// ParseLine parses an individual line in a hostfile, which may contain one
// (un)commented ip and one or more hostnames. For example
//
//	127.0.0.1 localhost mysite1 mysite2
func ParseLine(line string) Hostlist {
	var hostnames Hostlist

	if len(line) == 0 {
		return hostnames
	}

	// Parse leading # for disabled lines
	enabled := true
	if line[0:1] == "#" {
		enabled = false
		line = TrimWS(line[1:])
	}

	// Parse other #s for actual comments
	line = strings.Split(line, "#")[0]

	// Replace tabs and multispaces with single spaces throughout
	line = strings.Replace(line, "\t", " ", -1)
	for strings.Contains(line, "  ") {
		line = strings.Replace(line, "  ", " ", -1)
	}
	line = TrimWS(line)

	// Break line into words
	words := strings.Split(line, " ")
	for idx, word := range words {
		words[idx] = TrimWS(word)
	}

	// Separate the first bit (the ip) from the other bits (the domains)
	ip := words[0]
	domains := words[1:]

	if LooksLikeIPv4(ip) || LooksLikeIPv6(ip) {
		for _, v := range domains {
			hostname := NewHostname(v, ip, enabled)
			hostnames = append(hostnames, hostname)
		}
	}

	return hostnames
}

// Parse reads
func (h *Hostfile) Parse() []error {
	var errs []error
	for _, v := range strings.Split(string(h.data), "\n") {
		for _, hostname := range ParseLine(v) {
			err := h.Hosts.Add(hostname)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}
	return errs
}

// Read the contents of the hostfile from disk
func (h *Hostfile) Read() error {
	data, err := ioutil.ReadFile(h.Path)
	if err == nil {
		h.data = data
	}
	return err
}

// LoadHostfile creates a new Hostfile struct and tries to populate it from
// disk. Read and/or parse errors are returned as a slice.
func LoadHostfile() (hostfile *Hostfile, errs []error) {
	hostfile = NewHostfile()
	readErr := hostfile.Read()
	if readErr != nil {
		errs = []error{readErr}
		return
	}
	errs = hostfile.Parse()
	hostfile.Hosts.Sort()
	return
}

// GetData returns the internal snapshot of the hostfile we read when we loaded
// this hostfile from disk (if we ever did that). This is implemented for
// testing and you probably won't need to use it.
func (h *Hostfile) GetData() []byte {
	return h.data
}

// Format takes the current list of Hostnames in this Hostfile and turns it
// into a string suitable for use as an /etc/hosts file.
// Sorting uses the following logic:
// 1. List is sorted by IP address
// 2. Commented items are left in place
// 3. 127.* appears at the top of the list (so boot resolvers don't break)
// 4. When present, localhost will always appear first in the domain list
func (h *Hostfile) Format() []byte {
	return h.Hosts.Format()
}

// Save writes the Hostfile to disk to /etc/hosts or to the location specified
// by the HOSTESS_PATH environment variable (if set).
func (h *Hostfile) Save() error {
	file, err := os.OpenFile(h.Path, os.O_RDWR|os.O_APPEND|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}

	defer file.Close()
	_, err = file.Write(h.Format())

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"syscall"

	"github.com/shirou/gopsutil/host"
)

// `hostinfo` represent the computer informations
type hostinfo struct {
	hostname        string // host name of the system ex 'mycomputer'
	domainname      string // domain name of the system ex 'mydomain.com'
	os              string // OS type ex 'Linux'
	osRelease       string // OS release ex '4.2.0-35-generic'
	platform        string // OS distribution or vendor ex 'Ubuntu'
	platformVersion string // OS distribution version ex '15.10'
	arch            string // architectureex. 'x86_64'
}

// Get informations about the computer by using `syscall`and `gopesutil` packages
func getHostinfo() hostinfo {

	uts := syscall.Utsname{} //TODO add os check because this is not portable
	err := syscall.Uname(&uts)
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}

	info, err := host.Info()
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}

	result := hostinfo{
		hostname:        info.Hostname,
		domainname:      int8ArrayToString(uts.Domainname[:]),
		os:              info.OS,
		osRelease:       int8ArrayToString(uts.Release[:]),
		platform:        info.Platform,
		platformVersion: info.PlatformVersion,
		arch:            int8ArrayToString(uts.Machine[:]),
	}
	return result
}

// uptime is in a separate func than `getHostinfo` to avoid unnecessary calls
// as all the host informations will normaly not change contrary to uptime
<commit_msg>Fix strings convertions<commit_after>package main

import (
	"strings"
	"syscall"

	"github.com/shirou/gopsutil/host"
)

// `hostinfo` represent the computer informations
type hostinfo struct {
	hostname        string // host name of the system ex 'mycomputer'
	domainname      string // domain name of the system ex 'mydomain.com'
	os              string // OS type ex 'Linux'
	osRelease       string // OS release ex '4.2.0-35-generic'
	platform        string // OS distribution or vendor ex 'Ubuntu'
	platformVersion string // OS distribution version ex '15.10'
	arch            string // architectureex. 'x86_64'
}

// Get informations about the computer by using `syscall`and `gopesutil` packages
func getHostinfo() hostinfo {

	uts := syscall.Utsname{}   //TODO add an OS check because this is not portable
	err := syscall.Uname(&uts) //TODO so we may use host.Info() for this
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}

	info, err := host.Info()
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}

	result := hostinfo{
		hostname:        info.Hostname,
		domainname:      int8SliceToString(uts.Domainname[:]),
		os:              strings.Title(info.OS),
		osRelease:       int8SliceToString(uts.Release[:]),
		platform:        strings.Title(info.Platform),
		platformVersion: info.PlatformVersion,
		arch:            int8SliceToString(uts.Machine[:]),
	}
	return result
}

// uptime is in a separate func than `getHostinfo` to avoid unnecessary calls
// as all the host informations will normaly not change contrary to uptime
<|endoftext|>


<commit_before>package main

/*
#include <unistd.h>
#include <string.h>
*/
import "C"

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"syscall"
)

var (
	fflag = flag.Bool("f", true, "Include domain information in the printed name. This is the default behavior.")
	sflag = flag.Bool("s", false, "Trim off any domain information from the printed name.")
)

func init() {
	log.SetFlags(0)
	log.SetOutput(os.Stderr)
}

func main() {
	flag.Usage = usage
	flag.Parse()

	*fflag = true

	if flag.NArg() > 1 {
		usage()
	}

	if flag.NArg() == 1 {
		if err := setHostname(flag.Arg(0)); err != nil {
			log.Fatalln(err)
		}
	} else {
		hostname, err := getHostname()
		if err != nil {
			log.Fatalln(err)
		}

		if *sflag {
			parts := strings.Split(hostname, ".")
			if len(parts) > 1 {
				hostname = parts[0]
			}
		}

		fmt.Println(hostname)
	}
}

func usage() {
	log.Fatalln("usage: hostname [-fs] [name-of-host]")
}

func setHostname(hostname string) error {
	hname := C.CString(hostname)
	_, err := C.sethostname(hname, C.int(C.strlen(hname)))
	return err
}

func getHostname() (string, error) {
	return syscall.Sysctl("kern.hostname")
}
<commit_msg>setHostName not use C<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
)

import (
	"github.com/sternix/commands/lib/sysctl"
)

var (
	fflag = flag.Bool("f", true, "Include domain information in the printed name. This is the default behavior.")
	sflag = flag.Bool("s", false, "Trim off any domain information from the printed name.")
)

func init() {
	log.SetFlags(0)
	log.SetOutput(os.Stderr)
}

func main() {
	flag.Usage = usage
	flag.Parse()

	*fflag = true

	if flag.NArg() > 1 {
		usage()
	}

	if flag.NArg() == 1 {
		if err := setHostname(flag.Arg(0)); err != nil {
			log.Fatalln(err)
		}
	} else {
		hostname, err := getHostname()
		if err != nil {
			log.Fatalln(err)
		}

		if *sflag {
			parts := strings.Split(hostname, ".")
			if len(parts) > 1 {
				hostname = parts[0]
			}
		}

		fmt.Println(hostname)
	}
}

func usage() {
	log.Fatalln("usage: hostname [-fs] [name-of-host]")
}

func setHostname(hostname string) error {
	return sysctl.SetString("kern.hostname", hostname)
}

func getHostname() (string, error) {
	return sysctl.ByName("kern.hostname")
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Erik St. Martin, Brian Ketelsen. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package server

import (
	"crypto/sha1"
	"github.com/miekg/dns"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

const origTTL uint32 = 60

var cache *sigCache = newCache()
var inflight *single = new(single)

// TODO(miek): allow RRSIG queries and NSEC queries?

// ParseKeyFile read a DNSSEC keyfile as generated by dnssec-keygen or other
// utilities. It add ".key" for the public key and ".private" for the private key.
func ParseKeyFile(file string) (*dns.DNSKEY, dns.PrivateKey, error) {
	f, e := os.Open(file + ".key")
	if e != nil {
		return nil, nil, e
	}
	k, e := dns.ReadRR(f, file+".key")
	if e != nil {
		return nil, nil, e
	}
	f, e = os.Open(file + ".private")
	if e != nil {
		return nil, nil, e
	}
	p, e := k.(*dns.DNSKEY).ReadPrivateKey(f, file+".private")
	if e != nil {
		return nil, nil, e
	}
	return k.(*dns.DNSKEY), p, nil
}

// nsec creates (if needed) NSEC records that are included in the reply.
func (s *Server) nsec(m *dns.Msg) {
	if m.Rcode == dns.RcodeNameError {
		// qname nsec
		nsec1 := s.newNSEC(m.Question[0].Name)
		m.Ns = append(m.Ns, nsec1)
		// wildcard nsec
		idx := dns.Split(m.Question[0].Name)
		wildcard := "*." + m.Question[0].Name[idx[0]:]
		nsec2 := s.newNSEC(wildcard)
		if nsec1.Hdr.Name != nsec2.Hdr.Name || nsec1.NextDomain != nsec2.NextDomain {
			// different NSEC, add it
			m.Ns = append(m.Ns, nsec2)
		}
	}
	if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 {
		if _, ok := m.Ns[0].(*dns.SOA); ok {
			m.Ns = append(m.Ns, s.newNSEC(m.Question[0].Name))
		}
	}
}

// sign signs a message m, it takes care of negative or nodata responses as
// well by synthesising NSEC records. It will also cache the signatures, using
// a hash of the signed data as a key.
// We also fake the origin TTL in the signature, because we don't want to
// throw away signatures when services decide to have longer TTL. So we just
// set the origTTL to 60.
func (s *Server) sign(m *dns.Msg, bufsize uint16) {
	now := time.Now().UTC()
	incep := uint32(now.Add(-2 * time.Hour).Unix()) // 2 hours, be sure to catch daylight saving time and such
	expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week

	// TODO(miek): repeating this two times?
	for _, r := range rrSets(m.Answer) {
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Answer = append(m.Answer, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.newRRSIG(incep, expir)
			ttl := getTTLs(r)
			defer setTTLs(r, ttl)
			e := sig1.Sign(s.Privkey, r)
			if e != nil {
				log.Printf("Failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Answer = append(m.Answer, dns.Copy(sig).(*dns.RRSIG))
	}
	for _, r := range rrSets(m.Ns) {
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Ns = append(m.Ns, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.newRRSIG(incep, expir)
			ttl := getTTLs(r)
			defer setTTLs(r, ttl)
			e := sig1.Sign(s.Privkey, r)
			if e != nil {
				log.Printf("Failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Ns = append(m.Ns, dns.Copy(sig).(*dns.RRSIG))
	}
	// TODO(miek): Forget the additional section for now
	if bufsize >= 512 || bufsize <= 4096 {
		m.Truncated = m.Len() > int(bufsize)
	}
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetDo()
	o.SetUDPSize(4096)
	m.Extra = append(m.Extra, o)
	return
}

func (s *Server) newRRSIG(incep, expir uint32) *dns.RRSIG {
	sig := new(dns.RRSIG)
	sig.Hdr.Rrtype = dns.TypeRRSIG
	sig.Hdr.Ttl = origTTL
	sig.OrigTtl = origTTL
	sig.Algorithm = s.Dnskey.Algorithm
	sig.KeyTag = s.KeyTag
	sig.Inception = incep
	sig.Expiration = expir
	sig.SignerName = s.Dnskey.Hdr.Name
	return sig
}

func getTTLs(rrset []dns.RR) []uint32 {
	ttl := make([]uint32, len(rrset))
	for i, r := range rrset {
		ttl[i] = r.Header().Ttl
		r.Header().Ttl = origTTL
	}
	return ttl
}

func setTTLs(rrset []dns.RR, ttl []uint32) {
	for i, r := range rrset {
		r.Header().Ttl = ttl[i]
	}
}

// newNSEC returns the NSEC record need to denial qname, or gives back a NODATA NSEC.
func (s *Server) newNSEC(qname string) *dns.NSEC {
	qlabels := dns.SplitDomainName(qname)
	if len(qlabels) < s.domainLabels {
		// TODO(miek): can not happen...?
	}
	// Strip the last s.domainLabels, return up to 4 before
	// that. Four labels is the maximum qname we can handle.
	ls := len(qlabels) - s.domainLabels
	ls4 := ls - 4
	if ls4 < 0 {
		ls4 = 0
	}
	key := qlabels[ls4:ls]
	prev, next := s.registry.GetNSEC(strings.Join(key, "."))
	nsec := &dns.NSEC{Hdr: dns.RR_Header{Name: prev + s.domain + ".", Rrtype: dns.TypeNSEC, Class: dns.ClassINET, Ttl: 60},
		NextDomain: next + s.domain + "."}
	if prev == "" {
		nsec.TypeBitMap = []uint16{dns.TypeA, dns.TypeSOA, dns.TypeNS, dns.TypeAAAA, dns.TypeRRSIG, dns.TypeNSEC, dns.TypeDNSKEY}
	} else {
		nsec.TypeBitMap = []uint16{dns.TypeA, dns.TypeAAAA, dns.TypeSRV, dns.TypeRRSIG, dns.TypeNSEC}
	}
	return nsec
}

type rrset struct {
	qname  string
	qtype  uint16
}

func rrSets(rrs []dns.RR) map[rrset][]dns.RR {
	m := make(map[rrset][]dns.RR)
	for _, r := range rrs {
		if s, ok := m[rrset{r.Header().Name, r.Header().Rrtype}]; ok {
			s = append(s, r)
			m[rrset{r.Header().Name, r.Header().Rrtype}] = s
		} else {
			s := make([]dns.RR, 1, 3)
			s[0] = r
			m[rrset{r.Header().Name, r.Header().Rrtype}] = s
		}
	}
	if len(m) > 0 {
		return m
	}
	return nil
}

type sigCache struct {
	sync.RWMutex
	m map[string]*dns.RRSIG
}

func newCache() *sigCache {
	c := new(sigCache)
	c.m = make(map[string]*dns.RRSIG)
	return c
}

func (c *sigCache) remove(s string) {
	delete(c.m, s)
}

func (c *sigCache) insert(s string, r *dns.RRSIG) {
	c.Lock()
	defer c.Unlock()
	if _, ok := c.m[s]; !ok {
		c.m[s] = r
	}
}

func (c *sigCache) search(s string) *dns.RRSIG {
	c.RLock()
	defer c.RUnlock()
	if s, ok := c.m[s]; ok {
		// we want to return a copy here, because if we didn't the RRSIG
		// could be removed by another goroutine before the packet containing
		// this signature is send out.
		log.Println("DNS Signature retrieved from cache")
		return dns.Copy(s).(*dns.RRSIG)
	}
	return nil
}

// key uses the name, type and rdata, which is serialized and then hashed as the
// key for the lookup
func (c *sigCache) key(rrs []dns.RR) string {
	h := sha1.New()
	i := []byte(rrs[0].Header().Name)
	i = append(i, packUint16(rrs[0].Header().Rrtype)...)
	for _, r := range rrs {
		switch t := r.(type) { // we only do a few type, serialize these manually
		case *dns.SOA:
			i = append(i, packUint32(t.Serial)...)
			// we only fiddle with the serial so store that
		case *dns.SRV:
			i = append(i, packUint16(t.Priority)...)
			i = append(i, packUint16(t.Weight)...)
			i = append(i, packUint16(t.Weight)...)
			i = append(i, []byte(t.Target)...)
		case *dns.A:
			i = append(i, []byte(t.A)...)
		case *dns.AAAA:
			i = append(i, []byte(t.AAAA)...)
		case *dns.DNSKEY:
			// Need nothing more, the rdata stays the same during a run
		case *dns.NSEC:
			i = append(i, []byte(t.NextDomain)...)
			// bitmap does not differentiate
		default:
			log.Printf("DNS Signature for unhandled type %T seen", t)
		}
	}
	return string(h.Sum(i))
}

// TODO(miek): prolly should use the stdlib ones
func packUint16(i uint16) []byte { return []byte{byte(i >> 8), byte(i)} }
func packUint32(i uint32) []byte { return []byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)} }

// Adapted from singleinflight.go from the original Go Code. Copyright 2013 The Go Authors.
type call struct {
	wg   sync.WaitGroup
	val  *dns.RRSIG
	err  error
	dups int
}

type single struct {
	sync.Mutex
	m map[string]*call
}

func (g *single) Do(key string, fn func() (*dns.RRSIG, error)) (*dns.RRSIG, error, bool) {
	g.Lock()
	if g.m == nil {
		g.m = make(map[string]*call)
	}
	if c, ok := g.m[key]; ok {
		c.dups++
		g.Unlock()
		c.wg.Wait()
		return c.val, c.err, true
	}
	c := new(call)
	c.wg.Add(1)
	g.m[key] = c
	g.Unlock()

	c.val, c.err = fn()
	c.wg.Done()

	g.Lock()
	delete(g.m, key)
	g.Unlock()

	return c.val, c.err, c.dups > 0
}
<commit_msg>TTL stuff not needed<commit_after>// Copyright (c) 2013 Erik St. Martin, Brian Ketelsen. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package server

import (
	"crypto/sha1"
	"github.com/miekg/dns"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

const origTTL uint32 = 60

var cache *sigCache = newCache()
var inflight *single = new(single)

// TODO(miek): allow RRSIG queries and NSEC queries?

// ParseKeyFile read a DNSSEC keyfile as generated by dnssec-keygen or other
// utilities. It add ".key" for the public key and ".private" for the private key.
func ParseKeyFile(file string) (*dns.DNSKEY, dns.PrivateKey, error) {
	f, e := os.Open(file + ".key")
	if e != nil {
		return nil, nil, e
	}
	k, e := dns.ReadRR(f, file+".key")
	if e != nil {
		return nil, nil, e
	}
	f, e = os.Open(file + ".private")
	if e != nil {
		return nil, nil, e
	}
	p, e := k.(*dns.DNSKEY).ReadPrivateKey(f, file+".private")
	if e != nil {
		return nil, nil, e
	}
	return k.(*dns.DNSKEY), p, nil
}

// nsec creates (if needed) NSEC records that are included in the reply.
func (s *Server) nsec(m *dns.Msg) {
	if m.Rcode == dns.RcodeNameError {
		// qname nsec
		nsec1 := s.newNSEC(m.Question[0].Name)
		m.Ns = append(m.Ns, nsec1)
		// wildcard nsec
		idx := dns.Split(m.Question[0].Name)
		wildcard := "*." + m.Question[0].Name[idx[0]:]
		nsec2 := s.newNSEC(wildcard)
		if nsec1.Hdr.Name != nsec2.Hdr.Name || nsec1.NextDomain != nsec2.NextDomain {
			// different NSEC, add it
			m.Ns = append(m.Ns, nsec2)
		}
	}
	if m.Rcode == dns.RcodeSuccess && len(m.Ns) == 1 {
		if _, ok := m.Ns[0].(*dns.SOA); ok {
			m.Ns = append(m.Ns, s.newNSEC(m.Question[0].Name))
		}
	}
}

// sign signs a message m, it takes care of negative or nodata responses as
// well by synthesising NSEC records. It will also cache the signatures, using
// a hash of the signed data as a key.
// We also fake the origin TTL in the signature, because we don't want to
// throw away signatures when services decide to have longer TTL. So we just
// set the origTTL to 60.
func (s *Server) sign(m *dns.Msg, bufsize uint16) {
	now := time.Now().UTC()
	incep := uint32(now.Add(-2 * time.Hour).Unix()) // 2 hours, be sure to catch daylight saving time and such
	expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week

	// TODO(miek): repeating this two times?
	for _, r := range rrSets(m.Answer) {
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Answer = append(m.Answer, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.newRRSIG(incep, expir)
			e := sig1.Sign(s.Privkey, r)
			if e != nil {
				log.Printf("Failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Answer = append(m.Answer, dns.Copy(sig).(*dns.RRSIG))
	}
	for _, r := range rrSets(m.Ns) {
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Ns = append(m.Ns, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.newRRSIG(incep, expir)
			e := sig1.Sign(s.Privkey, r)
			if e != nil {
				log.Printf("Failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Ns = append(m.Ns, dns.Copy(sig).(*dns.RRSIG))
	}
	// TODO(miek): Forget the additional section for now
	if bufsize >= 512 || bufsize <= 4096 {
		m.Truncated = m.Len() > int(bufsize)
	}
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetDo()
	o.SetUDPSize(4096)
	m.Extra = append(m.Extra, o)
	return
}

func (s *Server) newRRSIG(incep, expir uint32) *dns.RRSIG {
	sig := new(dns.RRSIG)
	sig.Hdr.Rrtype = dns.TypeRRSIG
	sig.Hdr.Ttl = origTTL
	sig.OrigTtl = origTTL
	sig.Algorithm = s.Dnskey.Algorithm
	sig.KeyTag = s.KeyTag
	sig.Inception = incep
	sig.Expiration = expir
	sig.SignerName = s.Dnskey.Hdr.Name
	return sig
}

// newNSEC returns the NSEC record need to denial qname, or gives back a NODATA NSEC.
func (s *Server) newNSEC(qname string) *dns.NSEC {
	qlabels := dns.SplitDomainName(qname)
	if len(qlabels) < s.domainLabels {
		// TODO(miek): can not happen...?
	}
	// Strip the last s.domainLabels, return up to 4 before
	// that. Four labels is the maximum qname we can handle.
	ls := len(qlabels) - s.domainLabels
	ls4 := ls - 4
	if ls4 < 0 {
		ls4 = 0
	}
	key := qlabels[ls4:ls]
	prev, next := s.registry.GetNSEC(strings.Join(key, "."))
	nsec := &dns.NSEC{Hdr: dns.RR_Header{Name: prev + s.domain + ".", Rrtype: dns.TypeNSEC, Class: dns.ClassINET, Ttl: 60},
		NextDomain: next + s.domain + "."}
	if prev == "" {
		nsec.TypeBitMap = []uint16{dns.TypeA, dns.TypeSOA, dns.TypeNS, dns.TypeAAAA, dns.TypeRRSIG, dns.TypeNSEC, dns.TypeDNSKEY}
	} else {
		nsec.TypeBitMap = []uint16{dns.TypeA, dns.TypeAAAA, dns.TypeSRV, dns.TypeRRSIG, dns.TypeNSEC}
	}
	return nsec
}

type rrset struct {
	qname  string
	qtype  uint16
}

func rrSets(rrs []dns.RR) map[rrset][]dns.RR {
	m := make(map[rrset][]dns.RR)
	for _, r := range rrs {
		if s, ok := m[rrset{r.Header().Name, r.Header().Rrtype}]; ok {
			s = append(s, r)
			m[rrset{r.Header().Name, r.Header().Rrtype}] = s
		} else {
			s := make([]dns.RR, 1, 3)
			s[0] = r
			m[rrset{r.Header().Name, r.Header().Rrtype}] = s
		}
	}
	if len(m) > 0 {
		return m
	}
	return nil
}

type sigCache struct {
	sync.RWMutex
	m map[string]*dns.RRSIG
}

func newCache() *sigCache {
	c := new(sigCache)
	c.m = make(map[string]*dns.RRSIG)
	return c
}

func (c *sigCache) remove(s string) {
	delete(c.m, s)
}

func (c *sigCache) insert(s string, r *dns.RRSIG) {
	c.Lock()
	defer c.Unlock()
	if _, ok := c.m[s]; !ok {
		c.m[s] = r
	}
}

func (c *sigCache) search(s string) *dns.RRSIG {
	c.RLock()
	defer c.RUnlock()
	if s, ok := c.m[s]; ok {
		// we want to return a copy here, because if we didn't the RRSIG
		// could be removed by another goroutine before the packet containing
		// this signature is send out.
		log.Println("DNS Signature retrieved from cache")
		return dns.Copy(s).(*dns.RRSIG)
	}
	return nil
}

// key uses the name, type and rdata, which is serialized and then hashed as the
// key for the lookup
func (c *sigCache) key(rrs []dns.RR) string {
	h := sha1.New()
	i := []byte(rrs[0].Header().Name)
	i = append(i, packUint16(rrs[0].Header().Rrtype)...)
	for _, r := range rrs {
		switch t := r.(type) { // we only do a few type, serialize these manually
		case *dns.SOA:
			i = append(i, packUint32(t.Serial)...)
			// we only fiddle with the serial so store that
		case *dns.SRV:
			i = append(i, packUint16(t.Priority)...)
			i = append(i, packUint16(t.Weight)...)
			i = append(i, packUint16(t.Weight)...)
			i = append(i, []byte(t.Target)...)
		case *dns.A:
			i = append(i, []byte(t.A)...)
		case *dns.AAAA:
			i = append(i, []byte(t.AAAA)...)
		case *dns.DNSKEY:
			// Need nothing more, the rdata stays the same during a run
		case *dns.NSEC:
			i = append(i, []byte(t.NextDomain)...)
			// bitmap does not differentiate
		default:
			log.Printf("DNS Signature for unhandled type %T seen", t)
		}
	}
	return string(h.Sum(i))
}

// TODO(miek): prolly should use the stdlib ones
func packUint16(i uint16) []byte { return []byte{byte(i >> 8), byte(i)} }
func packUint32(i uint32) []byte { return []byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)} }

// Adapted from singleinflight.go from the original Go Code. Copyright 2013 The Go Authors.
type call struct {
	wg   sync.WaitGroup
	val  *dns.RRSIG
	err  error
	dups int
}

type single struct {
	sync.Mutex
	m map[string]*call
}

func (g *single) Do(key string, fn func() (*dns.RRSIG, error)) (*dns.RRSIG, error, bool) {
	g.Lock()
	if g.m == nil {
		g.m = make(map[string]*call)
	}
	if c, ok := g.m[key]; ok {
		c.dups++
		g.Unlock()
		c.wg.Wait()
		return c.val, c.err, true
	}
	c := new(call)
	c.wg.Add(1)
	g.m[key] = c
	g.Unlock()

	c.val, c.err = fn()
	c.wg.Done()

	g.Lock()
	delete(g.m, key)
	g.Unlock()

	return c.val, c.err, c.dups > 0
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 (
	"errors"
	"fmt"
	"strings"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// PassthruChaincode passes thru invoke and query to another chaincode where
//     called ChaincodeID = function
//     called chaincode's function = args[0]
//     called chaincode's args = args[1:]
type PassthruChaincode struct {
}

//Init func will return error if function has string "error" anywhere
func (p *PassthruChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	if strings.Index(function, "error") >= 0 {
		return nil, errors.New(function)
	}
	return []byte(function), nil
}

//helper
func (p *PassthruChaincode) iq(invoke bool, stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function == "" {
		return nil, errors.New("Chaincode ID not provided")
	}
	chaincodeID := function

	var f string
	var cargs []string
	if len(args) > 0 {
		f = args[0]
		cargs = args[1:]
	}

	if invoke {
		return stub.InvokeChaincode(chaincodeID, f, cargs)
	} else {
		return stub.QueryChaincode(chaincodeID, f, cargs)
	}
}

func (p *PassthruChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	return p.iq(true, stub, function, args)
}

func (p *PassthruChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	return p.iq(false, stub, function, args)
}

func main() {
	err := shim.Start(new(PassthruChaincode))
	if err != nil {
		fmt.Printf("Error starting Passthru chaincode: %s", err)
	}
}
<commit_msg>Set file mode to 644 on non-executable files<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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 (
	"errors"
	"fmt"
	"strings"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// PassthruChaincode passes thru invoke and query to another chaincode where
//     called ChaincodeID = function
//     called chaincode's function = args[0]
//     called chaincode's args = args[1:]
type PassthruChaincode struct {
}

//Init func will return error if function has string "error" anywhere
func (p *PassthruChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	if strings.Index(function, "error") >= 0 {
		return nil, errors.New(function)
	}
	return []byte(function), nil
}

//helper
func (p *PassthruChaincode) iq(invoke bool, stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function == "" {
		return nil, errors.New("Chaincode ID not provided")
	}
	chaincodeID := function

	var f string
	var cargs []string
	if len(args) > 0 {
		f = args[0]
		cargs = args[1:]
	}

	if invoke {
		return stub.InvokeChaincode(chaincodeID, f, cargs)
	} else {
		return stub.QueryChaincode(chaincodeID, f, cargs)
	}
}

func (p *PassthruChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	return p.iq(true, stub, function, args)
}

func (p *PassthruChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	return p.iq(false, stub, function, args)
}

func main() {
	err := shim.Start(new(PassthruChaincode))
	if err != nil {
		fmt.Printf("Error starting Passthru chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>package helios

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

const (
	srvService  = "helios"
	srvProtocol = "http"
)

type Client struct {
	// HTTP client used to talk to Helios.
	client *http.Client

	BaseURL *url.URL

	Hosts *HostsService
}

// NewClient returns a new Helios client for talking to (one of) the
// Helios masters in the provided domain. The Helios masters are discovered
// via SRV lookup. Optionally you may also provide your own http.Client.
func NewClient(domain string, httpClient *http.Client) (*Client, error) {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	_, addrs, err := net.LookupSRV(srvService, srvProtocol, domain)
	if err != nil {
		return nil, err
	}

	baseURL, err := url.Parse(fmt.Sprintf("http://%v:%d/", addrs[0].Target, addrs[0].Port))
	if err != nil {
		return nil, err
	}

	c := &Client{client: httpClient, BaseURL: baseURL}

	c.Hosts = &HostsService{client: c}

	return c, nil
}

func (c *Client) NewRequest(method, path string) (*http.Request, error) {
	p, err := url.Parse(path)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(p)

	req, err := http.NewRequest(method, u.String(), nil)
	if err != nil {
		return nil, err
	}

	return req, nil
}

func (c *Client) Do(req *http.Request, v interface{}) error {
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}

	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	if v != nil {
		return json.Unmarshal(body, v)
	}

	return nil
}
<commit_msg>Support specifying an explicit Helios master URL<commit_after>package helios

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

const (
	srvService  = "helios"
	srvProtocol = "http"
)

type Client struct {
	// HTTP client used to talk to Helios.
	client *http.Client

	BaseURL *url.URL

	Hosts *HostsService
}

// NewClient returns a new Helios client for talking to (one of) the
// Helios masters in the provided domain. The Helios masters are discovered
// via SRV lookup. Optionally you may also provide your own http.Client.
func NewClient(domain string, httpClient *http.Client) (*Client, error) {
	_, addrs, err := net.LookupSRV(srvService, srvProtocol, domain)
	if err != nil {
		return nil, err
	}

	masterURL, err := url.Parse(fmt.Sprintf("http://%v:%d/", addrs[0].Target, addrs[0].Port))
	if err != nil {
		return nil, err
	}

	return NewClientForURL(masterURL, httpClient), nil
}

// NewClientForURL returns a new Helios client for talking to a Helios master at
// an explicitly specified URL. Optionall you may also provide your own http.Client.
// This method is useful when you don't have SRV records setup, or when you want to
// talk to a specific Helios master in a cluster.
func NewClientForURL(masterURL *url.URL, httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	c := &Client{client: httpClient, BaseURL: masterURL}

	c.Hosts = &HostsService{client: c}

	return c
}

func (c *Client) NewRequest(method, path string) (*http.Request, error) {
	p, err := url.Parse(path)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(p)

	req, err := http.NewRequest(method, u.String(), nil)
	if err != nil {
		return nil, err
	}

	return req, nil
}

func (c *Client) Do(req *http.Request, v interface{}) error {
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}

	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	if v != nil {
		return json.Unmarshal(body, v)
	}

	return nil
}
<|endoftext|>