<commit_before>package main

import (
	"flag"
	"image"
	"image/color"
	"image/png"
	"math"
	"math/rand"
	"os"
	"time"
)

func Thresholding(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)
			if greyValue.Y <= threshold {
				greyValue.Y = 0
			} else {
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func RandomDithering(img *image.Gray) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	rand.Seed(time.Now().Unix())

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
			var threshold uint8 = uint8(rand.Intn(256))

			greyValue := (*img).GrayAt(x, y)
			if greyValue.Y <= threshold {
				greyValue.Y = 0
			} else {
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func OrderedDithering(img *image.Gray, matrix [][]float64) (out *image.Gray) {

	n := len(matrix)

	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)

			// to [0, 1]
			var value float64 = float64(greyValue.Y) / 255.0

			matrixValue := matrix[x%n][y%n]

			var resultValue float64

			if value <= matrixValue {
				resultValue = 0.0
			} else {
				resultValue = 1.0
			}

			greyValue.Y = uint8(math.Floor(255 * resultValue))
			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func LineErrorDiffusionDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err int
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		err = 0
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)

			value := int(greyValue.Y)

			if value+err <= int(threshold) {
				err = err + value
				greyValue.Y = 0
			} else {
				err = err + value - 255
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func LineAlternationErrorDiffusionDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err int
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		err = 0
		var new_x int
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
			if y%2 == 1 {
				new_x = rectangle.Max.X - (x - rectangle.Min.X)
			} else {
				new_x = x
			}

			greyValue := (*img).GrayAt(new_x, y)
			value := int(greyValue.Y)

			if value+err <= int(threshold) {
				err = err + value
				greyValue.Y = 0
			} else {
				err = err + value - 255
				greyValue.Y = 255
			}

			out.SetGray(new_x, y, greyValue)
		}
	}
	return
}

func FloydSteinbergDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err uint8
	var errIsPositive bool
	var nX, nY int
	nX = rectangle.Max.X
	nY = rectangle.Max.Y

	for y := rectangle.Min.Y; y < nY; y++ {
		for x := rectangle.Min.X; x < nX; x++ {

			greyValue := (*img).GrayAt(x, y)
			value := greyValue.Y

			if value <= threshold {
				greyValue.Y = 0
				err = value
				errIsPositive = true
				applyFSError(img, x, y, nX-1, nY-1, err, errIsPositive)
			} else {
				greyValue.Y = 255
				err = 255 - value
				errIsPositive = false
				applyFSError(img, x, y, nX-1, nY-1, err, errIsPositive)
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func cropValue(value, err uint8, errIsPositive bool) (new_value uint8) {
	var new_value_int int

	if errIsPositive == true {
		new_value_int = int(value + err)
		if new_value_int > 255 {
			new_value = 255
		} else {
			new_value = uint8(new_value_int)
		}
	} else {
		new_value_int = int(value - err)
		if new_value_int < 0 {
			new_value = 0
		} else {
			new_value = uint8(new_value_int)
		}
	}
	return
}

func applyFSError(img *image.Gray, x, y, maxX, maxY int, err uint8, errIsPositive bool) {
	if x == 0 || x == maxX || y == maxY {
		return
	}

	var value, applied_err, new_value uint8
	var greyValue color.Gray

	greyValue = (*img).GrayAt(x+1, y)
	value = greyValue.Y
	applied_err = uint8(math.Floor(float64(err) * 7.0 / 16.0))
	new_value = cropValue(value, applied_err, errIsPositive)
	greyValue.Y = new_value
	(*img).SetGray(x+1, y, greyValue)

	greyValue = (*img).GrayAt(x+1, y+1)
	value = greyValue.Y
	applied_err = uint8(math.Floor(float64(err) * 1.0 / 16.0))
	new_value = cropValue(value, applied_err, errIsPositive)
	greyValue.Y = new_value
	(*img).SetGray(x+1, y+1, greyValue)

	greyValue = (*img).GrayAt(x, y+1)
	value = greyValue.Y
	applied_err = uint8(math.Floor(float64(err) * 5.0 / 16.0))
	new_value = cropValue(value, applied_err, errIsPositive)
	greyValue.Y = new_value
	(*img).SetGray(x, y+1, greyValue)

	greyValue = (*img).GrayAt(x-1, y+1)
	value = greyValue.Y
	applied_err = uint8(math.Floor(float64(err) * 3.0 / 16.0))
	new_value = cropValue(value, applied_err, errIsPositive)
	greyValue.Y = new_value
	(*img).SetGray(x-1, y+1, greyValue)
}

func MakeOrderedMatrix() (matrix [][]float64) {

	matrix = [][]float64{
		{0, 8, 2, 10},
		{12, 4, 14, 6},
		{3, 11, 1, 9},
		{15, 7, 13, 5}}

	n := 4
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			matrix[i][j] = matrix[i][j] / 16
		}
	}

	return
}

func MakeImageGray(img *image.Image) (out *image.Gray) {

	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	// iterate over all points
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			fullColor := (*img).At(x, y)
			c := color.GrayModel.Convert(fullColor).(color.Gray)
			out.Set(x, y, c)
		}
	}
	return
}

func main() {
	input_img_ptr := flag.String("i", "input.png", "Input PNG image.")
	output_img_ptr := flag.String("o", "output.png", "Output PNG image.")
	approximation_type := flag.String("a", "threshold",
		"Approximation type ['threshold', 'random', 'ordered', 'diffusion', 'floyd'] (default='threshold')")
	flag.Parse()

	// load file
	input_img_raw, _ := os.Open(*input_img_ptr)

	// decode png image
	input_img, _ := png.Decode(input_img_raw)

	// create output file
	output_img_raw, _ := os.Create(*output_img_ptr)

	output_img := MakeImageGray(&input_img)

	switch *approximation_type {
	case "threshold":
		output_img = Thresholding(output_img, 100)
	case "random":
		output_img = RandomDithering(output_img)
	case "ordered":
		output_img = OrderedDithering(output_img, MakeOrderedMatrix())
	case "diffusion":
		output_img = LineErrorDiffusionDithering(output_img, 100)
		// output_img = LineAlternationErrorDiffusionDithering(output_img, 100)
	case "floyd":
		output_img = FloydSteinbergDithering(output_img, 100)
	default:
		output_img = Thresholding(output_img, 100)
	}

	png.Encode(output_img_raw, image.Image(output_img))
}
<commit_msg>Floyd move left and right<commit_after>package main

import (
	"flag"
	"image"
	"image/color"
	"image/png"
	"math"
	"math/rand"
	"os"
	"time"
)

func Thresholding(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)
			if greyValue.Y <= threshold {
				greyValue.Y = 0
			} else {
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func RandomDithering(img *image.Gray) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	rand.Seed(time.Now().Unix())

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
			var threshold uint8 = uint8(rand.Intn(256))

			greyValue := (*img).GrayAt(x, y)
			if greyValue.Y <= threshold {
				greyValue.Y = 0
			} else {
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func OrderedDithering(img *image.Gray, matrix [][]float64) (out *image.Gray) {

	n := len(matrix)

	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)

			// to [0, 1]
			var value float64 = float64(greyValue.Y) / 255.0

			matrixValue := matrix[x%n][y%n]

			var resultValue float64

			if value <= matrixValue {
				resultValue = 0.0
			} else {
				resultValue = 1.0
			}

			greyValue.Y = uint8(math.Floor(255 * resultValue))
			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func LineErrorDiffusionDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err int
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		err = 0
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			greyValue := (*img).GrayAt(x, y)

			value := int(greyValue.Y)

			if value+err <= int(threshold) {
				err = err + value
				greyValue.Y = 0
			} else {
				err = err + value - 255
				greyValue.Y = 255
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func LineAlternationErrorDiffusionDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err int
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		err = 0
		var new_x int
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {
			if y%2 == 1 {
				new_x = rectangle.Max.X - (x - rectangle.Min.X)
			} else {
				new_x = x
			}

			greyValue := (*img).GrayAt(new_x, y)
			value := int(greyValue.Y)

			if value+err <= int(threshold) {
				err = err + value
				greyValue.Y = 0
			} else {
				err = err + value - 255
				greyValue.Y = 255
			}

			out.SetGray(new_x, y, greyValue)
		}
	}
	return
}

func FloydSteinbergDithering(img *image.Gray, threshold uint8) (out *image.Gray) {
	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	var err uint8
	var moveRight, errIsPositive bool
	var nX, nY int
	nX = rectangle.Max.X
	nY = rectangle.Max.Y

	for y := rectangle.Min.Y; y < nY; y++ {

		if y%2 == 0 {
			moveRight = true
		} else {
			moveRight = false
		}

		for x := rectangle.Min.X; x < nX; x++ {

			greyValue := (*img).GrayAt(x, y)
			value := greyValue.Y

			if value <= threshold {
				greyValue.Y = 0
				err = value
				errIsPositive = true
				applyFSError(img, x, y, nX-1, nY-1, err, moveRight, errIsPositive)
			} else {
				greyValue.Y = 255
				err = 255 - value
				errIsPositive = false
				applyFSError(img, x, y, nX-1, nY-1, err, moveRight, errIsPositive)
			}

			out.SetGray(x, y, greyValue)
		}
	}
	return
}

func cropValue(value, err uint8, errIsPositive bool) (new_value uint8) {
	var new_value_int int

	if errIsPositive == true {
		new_value_int = int(value + err)
		if new_value_int > 255 {
			new_value = 255
		} else {
			new_value = uint8(new_value_int)
		}
	} else {
		new_value_int = int(value - err)
		if new_value_int < 0 {
			new_value = 0
		} else {
			new_value = uint8(new_value_int)
		}
	}
	return
}

func applyFSError(img *image.Gray, x, y, maxX, maxY int, err uint8, moveRight, errIsPositive bool) {
	if x == 0 || x == maxX || y == maxY {
		return
	}

	var value, applied_err, new_value uint8
	var greyValue color.Gray
	var coords [4][2]int
	var coefs [4]float64
	var coef float64
	var xx, yy int

	if moveRight == true {
		coords = [4][2]int{{x + 1, y}, {x + 1, y + 1}, {x, y + 1}, {x - 1, y + 1}}
	} else {
		coords = [4][2]int{{x - 1, y}, {x - 1, y + 1}, {x, y + 1}, {x + 1, y + 1}}
	}

	coefs = [4]float64{7.0 / 16.0, 1.0 / 16.0, 5.0 / 16.0, 3.0 / 16.0}

	for i, coord := range coords {
		xx = coord[0]
		yy = coord[1]
		coef = coefs[i]

		greyValue = (*img).GrayAt(xx, yy)
		value = greyValue.Y
		applied_err = uint8(math.Floor(float64(err) * coef))
		new_value = cropValue(value, applied_err, errIsPositive)
		greyValue.Y = new_value
		(*img).SetGray(xx, yy, greyValue)

	}
}

func MakeOrderedMatrix() (matrix [][]float64) {

	matrix = [][]float64{
		{0, 8, 2, 10},
		{12, 4, 14, 6},
		{3, 11, 1, 9},
		{15, 7, 13, 5}}

	n := 4
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			matrix[i][j] = matrix[i][j] / 16
		}
	}

	return
}

func MakeImageGray(img *image.Image) (out *image.Gray) {

	// get image bounds
	rectangle := (*img).Bounds()

	// create output image
	out = image.NewGray(rectangle)

	// iterate over all points
	for y := rectangle.Min.Y; y < rectangle.Max.Y; y++ {
		for x := rectangle.Min.X; x < rectangle.Max.X; x++ {

			fullColor := (*img).At(x, y)
			c := color.GrayModel.Convert(fullColor).(color.Gray)
			out.Set(x, y, c)
		}
	}
	return
}

func main() {
	input_img_ptr := flag.String("i", "input.png", "Input PNG image.")
	output_img_ptr := flag.String("o", "output.png", "Output PNG image.")
	approximation_type := flag.String("a", "threshold",
		"Approximation type ['threshold', 'random', 'ordered', 'diffusion', 'floyd'] (default='threshold')")
	flag.Parse()

	// load file
	input_img_raw, _ := os.Open(*input_img_ptr)

	// decode png image
	input_img, _ := png.Decode(input_img_raw)

	// create output file
	output_img_raw, _ := os.Create(*output_img_ptr)

	output_img := MakeImageGray(&input_img)

	switch *approximation_type {
	case "threshold":
		output_img = Thresholding(output_img, 100)
	case "random":
		output_img = RandomDithering(output_img)
	case "ordered":
		output_img = OrderedDithering(output_img, MakeOrderedMatrix())
	case "diffusion":
		output_img = LineErrorDiffusionDithering(output_img, 100)
		// output_img = LineAlternationErrorDiffusionDithering(output_img, 100)
	case "floyd":
		output_img = FloydSteinbergDithering(output_img, 100)
	default:
		output_img = Thresholding(output_img, 100)
	}

	png.Encode(output_img_raw, image.Image(output_img))
}
<|endoftext|>


<commit_before>package waitress

import (
	"net/http"
)

type ResponseWriter struct {
	http.ResponseWriter
	status int
}

func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
	return &ResponseWriter{w, 200}
}

func (w *ResponseWriter) Write(b []byte) (int, error) {
	w.ResponseWriter.WriteHeader(w.status)
	return w.ResponseWriter.Write(b)
}
<commit_msg>Fix double header issue.<commit_after>package waitress

import (
	"net/http"
)

type ResponseWriter struct {
	http.ResponseWriter
	status  int
	written bool
}

func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
	return &ResponseWriter{w, 200, false}
}

func (w *ResponseWriter) WriteHeader(code int) {
	w.written = true
	w.ResponseWriter.WriteHeader(code)
}

func (w *ResponseWriter) Write(b []byte) (int, error) {
	if !w.written {
		w.WriteHeader(w.status)
	}

	return w.ResponseWriter.Write(b)
}
<|endoftext|>


<commit_before>// Copyright 2015 The http2amqp Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package http2amqp

import (
	"errors"
	"log"
	"strconv"
	"time"

	"encoding/json"

	"github.com/aleasoluciones/goaleasoluciones/safemap"
	"github.com/aleasoluciones/simpleamqp"
)

const (
	amqpReceiveTimeout = 30 * time.Minute
	responsesQueue     = "queries_responses"
	responseTopic      = "queries.response"
)

func NewHTTP2AmqpService(brokerUri, exchange string, timeout time.Duration) *HTTP2amqpService {

	service := HTTP2amqpService{
		amqpConsumer:   simpleamqp.NewAmqpConsumer(brokerUri),
		amqpPublisher:  simpleamqp.NewAmqpPublisher(brokerUri, exchange),
		idsRepository:  NewIdsRepository(),
		exchange:       exchange,
		queryTimeout:   timeout,
		queryResponses: safemap.NewSafeMap(),
	}

	go service.receiveResponses(service.amqpConsumer.Receive(
		service.exchange,
		[]string{responseTopic},
		responsesQueue,
		simpleamqp.QueueOptions{Durable: false, Delete: true, Exclusive: true},
		amqpReceiveTimeout))

	return &service
}

type HTTP2amqpService struct {
	amqpConsumer   simpleamqp.AMQPConsumer
	amqpPublisher  simpleamqp.AMQPPublisher
	idsRepository  IdsRepository
	exchange       string
	queryTimeout   time.Duration
	queryResponses safemap.SafeMap
}

func (service *HTTP2amqpService) receiveResponses(amqpResponses chan simpleamqp.AmqpMessage) {
	var deserialized AmqpResponseMessage
	var value safemap.Value
	var responses chan Response
	var found bool

	for message := range amqpResponses {
		_ = json.Unmarshal([]byte(message.Body), &deserialized)

		value, found = service.queryResponses.Find(deserialized.Id)
		if found {
			responses = value.(chan Response)
			responses <- deserialized.Response
		}
	}
}

func (service *HTTP2amqpService) publishQuery(id string, topic string, request Request) {
	serialized, _ := json.Marshal(AmqpRequestMessage{
		Id:            id,
		Request:       request,
		ResponseTopic: responseTopic,
	})
	log.Println("[queries_service] Query id:", id, "topic:", topic, "request:", request)
	service.amqpPublisher.Publish(topic, serialized)
}

func (service *HTTP2amqpService) Query(topic string, request Request) (Response, error) {
	id := service.idsRepository.Next()
	responses := make(chan Response)
	service.queryResponses.Insert(id, responses)
	defer service.queryResponses.Delete(id)

	timeout := service.queryTimeout
	for k, v := range request.URL.Query() {
		if k == "timeout" {
			milliseconds, _ := strconv.Atoi(v[0])
			timeout = time.Duration(milliseconds) * time.Millisecond
		}
	}
	service.publishQuery(id, topic, request)

	timeoutTicker := time.NewTicker(timeout)
	defer timeoutTicker.Stop()
	afterTimeout := timeoutTicker.C

	select {
	case response := <-responses:
		return response, nil
	case <-afterTimeout:
		log.Println("[queries_service] Timeout for query id:", id)
		return Response{}, errors.New("Timeout")
	}
}
<commit_msg>Renaming (golint sugestion)<commit_after>// Copyright 2015 The http2amqp Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.

package http2amqp

import (
	"errors"
	"log"
	"strconv"
	"time"

	"encoding/json"

	"github.com/aleasoluciones/goaleasoluciones/safemap"
	"github.com/aleasoluciones/simpleamqp"
)

const (
	amqpReceiveTimeout = 30 * time.Minute
	responsesQueue     = "queries_responses"
	responseTopic      = "queries.response"
)

func NewHTTP2AmqpService(brokerURI, exchange string, timeout time.Duration) *HTTP2amqpService {

	service := HTTP2amqpService{
		amqpConsumer:   simpleamqp.NewAmqpConsumer(brokerURI),
		amqpPublisher:  simpleamqp.NewAmqpPublisher(brokerURI, exchange),
		idsRepository:  NewIdsRepository(),
		exchange:       exchange,
		queryTimeout:   timeout,
		queryResponses: safemap.NewSafeMap(),
	}

	go service.receiveResponses(service.amqpConsumer.Receive(
		service.exchange,
		[]string{responseTopic},
		responsesQueue,
		simpleamqp.QueueOptions{Durable: false, Delete: true, Exclusive: true},
		amqpReceiveTimeout))

	return &service
}

type HTTP2amqpService struct {
	amqpConsumer   simpleamqp.AMQPConsumer
	amqpPublisher  simpleamqp.AMQPPublisher
	idsRepository  IdsRepository
	exchange       string
	queryTimeout   time.Duration
	queryResponses safemap.SafeMap
}

func (service *HTTP2amqpService) receiveResponses(amqpResponses chan simpleamqp.AmqpMessage) {
	var deserialized AmqpResponseMessage
	var value safemap.Value
	var responses chan Response
	var found bool

	for message := range amqpResponses {
		_ = json.Unmarshal([]byte(message.Body), &deserialized)

		value, found = service.queryResponses.Find(deserialized.Id)
		if found {
			responses = value.(chan Response)
			responses <- deserialized.Response
		}
	}
}

func (service *HTTP2amqpService) publishQuery(id string, topic string, request Request) {
	serialized, _ := json.Marshal(AmqpRequestMessage{
		Id:            id,
		Request:       request,
		ResponseTopic: responseTopic,
	})
	log.Println("[queries_service] Query id:", id, "topic:", topic, "request:", request)
	service.amqpPublisher.Publish(topic, serialized)
}

func (service *HTTP2amqpService) Query(topic string, request Request) (Response, error) {
	id := service.idsRepository.Next()
	responses := make(chan Response)
	service.queryResponses.Insert(id, responses)
	defer service.queryResponses.Delete(id)

	timeout := service.queryTimeout
	for k, v := range request.URL.Query() {
		if k == "timeout" {
			milliseconds, _ := strconv.Atoi(v[0])
			timeout = time.Duration(milliseconds) * time.Millisecond
		}
	}
	service.publishQuery(id, topic, request)

	timeoutTicker := time.NewTicker(timeout)
	defer timeoutTicker.Stop()
	afterTimeout := timeoutTicker.C

	select {
	case response := <-responses:
		return response, nil
	case <-afterTimeout:
		log.Println("[queries_service] Timeout for query id:", id)
		return Response{}, errors.New("Timeout")
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"time"
)

const (
	maxLength = 4096
	maxAge    = 86400 * 30
)

// These should be set once on app startup

// The key for generating HMAC
var HMACKey []byte

// The key for encrypting content
var SecretKey []byte

// The session name
var SessionName string

// Should we use secure cookies?
var SecureCookies bool

// The session user key
var SessionUserKey string

// The session token key
var SessionTokenKey string

// SessionStore is the interface for a session store (backed by unknown storage)
type SessionStore interface {
	Get(string) string
	Set(string, string)
	Load(request *http.Request) error
	Save(http.ResponseWriter) error
	Clear(http.ResponseWriter)
}

// CookieSessionStore is a Concrete version of SessionStore, which stores the information encrypted with bcrypt in cookies.
type CookieSessionStore struct {
	values map[string]string
}

// init the package
func init() {
	// HttpOnly is on by default
	SecureCookies = false // off by default
	SessionName = "fragmenta_session"
	SessionUserKey = "user_id"
	SessionTokenKey = "authenticity_token"
}

// Session loads or create the current session
func Session(writer http.ResponseWriter, request *http.Request) (SessionStore, error) {

	s, err := SessionGet(request)
	if err != nil {
		// If no session, write it out for the first time (empty)
		fmt.Printf("Error on cookie load: %s\n", err)
		s.Save(writer)
		return s, nil
	}

	return s, nil
}

// SessionGet loads the current session (if any)
func SessionGet(request *http.Request) (SessionStore, error) {

	// Return the current session store from cookie or a new one if none found
	s := &CookieSessionStore{
		values: make(map[string]string, 0),
	}

	if len(HMACKey) == 0 || len(SecretKey) == 0 || len(SessionTokenKey) == 0 {
		return s, errors.New("Authentication secrets not initialised")
	}

	// Check if the session exists and load it
	err := s.Load(request)
	if err != nil {
		return s, err // return blank session if none found
	}

	return s, nil
}

// ClearSession clears the current session cookie
func ClearSession(writer http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   SessionName,
		Value:  "",
		MaxAge: -1,
		Path:   "/",
	}

	http.SetCookie(writer, cookie)
}

// Get a value from the session
func (s *CookieSessionStore) Get(key string) string {
	return s.values[key]
}

// Set a value in the session - NB you must call Save after this if you wish to save
func (s *CookieSessionStore) Set(key string, value string) {
	s.values[key] = value
}

// Load the session from cookie
func (s *CookieSessionStore) Load(request *http.Request) error {

	cookie, err := request.Cookie(SessionName)
	if err != nil {
		return err
	}

	// Read the encrypted values back out into our values in the session
	err = s.Decode(SessionName, HMACKey, SecretKey, cookie.Value, &s.values)
	if err != nil {
		return err
	}

	return nil
}

// Save the session to a cookie
func (s *CookieSessionStore) Save(writer http.ResponseWriter) error {

	encrypted, err := s.Encode(SessionName, s.values, HMACKey, SecretKey)
	if err != nil {
		return err
	}

	cookie := &http.Cookie{
		Name:     SessionName,
		Value:    encrypted,
		HttpOnly: true,
		Secure:   SecureCookies,
		Path:     "/",
		Expires:  time.Now().AddDate(0, 0, 7), // Expires in seven days
	}

	http.SetCookie(writer, cookie)

	return nil
}

// Clear the session values from the cookie
func (s *CookieSessionStore) Clear(writer http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   SessionName,
		Value:  "",
		MaxAge: -1,
		Path:   "/",
	}

	http.SetCookie(writer, cookie)
}

// This code based on Gorilla secure cookie

// Encode a given value in the session cookie
func (s *CookieSessionStore) Encode(name string, value interface{}, hashKey []byte, blockKey []byte) (string, error) {

	if hashKey == nil || blockKey == nil {
		return "", errors.New("Keys not set")
	}

	// Serialize
	b, err := serialize(value)
	if err != nil {
		return "", err
	}

	// Encrypt with AES
	b, err = Encrypt(blockKey, b)
	if err != nil {
		return "", err
	}

	// Encode to base64
	b = encodeBase64(b)

	// Create MAC for "name|date|value". Extra pipe unused.
	now := time.Now().UTC().Unix()
	b = []byte(fmt.Sprintf("%s|%d|%s|", name, now, b))
	mac := CreateMAC(hmac.New(sha256.New, hashKey), b[:len(b)-1])

	// Append mac, remove name
	b = append(b, mac...)[len(name)+1:]

	// Encode to base64 again
	b = encodeBase64(b)

	// Check length when encoded
	if maxLength != 0 && len(b) > maxLength {
		return "", errors.New("Cookie: the value is too long")
	}

	// Done, convert to string and return
	return string(b), nil
}

// Decode the value in the session cookie
func (s *CookieSessionStore) Decode(name string, hashKey []byte, blockKey []byte, value string, dst interface{}) error {

	if hashKey == nil || blockKey == nil {
		return errors.New("Keys not set")
	}

	if maxLength != 0 && len(value) > maxLength {
		return errors.New("cookie value is too long")
	}

	// Decode from base64
	b, err := decodeBase64([]byte(value))
	if err != nil {
		return err
	}
	// Verify MAC - value is "date|value|mac"
	parts := bytes.SplitN(b, []byte("|"), 3)
	if len(parts) != 3 {
		return errors.New("MAC invalid")
	}
	h := hmac.New(sha256.New, hashKey)
	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
	err = VerifyMAC(h, b, parts[2])
	if err != nil {
		return err
	}

	// Verify date ranges
	timestamp, err := strconv.ParseInt(string(parts[0]), 10, 64)
	if err != nil {
		return errors.New("timestamp invalid")
	}
	now := time.Now().UTC().Unix()
	if maxAge != 0 && timestamp < now-maxAge {
		return errors.New("timestamp expired")
	}

	// Decode from base64
	b, err = decodeBase64(parts[1])
	if err != nil {
		return err
	}

	// Derypt with AES
	b, err = Decrypt(blockKey, b)
	if err != nil {
		return err
	}

	// Deserialize
	err = deserialize(b, dst)
	if err != nil {
		return err
	}

	// Done.
	return nil
}

// encodeBase64 encodes a value using base64.
func encodeBase64(value []byte) []byte {
	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
	base64.URLEncoding.Encode(encoded, value)
	return encoded
}

// decodeBase64 decodes a value using base64.
func decodeBase64(value []byte) ([]byte, error) {
	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
	b, err := base64.URLEncoding.Decode(decoded, value)
	if err != nil {
		return nil, err
	}
	return decoded[:b], nil
}

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}
<commit_msg>Removed spurious logging on cookie load<commit_after>package auth

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"time"
)

const (
	maxLength = 4096
	maxAge    = 86400 * 30
)

// These should be set once on app startup

// The key for generating HMAC
var HMACKey []byte

// The key for encrypting content
var SecretKey []byte

// The session name
var SessionName string

// Should we use secure cookies?
var SecureCookies bool

// The session user key
var SessionUserKey string

// The session token key
var SessionTokenKey string

// SessionStore is the interface for a session store (backed by unknown storage)
type SessionStore interface {
	Get(string) string
	Set(string, string)
	Load(request *http.Request) error
	Save(http.ResponseWriter) error
	Clear(http.ResponseWriter)
}

// CookieSessionStore is a Concrete version of SessionStore, which stores the information encrypted with bcrypt in cookies.
type CookieSessionStore struct {
	values map[string]string
}

// init the package
func init() {
	// HttpOnly is on by default
	SecureCookies = false // off by default
	SessionName = "fragmenta_session"
	SessionUserKey = "user_id"
	SessionTokenKey = "authenticity_token"
}

// Session loads or create the current session
func Session(writer http.ResponseWriter, request *http.Request) (SessionStore, error) {

	s, err := SessionGet(request)
	if err != nil {
		// If no session, write it out for the first time (empty)
		//fmt.Printf("Error on cookie load: %s\n", err)
		s.Save(writer)
		return s, nil
	}

	return s, nil
}

// SessionGet loads the current session (if any)
func SessionGet(request *http.Request) (SessionStore, error) {

	// Return the current session store from cookie or a new one if none found
	s := &CookieSessionStore{
		values: make(map[string]string, 0),
	}

	if len(HMACKey) == 0 || len(SecretKey) == 0 || len(SessionTokenKey) == 0 {
		return s, errors.New("Authentication secrets not initialised")
	}

	// Check if the session exists and load it
	err := s.Load(request)
	if err != nil {
		return s, err // return blank session if none found
	}

	return s, nil
}

// ClearSession clears the current session cookie
func ClearSession(writer http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   SessionName,
		Value:  "",
		MaxAge: -1,
		Path:   "/",
	}

	http.SetCookie(writer, cookie)
}

// Get a value from the session
func (s *CookieSessionStore) Get(key string) string {
	return s.values[key]
}

// Set a value in the session - NB you must call Save after this if you wish to save
func (s *CookieSessionStore) Set(key string, value string) {
	s.values[key] = value
}

// Load the session from cookie
func (s *CookieSessionStore) Load(request *http.Request) error {

	cookie, err := request.Cookie(SessionName)
	if err != nil {
		return err
	}

	// Read the encrypted values back out into our values in the session
	err = s.Decode(SessionName, HMACKey, SecretKey, cookie.Value, &s.values)
	if err != nil {
		return err
	}

	return nil
}

// Save the session to a cookie
func (s *CookieSessionStore) Save(writer http.ResponseWriter) error {

	encrypted, err := s.Encode(SessionName, s.values, HMACKey, SecretKey)
	if err != nil {
		return err
	}

	cookie := &http.Cookie{
		Name:     SessionName,
		Value:    encrypted,
		HttpOnly: true,
		Secure:   SecureCookies,
		Path:     "/",
		Expires:  time.Now().AddDate(0, 0, 7), // Expires in seven days
	}

	http.SetCookie(writer, cookie)

	return nil
}

// Clear the session values from the cookie
func (s *CookieSessionStore) Clear(writer http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   SessionName,
		Value:  "",
		MaxAge: -1,
		Path:   "/",
	}

	http.SetCookie(writer, cookie)
}

// This code based on Gorilla secure cookie

// Encode a given value in the session cookie
func (s *CookieSessionStore) Encode(name string, value interface{}, hashKey []byte, blockKey []byte) (string, error) {

	if hashKey == nil || blockKey == nil {
		return "", errors.New("Keys not set")
	}

	// Serialize
	b, err := serialize(value)
	if err != nil {
		return "", err
	}

	// Encrypt with AES
	b, err = Encrypt(blockKey, b)
	if err != nil {
		return "", err
	}

	// Encode to base64
	b = encodeBase64(b)

	// Create MAC for "name|date|value". Extra pipe unused.
	now := time.Now().UTC().Unix()
	b = []byte(fmt.Sprintf("%s|%d|%s|", name, now, b))
	mac := CreateMAC(hmac.New(sha256.New, hashKey), b[:len(b)-1])

	// Append mac, remove name
	b = append(b, mac...)[len(name)+1:]

	// Encode to base64 again
	b = encodeBase64(b)

	// Check length when encoded
	if maxLength != 0 && len(b) > maxLength {
		return "", errors.New("Cookie: the value is too long")
	}

	// Done, convert to string and return
	return string(b), nil
}

// Decode the value in the session cookie
func (s *CookieSessionStore) Decode(name string, hashKey []byte, blockKey []byte, value string, dst interface{}) error {

	if hashKey == nil || blockKey == nil {
		return errors.New("Keys not set")
	}

	if maxLength != 0 && len(value) > maxLength {
		return errors.New("cookie value is too long")
	}

	// Decode from base64
	b, err := decodeBase64([]byte(value))
	if err != nil {
		return err
	}
	// Verify MAC - value is "date|value|mac"
	parts := bytes.SplitN(b, []byte("|"), 3)
	if len(parts) != 3 {
		return errors.New("MAC invalid")
	}
	h := hmac.New(sha256.New, hashKey)
	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
	err = VerifyMAC(h, b, parts[2])
	if err != nil {
		return err
	}

	// Verify date ranges
	timestamp, err := strconv.ParseInt(string(parts[0]), 10, 64)
	if err != nil {
		return errors.New("timestamp invalid")
	}
	now := time.Now().UTC().Unix()
	if maxAge != 0 && timestamp < now-maxAge {
		return errors.New("timestamp expired")
	}

	// Decode from base64
	b, err = decodeBase64(parts[1])
	if err != nil {
		return err
	}

	// Derypt with AES
	b, err = Decrypt(blockKey, b)
	if err != nil {
		return err
	}

	// Deserialize
	err = deserialize(b, dst)
	if err != nil {
		return err
	}

	// Done.
	return nil
}

// encodeBase64 encodes a value using base64.
func encodeBase64(value []byte) []byte {
	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
	base64.URLEncoding.Encode(encoded, value)
	return encoded
}

// decodeBase64 decodes a value using base64.
func decodeBase64(value []byte) ([]byte, error) {
	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
	b, err := base64.URLEncoding.Decode(decoded, value)
	if err != nil {
		return nil, err
	}
	return decoded[:b], nil
}

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package qbit

func NewSession(engine *Engine) *Session {
	return &Session{
		engine: engine,
	}
}

type Session struct {
	engine *Engine
}

func (s *Session) Engine() *Engine {
	return s.engine
}
<commit_msg>add comments to session, fix lint errors<commit_after>package qbit

// NewSession generates a new Session given engine and returns session pointer
func NewSession(engine *Engine) *Session {
	return &Session{
		engine: engine,
	}
}

// Session is the composition of engine connection & orm mappings
type Session struct {
	engine *Engine
}

// Engine returns the current session engine
func (s *Session) Engine() *Engine {
	return s.engine
}
<|endoftext|>


<commit_before>package kocha

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"io"

	"github.com/ugorji/go/codec"
)

// SessionStore is the interface that session store.
type SessionStore interface {
	Save(sess Session) (key string, err error)
	Load(key string) (sess Session, err error)
}

// Session represents a session data store.
type Session map[string]string

// Get gets a value associated with the given key.
// If there is the no value associated with the given key, Get returns "".
func (sess Session) Get(key string) string {
	return sess[key]
}

// Set sets the value associated with the key.
// If replaces the existing value associated with the key.
func (sess Session) Set(key, value string) {
	sess[key] = value
}

// Del deletes the value associated with the key.
func (sess Session) Del(key string) {
	delete(sess, key)
}

// Clear clear the all session data.
func (sess Session) Clear() {
	for k, _ := range sess {
		delete(sess, k)
	}
}

type ErrSession struct {
	msg string
}

func (e ErrSession) Error() string {
	return e.msg
}

func NewErrSession(msg string) error {
	return ErrSession{
		msg: msg,
	}
}

// Implementation of cookie store.
//
// This session store will be a session save to client-side cookie.
// Session cookie for save is encoded, encrypted and signed.
type SessionCookieStore struct {
	// key for the encryption.
	SecretKey string

	// Key for the cookie singing.
	SigningKey string
}

var codecHandler = &codec.MsgpackHandle{}

// Save saves and returns the key of session cookie.
// Actually, key is session cookie data itself.
func (store *SessionCookieStore) Save(sess Session) (key string, err error) {
	buf := bufPool.Get().(*bytes.Buffer)
	defer func() {
		buf.Reset()
		bufPool.Put(buf)
	}()
	if err := codec.NewEncoder(buf, codecHandler).Encode(sess); err != nil {
		return "", err
	}
	encrypted, err := store.encrypt(buf.Bytes())
	if err != nil {
		return "", err
	}
	return store.encode(store.sign(encrypted)), nil
}

// Load returns the session data that extract from cookie value.
// The key is stored session cookie value.
func (store *SessionCookieStore) Load(key string) (sess Session, err error) {
	decoded, err := store.decode(key)
	if err != nil {
		return nil, err
	}
	unsigned, err := store.verify(decoded)
	if err != nil {
		return nil, err
	}
	decrypted, err := store.decrypt(unsigned)
	if err != nil {
		return nil, err
	}
	if err := codec.NewDecoderBytes(decrypted, codecHandler).Decode(&sess); err != nil {
		return nil, err
	}
	return sess, nil
}

// Validate validates SecretKey size.
func (store *SessionCookieStore) Validate() error {
	switch len(store.SecretKey) {
	case 16, 24, 32:
		return nil
	}
	return fmt.Errorf("kocha: session: %T.SecretKey size must be 16, 24 or 32, but %v", *store, len(store.SecretKey))
}

// encrypt returns encrypted data by AES-256-CBC.
func (store *SessionCookieStore) encrypt(buf []byte) ([]byte, error) {
	block, err := aes.NewCipher([]byte(store.SecretKey))
	if err != nil {
		return nil, err
	}
	// padding for CBC
	rem := (aes.BlockSize - len(buf)%aes.BlockSize) % aes.BlockSize
	for i := 0; i < rem; i++ {
		buf = append(buf, byte(rem))
	}
	encrypted := make([]byte, aes.BlockSize+len(buf))
	iv := encrypted[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted[aes.BlockSize:], buf)
	return encrypted, nil
}

// decrypt returns decrypted data from crypted data by AES-256-CBC.
func (store *SessionCookieStore) decrypt(buf []byte) ([]byte, error) {
	block, err := aes.NewCipher([]byte(store.SecretKey))
	if err != nil {
		return nil, err
	}
	iv := buf[:aes.BlockSize]
	decrypted := buf[aes.BlockSize:]
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(decrypted, decrypted)
	return decrypted, nil
}

// encode returns encoded string by Base64 with URLEncoding.
// However, encoded string will stripped the padding character of Base64.
func (store *SessionCookieStore) encode(src []byte) string {
	buf := make([]byte, base64.URLEncoding.EncodedLen(len(src)))
	base64.URLEncoding.Encode(buf, src)
	for {
		if buf[len(buf)-1] != '=' {
			break
		}
		buf = buf[:len(buf)-1]
	}
	return string(buf)
}

// decode returns decoded data from encoded data by Base64 with URLEncoding.
func (store *SessionCookieStore) decode(src string) ([]byte, error) {
	size := len(src)
	rem := (4 - size%4) % 4
	buf := make([]byte, size+rem)
	copy(buf, src)
	for i := 0; i < rem; i++ {
		buf[size+i] = '='
	}
	n, err := base64.URLEncoding.Decode(buf, buf)
	if err != nil {
		return nil, err
	}
	return buf[:n], nil
}

// sign returns signed data.
func (store *SessionCookieStore) sign(src []byte) []byte {
	sign := store.hash(src)
	return append(sign, src...)
}

// verify verify signed data and returns unsigned data if valid.
func (store *SessionCookieStore) verify(src []byte) (unsigned []byte, err error) {
	if len(src) <= sha1.Size {
		return nil, errors.New("kocha: session cookie value too short")
	}
	sign := src[:sha1.Size]
	unsigned = src[sha1.Size:]
	if !hmac.Equal(store.hash(unsigned), sign) {
		return nil, errors.New("kocha: session cookie verification failed")
	}
	return unsigned, nil
}

// hash returns hashed data by HMAC-SHA1.
func (store *SessionCookieStore) hash(src []byte) []byte {
	hash := hmac.New(sha1.New, []byte(store.SigningKey))
	hash.Write(src)
	return hash.Sum(nil)
}
<commit_msg>session: Modify hash function for signature<commit_after>package kocha

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"errors"
	"fmt"
	"io"

	"github.com/ugorji/go/codec"
)

// SessionStore is the interface that session store.
type SessionStore interface {
	Save(sess Session) (key string, err error)
	Load(key string) (sess Session, err error)
}

// Session represents a session data store.
type Session map[string]string

// Get gets a value associated with the given key.
// If there is the no value associated with the given key, Get returns "".
func (sess Session) Get(key string) string {
	return sess[key]
}

// Set sets the value associated with the key.
// If replaces the existing value associated with the key.
func (sess Session) Set(key, value string) {
	sess[key] = value
}

// Del deletes the value associated with the key.
func (sess Session) Del(key string) {
	delete(sess, key)
}

// Clear clear the all session data.
func (sess Session) Clear() {
	for k, _ := range sess {
		delete(sess, k)
	}
}

type ErrSession struct {
	msg string
}

func (e ErrSession) Error() string {
	return e.msg
}

func NewErrSession(msg string) error {
	return ErrSession{
		msg: msg,
	}
}

// Implementation of cookie store.
//
// This session store will be a session save to client-side cookie.
// Session cookie for save is encoded, encrypted and signed.
type SessionCookieStore struct {
	// key for the encryption.
	SecretKey string

	// Key for the cookie singing.
	SigningKey string
}

var codecHandler = &codec.MsgpackHandle{}

// Save saves and returns the key of session cookie.
// Actually, key is session cookie data itself.
func (store *SessionCookieStore) Save(sess Session) (key string, err error) {
	buf := bufPool.Get().(*bytes.Buffer)
	defer func() {
		buf.Reset()
		bufPool.Put(buf)
	}()
	if err := codec.NewEncoder(buf, codecHandler).Encode(sess); err != nil {
		return "", err
	}
	encrypted, err := store.encrypt(buf.Bytes())
	if err != nil {
		return "", err
	}
	return store.encode(store.sign(encrypted)), nil
}

// Load returns the session data that extract from cookie value.
// The key is stored session cookie value.
func (store *SessionCookieStore) Load(key string) (sess Session, err error) {
	decoded, err := store.decode(key)
	if err != nil {
		return nil, err
	}
	unsigned, err := store.verify(decoded)
	if err != nil {
		return nil, err
	}
	decrypted, err := store.decrypt(unsigned)
	if err != nil {
		return nil, err
	}
	if err := codec.NewDecoderBytes(decrypted, codecHandler).Decode(&sess); err != nil {
		return nil, err
	}
	return sess, nil
}

// Validate validates SecretKey size.
func (store *SessionCookieStore) Validate() error {
	switch len(store.SecretKey) {
	case 16, 24, 32:
		return nil
	}
	return fmt.Errorf("kocha: session: %T.SecretKey size must be 16, 24 or 32, but %v", *store, len(store.SecretKey))
}

// encrypt returns encrypted data by AES-256-CBC.
func (store *SessionCookieStore) encrypt(buf []byte) ([]byte, error) {
	block, err := aes.NewCipher([]byte(store.SecretKey))
	if err != nil {
		return nil, err
	}
	// padding for CBC
	rem := (aes.BlockSize - len(buf)%aes.BlockSize) % aes.BlockSize
	for i := 0; i < rem; i++ {
		buf = append(buf, byte(rem))
	}
	encrypted := make([]byte, aes.BlockSize+len(buf))
	iv := encrypted[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted[aes.BlockSize:], buf)
	return encrypted, nil
}

// decrypt returns decrypted data from crypted data by AES-256-CBC.
func (store *SessionCookieStore) decrypt(buf []byte) ([]byte, error) {
	block, err := aes.NewCipher([]byte(store.SecretKey))
	if err != nil {
		return nil, err
	}
	iv := buf[:aes.BlockSize]
	decrypted := buf[aes.BlockSize:]
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(decrypted, decrypted)
	return decrypted, nil
}

// encode returns encoded string by Base64 with URLEncoding.
// However, encoded string will stripped the padding character of Base64.
func (store *SessionCookieStore) encode(src []byte) string {
	buf := make([]byte, base64.URLEncoding.EncodedLen(len(src)))
	base64.URLEncoding.Encode(buf, src)
	for {
		if buf[len(buf)-1] != '=' {
			break
		}
		buf = buf[:len(buf)-1]
	}
	return string(buf)
}

// decode returns decoded data from encoded data by Base64 with URLEncoding.
func (store *SessionCookieStore) decode(src string) ([]byte, error) {
	size := len(src)
	rem := (4 - size%4) % 4
	buf := make([]byte, size+rem)
	copy(buf, src)
	for i := 0; i < rem; i++ {
		buf[size+i] = '='
	}
	n, err := base64.URLEncoding.Decode(buf, buf)
	if err != nil {
		return nil, err
	}
	return buf[:n], nil
}

// sign returns signed data.
func (store *SessionCookieStore) sign(src []byte) []byte {
	sign := store.hash(src)
	return append(sign, src...)
}

// verify verify signed data and returns unsigned data if valid.
func (store *SessionCookieStore) verify(src []byte) (unsigned []byte, err error) {
	if len(src) <= sha512.Size256 {
		return nil, errors.New("kocha: session cookie value too short")
	}
	sign := src[:sha512.Size256]
	unsigned = src[sha512.Size256:]
	if !hmac.Equal(store.hash(unsigned), sign) {
		return nil, errors.New("kocha: session cookie verification failed")
	}
	return unsigned, nil
}

// hash returns hashed data by HMAC-SHA512/256.
func (store *SessionCookieStore) hash(src []byte) []byte {
	hash := hmac.New(sha512.New512_256, []byte(store.SigningKey))
	hash.Write(src)
	return hash.Sum(nil)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
)

var (
	env      string
	etcdHost string
	etcdPort string
	publicIP string
)

func init() {
	flag.StringVar(&env, "env", "dev", "environment {dev|stage|prod}")
	flag.StringVar(&etcdHost, "etcd", "127.0.0.1", "etcd hostname")
	flag.StringVar(&etcdPort, "etcd-port", "4001", "etcd port")
	flag.StringVar(&publicIP, "public-ip", "127.0.0.1", "advertised public IP for this host")
	flag.StringVar(&backendCfg, "backends", "backend.cfg", "haproxy backend config file")
	flag.StringVar(&globalCfg, "global", "haproxy.cfg", "haproxy global config file")
	flag.StringVar(&haproxyPid, "pid", "haproxy.pid", "haproxy pid file")
	flag.StringVar(&haproxy, "haproxy", "haproxy", "haproxy binary")
	flag.Parse()

	haproxyOpts = []string{"-f", globalCfg, "-f", backendCfg, "-p", haproxyPid}
}

// struct for unmarshaling Service (for PORT) and Server locations
type ServiceCfg struct {
	Port         string `json:"PORT"`
	ExternalIP   string `json:"EXTERNAL_IP"`
	ExternalPort string `json:"EXTERNAL_PORT"`
	InternalIP   string `json:"INTERNAL_IP"`
	InternalPort string `json:"INTERNAL_PORT"`
}

// detect Services and Servers by their configuration key names
// return "server" or "service"
func valueType(parts []string) string {
	if len(parts) == 4 && parts[3] == "environment" {
		return "service"
	}
	if len(parts) == 6 && parts[5] == "location" {
		return "server"
	}
	return ""
}

// Walk the entire tree once to get the current config.
// Further updates will come in through a Watch.
func walkTree(n etcd.Node, config *HaproxyCfg) {
	// strip the leading "/" while we split
	parts := strings.Split(strings.TrimLeft(n.Key, "/"), "/")

	switch valueType(parts) {
	case "service":
		config.UpdateListener(n.Key, n.Value)
	case "server":
		config.UpdateServer(n.Key, n.Value)
	}

	for _, next := range n.Nodes {
		walkTree(next, config)
	}
}

func updateConfig(config *HaproxyCfg, resp *etcd.Response) (changed bool) {
	if resp == nil || resp.Node == nil {
		return
	}

	parts := strings.Split(strings.TrimLeft(resp.Node.Key, "/"), "/")
	switch valueType(parts) {
	case "service":
		changed = config.UpdateListener(resp.Node.Key, resp.Node.Value)
	case "server":
		changed = config.UpdateServer(resp.Node.Key, resp.Node.Value)
	}
	return changed
}

func buildConfig(n etcd.Node) *HaproxyCfg {
	config := NewHaproxyCfg()
	walkTree(n, config)
	return config
}

func watchConfig() {
	respCh := make(chan *etcd.Response)
	updateCh := make(chan []byte)
	go haproxyUpdater(updateCh)

	client := etcd.NewClient([]string{fmt.Sprintf("http://%s:%s", etcdHost, etcdPort)})
	client.SyncCluster()

	// drop back here on error, building a new config in case there was a
	// number of changes piled up.
REDO:
	var resp *etcd.Response
	var err error
	for {
		// loop here until we can get a response from the cluster
		resp, err = client.Get(env, false, true)
		if err != nil {
			log.Println(err)
			time.Sleep(10 * time.Second)
		} else {
			break
		}
	}

	lastIndex := resp.EtcdIndex

	config := buildConfig(*resp.Node)
	updateCh <- config.Bytes()

	stopCh := make(chan bool)
	errCh := make(chan error, 1)
	go func() {
		_, err := client.Watch(env, lastIndex+1, true, respCh, stopCh)
		errCh <- err
	}()

	// restart the watch every so often in case our socket is broken
	// pollTicker := time.NewTicker(time.Hour)

	for {
		select {
		case resp := <-respCh:
			lastIndex = resp.EtcdIndex
			if updateConfig(config, resp) {
				log.Println("config changed")
				updateCh <- config.Bytes()
			}
		case err := <-errCh:
			log.Println(err)
			goto REDO
		}
	}
}

func main() {
	if !haproxyRunning() {
		restartHaproxy()
	}

	watchConfig()
}
<commit_msg>Remove some service config registration duplicate code<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/litl/galaxy/registry"
)

var (
	env      string
	etcdHost string
	etcdPort string
	publicIP string
)

func init() {
	flag.StringVar(&env, "env", "dev", "environment {dev|stage|prod}")
	flag.StringVar(&etcdHost, "etcd", "127.0.0.1", "etcd hostname")
	flag.StringVar(&etcdPort, "etcd-port", "4001", "etcd port")
	flag.StringVar(&publicIP, "public-ip", "127.0.0.1", "advertised public IP for this host")
	flag.StringVar(&backendCfg, "backends", "backend.cfg", "haproxy backend config file")
	flag.StringVar(&globalCfg, "global", "haproxy.cfg", "haproxy global config file")
	flag.StringVar(&haproxyPid, "pid", "haproxy.pid", "haproxy pid file")
	flag.StringVar(&haproxy, "haproxy", "haproxy", "haproxy binary")
	flag.Parse()

	haproxyOpts = []string{"-f", globalCfg, "-f", backendCfg, "-p", haproxyPid}
}

// struct for unmarshaling Service (for PORT) and Server locations
type ServiceCfg struct {
	Port string `json:"PORT"`
	registry.ServiceRegistration
}

// detect Services and Servers by their configuration key names
// return "server" or "service"
func valueType(parts []string) string {
	if len(parts) == 4 && parts[3] == "environment" {
		return "service"
	}
	if len(parts) == 6 && parts[5] == "location" {
		return "server"
	}
	return ""
}

// Walk the entire tree once to get the current config.
// Further updates will come in through a Watch.
func walkTree(n etcd.Node, config *HaproxyCfg) {
	// strip the leading "/" while we split
	parts := strings.Split(strings.TrimLeft(n.Key, "/"), "/")

	switch valueType(parts) {
	case "service":
		config.UpdateListener(n.Key, n.Value)
	case "server":
		config.UpdateServer(n.Key, n.Value)
	}

	for _, next := range n.Nodes {
		walkTree(next, config)
	}
}

func updateConfig(config *HaproxyCfg, resp *etcd.Response) (changed bool) {
	if resp == nil || resp.Node == nil {
		return
	}

	parts := strings.Split(strings.TrimLeft(resp.Node.Key, "/"), "/")
	switch valueType(parts) {
	case "service":
		changed = config.UpdateListener(resp.Node.Key, resp.Node.Value)
	case "server":
		changed = config.UpdateServer(resp.Node.Key, resp.Node.Value)
	}
	return changed
}

func buildConfig(n etcd.Node) *HaproxyCfg {
	config := NewHaproxyCfg()
	walkTree(n, config)
	return config
}

func watchConfig() {
	respCh := make(chan *etcd.Response)
	updateCh := make(chan []byte)
	go haproxyUpdater(updateCh)

	client := etcd.NewClient([]string{fmt.Sprintf("http://%s:%s", etcdHost, etcdPort)})
	client.SyncCluster()

	// drop back here on error, building a new config in case there was a
	// number of changes piled up.
REDO:
	var resp *etcd.Response
	var err error
	for {
		// loop here until we can get a response from the cluster
		resp, err = client.Get(env, false, true)
		if err != nil {
			log.Println(err)
			time.Sleep(10 * time.Second)
		} else {
			break
		}
	}

	lastIndex := resp.EtcdIndex

	config := buildConfig(*resp.Node)
	updateCh <- config.Bytes()

	stopCh := make(chan bool)
	errCh := make(chan error, 1)
	go func() {
		_, err := client.Watch(env, lastIndex+1, true, respCh, stopCh)
		errCh <- err
	}()

	// restart the watch every so often in case our socket is broken
	// pollTicker := time.NewTicker(time.Hour)

	for {
		select {
		case resp := <-respCh:
			lastIndex = resp.EtcdIndex
			if updateConfig(config, resp) {
				log.Println("config changed")
				updateCh <- config.Bytes()
			}
		case err := <-errCh:
			log.Println(err)
			goto REDO
		}
	}
}

func main() {
	if !haproxyRunning() {
		restartHaproxy()
	}

	watchConfig()
}
<|endoftext|>


<commit_before>package ciolite

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"github.com/garyburd/go-oauth/oauth"
	"github.com/pkg/errors"
)

// clientRequest defines information that can be used to make a request
type clientRequest struct {
	Method       string
	Path         string
	FormValues   interface{}
	QueryValues  interface{}
	UserID       string
	AccountLabel string
}

// doFormRequest makes the actual request
func (cio CioLite) doFormRequest(request clientRequest, result interface{}) error {

	// Construct the url
	cioURL := cio.Host + request.Path + queryString(request.QueryValues)

	// Construct the body
	bodyValues := formValues(request.FormValues)
	bodyString := bodyValues.Encode()

	// Before-Request Hook Function (logging)
	if cio.PreRequestHook != nil {
		cio.PreRequestHook(request.UserID, request.AccountLabel, request.Method, cioURL, redactBodyValues(bodyValues))
	}

	var (
		statusCode int
		resBody    string
		err        error
	)

	for i := 1; i <= 10; i++ {
		statusCode, resBody, err = cio.createAndSendRequest(request, cioURL, bodyString, bodyValues, result)
		// After-Request Hook Function (logging)
		if cio.PostRequestShouldRetryHook == nil || !cio.PostRequestShouldRetryHook(i, request.UserID, request.AccountLabel, request.Method, cioURL, statusCode, resBody, err) {
			break
		}
		time.Sleep(time.Duration(i*i*i) * time.Second) // Exponential backoff
	}

	return err
}

// createAndSendRequest creates the body io.Reader, the *http.Request, and sends the request, logging the response.
// Returns the status code, the response body, and any error
func (cio CioLite) createAndSendRequest(request clientRequest, cioURL string, bodyString string, bodyValues url.Values, result interface{}) (int, string, error) {

	var bodyReader io.Reader
	if len(bodyString) > 0 {
		bodyReader = bytes.NewReader([]byte(bodyString))
	}

	// Construct the request
	httpReq, err := cio.createRequest(request, cioURL, bodyReader, bodyValues)
	if err != nil {
		return 0, "", err
	}

	// Send the request
	return cio.sendRequest(httpReq, result, cioURL)
}

// createRequest creates the *http.Request object
func (cio CioLite) createRequest(request clientRequest, cioURL string, bodyReader io.Reader, bodyValues url.Values) (*http.Request, error) {
	// Construct the request
	httpReq, err := http.NewRequest(request.Method, cioURL, bodyReader)
	if err != nil {
		return httpReq, RequestError{errors.Wrap(err, "CIO: Failed to form request"), ErrorMetaData{Method: request.Method, URL: cioURL}}
	}

	// oAuth signature
	var client oauth.Client
	client.Credentials = oauth.Credentials{Token: cio.apiKey, Secret: cio.apiSecret}

	// Add headers
	httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	httpReq.Header.Set("Accept", "application/json")
	httpReq.Header.Set("Accept-Charset", "utf-8")
	httpReq.Header.Set("User-Agent", "Golang CIO Library")
	httpReq.Header.Set("Authorization", client.AuthorizationHeader(nil, request.Method, httpReq.URL, bodyValues))

	return httpReq, nil
}

// sendRequest sends the *http.Request, and returns the status code, the response body, and any error
func (cio CioLite) sendRequest(httpReq *http.Request, result interface{}, cioURL string) (int, string, error) {
	// Create the HTTP client
	httpClient := &http.Client{
		Transport: http.DefaultTransport,
		Timeout:   cio.RequestTimeout,
	}

	// Make the request
	res, err := httpClient.Do(httpReq)
	if err != nil {
		return 0, "", RequestError{errors.Wrap(err, "CIO: Failed to make request"), ErrorMetaData{Method: httpReq.Method, URL: cioURL}}
	}

	// Parse the response
	defer func() {
		if closeErr := res.Body.Close(); closeErr != nil && cio.ResponseBodyCloseErrorHook != nil {
			cio.ResponseBodyCloseErrorHook(closeErr) // Logging
		}
	}()

	resBody, err := ioutil.ReadAll(res.Body)
	resBodyString := string(resBody)
	if err != nil {
		return res.StatusCode, resBodyString, RequestError{errors.Wrap(err, "CIO: Could not read response"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}

	// Unmarshal result
	err = json.Unmarshal(resBody, &result)

	// Return own error if Status Code >= 400
	if res.StatusCode >= 400 {
		return res.StatusCode, resBodyString, RequestError{errors.New("CIO: Status Code >= 400"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}

	// Return Unmarshal error (if any) if Status Code is < 400
	if err != nil {
		return res.StatusCode, resBodyString, RequestError{errors.Wrap(err, "CIO: Could not unmarshal payload"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}
	return res.StatusCode, resBodyString, nil
}

// redactBodyValues returns a copy of the body values redacted
func redactBodyValues(bodyValues url.Values) url.Values {

	// Copy url.Values
	redactedValues := url.Values{}
	for k, v := range bodyValues {
		redactedValues[k] = v
	}

	// Redact sensitive information
	if val := redactedValues.Get("password"); len(val) > 0 {
		redactedValues.Set("password", "redacted")
	}
	if val := redactedValues.Get("provider_refresh_token"); len(val) > 0 {
		redactedValues.Set("provider_refresh_token", "redacted")
	}
	if val := redactedValues.Get("provider_consumer_key"); len(val) > 0 {
		redactedValues.Set("provider_consumer_key", "redacted")
	}
	if val := redactedValues.Get("provider_consumer_secret"); len(val) > 0 {
		redactedValues.Set("provider_consumer_secret", "redacted")
	}

	return redactedValues
}
<commit_msg>move sleep and loop exit decisions into the optional post-request-hook<commit_after>package ciolite

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/garyburd/go-oauth/oauth"
	"github.com/pkg/errors"
)

// clientRequest defines information that can be used to make a request
type clientRequest struct {
	Method       string
	Path         string
	FormValues   interface{}
	QueryValues  interface{}
	UserID       string
	AccountLabel string
}

// doFormRequest makes the actual request
func (cio CioLite) doFormRequest(request clientRequest, result interface{}) error {

	// Construct the url
	cioURL := cio.Host + request.Path + queryString(request.QueryValues)

	// Construct the body
	bodyValues := formValues(request.FormValues)
	bodyString := bodyValues.Encode()

	// Before-Request Hook Function (logging)
	if cio.PreRequestHook != nil {
		cio.PreRequestHook(request.UserID, request.AccountLabel, request.Method, cioURL, redactBodyValues(bodyValues))
	}

	var (
		statusCode int
		resBody    string
		err        error
	)

	for i := 1; ; i++ {
		statusCode, resBody, err = cio.createAndSendRequest(request, cioURL, bodyString, bodyValues, result)
		// After-Request Hook Function (logging)
		if cio.PostRequestShouldRetryHook == nil || !cio.PostRequestShouldRetryHook(i, request.UserID, request.AccountLabel, request.Method, cioURL, statusCode, resBody, err) {
			break
		}
	}

	return err
}

// createAndSendRequest creates the body io.Reader, the *http.Request, and sends the request, logging the response.
// Returns the status code, the response body, and any error
func (cio CioLite) createAndSendRequest(request clientRequest, cioURL string, bodyString string, bodyValues url.Values, result interface{}) (int, string, error) {

	var bodyReader io.Reader
	if len(bodyString) > 0 {
		bodyReader = bytes.NewReader([]byte(bodyString))
	}

	// Construct the request
	httpReq, err := cio.createRequest(request, cioURL, bodyReader, bodyValues)
	if err != nil {
		return 0, "", err
	}

	// Send the request
	return cio.sendRequest(httpReq, result, cioURL)
}

// createRequest creates the *http.Request object
func (cio CioLite) createRequest(request clientRequest, cioURL string, bodyReader io.Reader, bodyValues url.Values) (*http.Request, error) {
	// Construct the request
	httpReq, err := http.NewRequest(request.Method, cioURL, bodyReader)
	if err != nil {
		return httpReq, RequestError{errors.Wrap(err, "CIO: Failed to form request"), ErrorMetaData{Method: request.Method, URL: cioURL}}
	}

	// oAuth signature
	var client oauth.Client
	client.Credentials = oauth.Credentials{Token: cio.apiKey, Secret: cio.apiSecret}

	// Add headers
	httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	httpReq.Header.Set("Accept", "application/json")
	httpReq.Header.Set("Accept-Charset", "utf-8")
	httpReq.Header.Set("User-Agent", "Golang CIO Library")
	httpReq.Header.Set("Authorization", client.AuthorizationHeader(nil, request.Method, httpReq.URL, bodyValues))

	return httpReq, nil
}

// sendRequest sends the *http.Request, and returns the status code, the response body, and any error
func (cio CioLite) sendRequest(httpReq *http.Request, result interface{}, cioURL string) (int, string, error) {
	// Create the HTTP client
	httpClient := &http.Client{
		Transport: http.DefaultTransport,
		Timeout:   cio.RequestTimeout,
	}

	// Make the request
	res, err := httpClient.Do(httpReq)
	if err != nil {
		return 0, "", RequestError{errors.Wrap(err, "CIO: Failed to make request"), ErrorMetaData{Method: httpReq.Method, URL: cioURL}}
	}

	// Parse the response
	defer func() {
		if closeErr := res.Body.Close(); closeErr != nil && cio.ResponseBodyCloseErrorHook != nil {
			cio.ResponseBodyCloseErrorHook(closeErr) // Logging
		}
	}()

	resBody, err := ioutil.ReadAll(res.Body)
	resBodyString := string(resBody)
	if err != nil {
		return res.StatusCode, resBodyString, RequestError{errors.Wrap(err, "CIO: Could not read response"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}

	// Unmarshal result
	err = json.Unmarshal(resBody, &result)

	// Return own error if Status Code >= 400
	if res.StatusCode >= 400 {
		return res.StatusCode, resBodyString, RequestError{errors.New("CIO: Status Code >= 400"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}

	// Return Unmarshal error (if any) if Status Code is < 400
	if err != nil {
		return res.StatusCode, resBodyString, RequestError{errors.Wrap(err, "CIO: Could not unmarshal payload"), ErrorMetaData{Method: httpReq.Method, URL: cioURL, StatusCode: res.StatusCode, Payload: resBodyString}}
	}
	return res.StatusCode, resBodyString, nil
}

// redactBodyValues returns a copy of the body values redacted
func redactBodyValues(bodyValues url.Values) url.Values {

	// Copy url.Values
	redactedValues := url.Values{}
	for k, v := range bodyValues {
		redactedValues[k] = v
	}

	// Redact sensitive information
	if val := redactedValues.Get("password"); len(val) > 0 {
		redactedValues.Set("password", "redacted")
	}
	if val := redactedValues.Get("provider_refresh_token"); len(val) > 0 {
		redactedValues.Set("provider_refresh_token", "redacted")
	}
	if val := redactedValues.Get("provider_consumer_key"); len(val) > 0 {
		redactedValues.Set("provider_consumer_key", "redacted")
	}
	if val := redactedValues.Get("provider_consumer_secret"); len(val) > 0 {
		redactedValues.Set("provider_consumer_secret", "redacted")
	}

	return redactedValues
}
<|endoftext|>


<commit_before>package naming

import (
	"strings"
)

// SplitAddressName takes an object name and returns the server address and
// the name relative to the server.
// The name parameter may be a rooted name or a relative name; an empty string
// address is returned for the latter case.
// The returned address may be in endpoint format or host:port format.
func SplitAddressName(name string) (string, string) {
	name = Clean(name)
	if !Rooted(name) {
		return "", name
	}
	name = name[1:]
	if len(name) == 0 {
		return "", ""
	}
	// Could have used regular expressions, but that makes this function
	// 10x slower as per the benchmark.
	if strings.HasPrefix(name, "@") { // /<endpoint>/<suffix>
		addr, suffix := splitIntoTwo(name, "@@/")
		if len(suffix) > 0 { // The trailing "@@" was stripped, restore it
			addr = addr + "@@"
		}
		return addr, suffix
	}
	if strings.HasPrefix(name, "(") { // /(blessing)@host:[port]/suffix
		_, tmp := splitIntoTwo(name, ")@")
		_, suffix := splitIntoTwo(tmp, "/")
		return strings.TrimSuffix(name, "/"+suffix), suffix
	}
	// /host:[port]/suffix
	return splitIntoTwo(name, "/")
}

// JoinAddressName takes an address and a relative name and returns a rooted
// or relative name. If a valid address is supplied then the returned name
// will always be a rooted name (i.e. starting with /), otherwise it may
// be relative. Address should not start with a / and if it does,
// that prefix will be stripped.
func JoinAddressName(address, name string) string {
	address = strings.TrimLeft(address, "/")
	if len(address) == 0 {
		return Clean(name)
	}
	if len(name) == 0 {
		return Clean("/" + address)
	}
	return Clean("/" + address + "/" + name)
}

// Rooted returns true for any name that is considered to be rooted.
// A rooted name is one that starts with a single / followed by
// a non /. / on its own is considered rooted.
func Rooted(name string) bool {
	return strings.HasPrefix(name, "/")
}

// Join takes a variable number of name fragments and concatenates them
// together using '/'.  The returned name is cleaned of multiple adjacent
// '/'s.
func Join(elems ...string) string {
	for len(elems) > 0 && elems[0] == "" {
		elems = elems[1:]
	}
	return Clean(strings.Join(elems, "/"))
}

// TrimSuffix removes the suffix (and any connecting '/') from
// the name.
func TrimSuffix(name, suffix string) string {
	name = Clean(name)
	suffix = Clean(suffix)

	// Easy cases first.
	if name == suffix {
		return ""
	}
	if len(suffix) >= len(name) {
		return name
	}
	// A suffix starting with a slash cannot be a partial match.
	if strings.HasPrefix(suffix, "/") {
		return name
	}
	// At this point suffix is guaranteed not to start with a '/' and
	// suffix is shorter than name.
	if strings.HasSuffix(name, suffix) {
		prefix := strings.TrimSuffix(name, suffix)
		if strings.HasSuffix(prefix, "/") {
			if len(prefix) == 1 {
				return name
			}
			return strings.TrimSuffix(prefix, "/")
		}
	}
	return name
}

// IsReserved returns true if name is a reserved name.
func IsReserved(name string) bool {
	return strings.HasPrefix(name, ReservedNamePrefix)
}

// StripReserved returns the name stripped of the reserved prefix.
func StripReserved(name string) string {
	if IsReserved(name) {
		return name[len(ReservedNamePrefix):]
	}
	return name
}

// Clean reduces multiple adjacent slashes to a single slash.
// It also removes any trailing slash.
func Clean(name string) string {
	// Eradicate duplicate slashes and trailing slashes.  We
	// could use path.Clean but it has other side effects.
	for strings.Contains(name, "//") {
		name = strings.Replace(name, "//", "/", -1)
	}
	if name == "/" {
		return name
	}
	return strings.TrimSuffix(name, "/")
}

func splitIntoTwo(str, separator string) (string, string) {
	elems := strings.SplitN(str, separator, 2)
	if len(elems) == 1 {
		return elems[0], ""
	}
	return elems[0], elems[1]
}
<commit_msg>"v23/naming": Minor change to a comment<commit_after>package naming

import (
	"strings"
)

// SplitAddressName takes an object name and returns the server address and
// the name relative to the server.
// The name parameter may be a rooted name or a relative name; an empty string
// address is returned for the latter case.
// The returned address may be in endpoint format or host:port format.
func SplitAddressName(name string) (string, string) {
	name = Clean(name)
	if !Rooted(name) {
		return "", name
	}
	name = name[1:] // trim the beginning "/"
	if len(name) == 0 {
		return "", ""
	}
	// Could have used regular expressions, but that makes this function
	// 10x slower as per the benchmark.
	if strings.HasPrefix(name, "@") { // <endpoint>/<suffix>
		addr, suffix := splitIntoTwo(name, "@@/")
		if len(suffix) > 0 { // The trailing "@@" was stripped, restore it
			addr = addr + "@@"
		}
		return addr, suffix
	}
	if strings.HasPrefix(name, "(") { // (blessing)@host:[port]/suffix
		_, tmp := splitIntoTwo(name, ")@")
		_, suffix := splitIntoTwo(tmp, "/")
		return strings.TrimSuffix(name, "/"+suffix), suffix
	}
	// host:[port]/suffix
	return splitIntoTwo(name, "/")
}

// JoinAddressName takes an address and a relative name and returns a rooted
// or relative name. If a valid address is supplied then the returned name
// will always be a rooted name (i.e. starting with /), otherwise it may
// be relative. Address should not start with a / and if it does,
// that prefix will be stripped.
func JoinAddressName(address, name string) string {
	address = strings.TrimLeft(address, "/")
	if len(address) == 0 {
		return Clean(name)
	}
	if len(name) == 0 {
		return Clean("/" + address)
	}
	return Clean("/" + address + "/" + name)
}

// Rooted returns true for any name that is considered to be rooted.
// A rooted name is one that starts with a single / followed by
// a non /. / on its own is considered rooted.
func Rooted(name string) bool {
	return strings.HasPrefix(name, "/")
}

// Join takes a variable number of name fragments and concatenates them
// together using '/'.  The returned name is cleaned of multiple adjacent
// '/'s.
func Join(elems ...string) string {
	for len(elems) > 0 && elems[0] == "" {
		elems = elems[1:]
	}
	return Clean(strings.Join(elems, "/"))
}

// TrimSuffix removes the suffix (and any connecting '/') from
// the name.
func TrimSuffix(name, suffix string) string {
	name = Clean(name)
	suffix = Clean(suffix)

	// Easy cases first.
	if name == suffix {
		return ""
	}
	if len(suffix) >= len(name) {
		return name
	}
	// A suffix starting with a slash cannot be a partial match.
	if strings.HasPrefix(suffix, "/") {
		return name
	}
	// At this point suffix is guaranteed not to start with a '/' and
	// suffix is shorter than name.
	if strings.HasSuffix(name, suffix) {
		prefix := strings.TrimSuffix(name, suffix)
		if strings.HasSuffix(prefix, "/") {
			if len(prefix) == 1 {
				return name
			}
			return strings.TrimSuffix(prefix, "/")
		}
	}
	return name
}

// IsReserved returns true if name is a reserved name.
func IsReserved(name string) bool {
	return strings.HasPrefix(name, ReservedNamePrefix)
}

// StripReserved returns the name stripped of the reserved prefix.
func StripReserved(name string) string {
	if IsReserved(name) {
		return name[len(ReservedNamePrefix):]
	}
	return name
}

// Clean reduces multiple adjacent slashes to a single slash.
// It also removes any trailing slash.
func Clean(name string) string {
	// Eradicate duplicate slashes and trailing slashes.  We
	// could use path.Clean but it has other side effects.
	for strings.Contains(name, "//") {
		name = strings.Replace(name, "//", "/", -1)
	}
	if name == "/" {
		return name
	}
	return strings.TrimSuffix(name, "/")
}

func splitIntoTwo(str, separator string) (string, string) {
	elems := strings.SplitN(str, separator, 2)
	if len(elems) == 1 {
		return elems[0], ""
	}
	return elems[0], elems[1]
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"testing"

	"github.com/juju/errgo"

	"github.com/giantswarm/formica/controller"
	"github.com/giantswarm/formica/file-system/fake"
)

type testFileSystemSetup struct {
	FileName    string
	FileContent []byte
	FilePerm    os.FileMode
}

func Test_Common_createRequestWithContent(t *testing.T) {
	testCases := []struct {
		Setup    []testFileSystemSetup
		Input    []string
		Error    error
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that trying to load unit files with invalid input
		// throws an error.
		{
			Setup:    []testFileSystemSetup{},
			Input:    []string{},
			Error:    invalidArgumentsError,
			Expected: controller.Request{},
		},

		// This test ensures that trying to load unit files when no files are in
		// the file system throws an error.
		{
			Setup: []testFileSystemSetup{},
			Input: []string{"dirname"},
			Error: &os.PathError{
				Op:   "open",
				Path: "dirname",
				Err:  errgo.New("no such file or directory"),
			},
			Expected: controller.Request{},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1" results in the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit@.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname@1"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1", "@foo" and "@5" results in the expected
		// controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit@.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname@1", "dirname@foo", "dirname@5"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1", "foo", "5"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		newFileSystem = filesystemfake.NewFileSystem()

		for _, setup := range testCase.Setup {
			err := newFileSystem.WriteFile(setup.FileName, setup.FileContent, setup.FilePerm)
			if err != nil {
				t.Fatalf("FileSystem.WriteFile returned error: %#v", err)
			}
		}

		output, err := createRequestWithContent(testCase.Input)
		fmt.Printf("output: %#v\n", output)
		fmt.Printf("err: %#v\n", err)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatalf("(test case %d) createRequestWithContent was expected to return error: %#v", i+1, testCase.Error)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatalf("(test case %d) sliceIDs of generated output differs from expected sliceIDs", i+1)
		}

		for i, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[i].Name {
				t.Fatalf("output unit name '%s' is not equal to expected unit name '%s'", outputUnit.Name, testCase.Expected.Units[i].Name)
			}
		}
	}
}

func Test_Common_createRequest(t *testing.T) {
	testCases := []struct {
		Input    []string
		Error    error
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Input: []string{"dirname"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that trying to load unit files with invalid input
		// throws an error.
		{
			Input:    []string{},
			Error:    invalidArgumentsError,
			Expected: controller.Request{},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1" results in the expected controller request.
		{
			Input: []string{"dirname@1"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1", "@foo" and "@5" results in the expected
		// controller request.
		{
			Input: []string{"dirname@1", "dirname@foo", "dirname@5"},
			Expected: controller.Request{
				SliceIDs: []string{"1", "foo", "5"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		output, err := createRequest(testCase.Input)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatalf("createRequest was expected to return error: %#v", testCase.Error)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatalf("(test case %d) sliceIDs of generated output differs from expected sliceIDs", i+1)
		}

		for i, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[i].Name {
				t.Fatalf("output unit name '%s' is not equal to expected unit name '%s'", outputUnit.Name, testCase.Expected.Units[i].Name)
			}
		}
	}
}
<commit_msg>create status test - WIP<commit_after>package cli

import (
	"fmt"
	"net"
	"os"
	"testing"

	"github.com/juju/errgo"

	"github.com/giantswarm/formica/controller"
	"github.com/giantswarm/formica/file-system/fake"
	"github.com/giantswarm/formica/fleet"
)

type testFileSystemSetup struct {
	FileName    string
	FileContent []byte
	FilePerm    os.FileMode
}

func Test_Common_createRequestWithContent(t *testing.T) {
	testCases := []struct {
		Setup    []testFileSystemSetup
		Input    []string
		Error    error
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that trying to load unit files with invalid input
		// throws an error.
		{
			Setup:    []testFileSystemSetup{},
			Input:    []string{},
			Error:    invalidArgumentsError,
			Expected: controller.Request{},
		},

		// This test ensures that trying to load unit files when no files are in
		// the file system throws an error.
		{
			Setup: []testFileSystemSetup{},
			Input: []string{"dirname"},
			Error: &os.PathError{
				Op:   "open",
				Path: "dirname",
				Err:  errgo.New("no such file or directory"),
			},
			Expected: controller.Request{},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1" results in the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit@.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname@1"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1", "@foo" and "@5" results in the expected
		// controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit@.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Input: []string{"dirname@1", "dirname@foo", "dirname@5"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1", "foo", "5"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		newFileSystem = filesystemfake.NewFileSystem()

		for _, setup := range testCase.Setup {
			err := newFileSystem.WriteFile(setup.FileName, setup.FileContent, setup.FilePerm)
			if err != nil {
				t.Fatalf("FileSystem.WriteFile returned error: %#v", err)
			}
		}

		output, err := createRequestWithContent(testCase.Input)
		fmt.Printf("output: %#v\n", output)
		fmt.Printf("err: %#v\n", err)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatalf("(test case %d) createRequestWithContent was expected to return error: %#v", i+1, testCase.Error)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatalf("(test case %d) sliceIDs of generated output differs from expected sliceIDs", i+1)
		}

		for i, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[i].Name {
				t.Fatalf("output unit name '%s' is not equal to expected unit name '%s'", outputUnit.Name, testCase.Expected.Units[i].Name)
			}
		}
	}
}

func Test_Common_createRequest(t *testing.T) {
	testCases := []struct {
		Input    []string
		Error    error
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Input: []string{"dirname"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that trying to load unit files with invalid input
		// throws an error.
		{
			Input:    []string{},
			Error:    invalidArgumentsError,
			Expected: controller.Request{},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1" results in the expected controller request.
		{
			Input: []string{"dirname@1"},
			Error: nil,
			Expected: controller.Request{
				SliceIDs: []string{"1"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that loading a single unit from a directory with the
		// slice expression "@1", "@foo" and "@5" results in the expected
		// controller request.
		{
			Input: []string{"dirname@1", "dirname@foo", "dirname@5"},
			Expected: controller.Request{
				SliceIDs: []string{"1", "foo", "5"},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit@.service",
						Content: "some unit content",
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		output, err := createRequest(testCase.Input)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatalf("createRequest was expected to return error: %#v", testCase.Error)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatalf("(test case %d) sliceIDs of generated output differs from expected sliceIDs", i+1)
		}

		for i, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[i].Name {
				t.Fatalf("output unit name '%s' is not equal to expected unit name '%s'", outputUnit.Name, testCase.Expected.Units[i].Name)
			}
		}
	}
}

func TestCreateStatus(t *testing.T) {
	assert := assert.New(t)
	group := "example"
	statusList := controller.UnitStatusList{
		fleet.UnitStatus{
			Current: fleet.unitStateLoaded,
			Desired: fleet.unitStateLoaded,
			Machine: MachineStatus{
				ID: "505e0d7802d7439a924c269b76f34b5f",
				IP: net.IP{
				// TODO add IP here
				},
				SystemdActive: "inactive",
				SystemdSub:    "inactive",
				UnitHash:      "fa59254bb1fac86a10935d9aaf839fe0638fbaba",
			},
			Name:  "example-main",
			Slice: "@1",
		},
	}
	status, err := createStatus(group, statusList)
	assert.Nil(err)
}
<|endoftext|>


<commit_before>package client

import "strings"

// this file contains the various commands you can
// send to the server using an Conn connection

// This could be a lot less ugly with the ability to manipulate
// the symbol table and add methods/functions on the fly
// [ CMD, FMT, FMTARGS ] etc.

// Raw() sends a raw line to the server, should really only be used for
// debugging purposes but may well come in handy.
func (conn *Conn) Raw(rawline string) { conn.out <- rawline }

// Pass() sends a PASS command to the server
func (conn *Conn) Pass(password string) { conn.out <- "PASS "+password }

// Nick() sends a NICK command to the server
func (conn *Conn) Nick(nick string) { conn.out <- "NICK "+nick }

// User() sends a USER command to the server
func (conn *Conn) User(ident, name string) {
	conn.out <- "USER "+ident+" 12 * :"+name
}

// Join() sends a JOIN command to the server
func (conn *Conn) Join(channel string) { conn.out <- "JOIN "+channel }

// Part() sends a PART command to the server with an optional part message
func (conn *Conn) Part(channel string, message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "PART "+channel+msg
}

// Kick() sends a KICK command to remove a nick from a channel
func (conn *Conn) Kick(channel, nick string, message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "KICK "+channel+" "+nick+msg
}

// Quit() sends a QUIT command to the server with an optional quit message
func (conn *Conn) Quit(message ...string) {
	msg := strings.Join(message, " ")
	if msg == "" {
		msg = "GoBye!"
	}
	conn.out <- "QUIT :"+msg
}

// Whois() sends a WHOIS command to the server
func (conn *Conn) Whois(nick string) { conn.out <- "WHOIS "+nick }

//Who() sends a WHO command to the server
func (conn *Conn) Who(nick string) { conn.out <- "WHO "+nick }

// Privmsg() sends a PRIVMSG to the target t
func (conn *Conn) Privmsg(t, msg string) { conn.out <- "PRIVMSG "+t+" :"+msg }

// Notice() sends a NOTICE to the target t
func (conn *Conn) Notice(t, msg string) { conn.out <- "NOTICE "+t+" :"+msg }

// Ctcp() sends a (generic) CTCP message to the target t
// with an optional argument
func (conn *Conn) Ctcp(t, ctcp string, arg ...string) {
	msg := strings.Join(arg, " ")
	if msg != "" {
		msg = " " + msg
	}
	conn.Privmsg(t, "\001"+ctcp+msg+"\001")
}

// CtcpReply() sends a generic CTCP reply to the target t
// with an optional argument
func (conn *Conn) CtcpReply(t, ctcp string, arg ...string) {
	msg := strings.Join(arg, " ")
	if msg != "" {
		msg = " " + msg
	}
	conn.Notice(t, "\001"+ctcp+msg+"\001")
}

// Version() sends a CTCP "VERSION" to the target t
func (conn *Conn) Version(t string) { conn.Ctcp(t, "VERSION") }

// Action() sends a CTCP "ACTION" to the target t
func (conn *Conn) Action(t, msg string) { conn.Ctcp(t, "ACTION", msg) }

// Topic() sends a TOPIC command to the channel
//   Topic(channel) retrieves the current channel topic (see "332" handler)
//   Topic(channel, topic) sets the topic for the channel
func (conn *Conn) Topic(channel string, topic ...string) {
	t := strings.Join(topic, " ")
	if t != "" {
		t = " :" + t
	}
	conn.out <- "TOPIC "+channel+t
}

// Mode() sends a MODE command to the server. This one can get complicated if
// we try to be too clever, so it's deliberately simple:
//   Mode(t) retrieves the user or channel modes for target t
//   Mode(t, "modestring") sets user or channel modes for target t, where...
//     modestring == e.g. "+o <nick>" or "+ntk <key>" or "-is"
// This means you'll need to do your own mode work. It may be linked in with
// the state tracking and ChanMode/NickMode/ChanPrivs objects later...
func (conn *Conn) Mode(t string, modestring ...string) {
	mode := strings.Join(modestring, " ")
	if mode != "" {
		mode = " " + mode
	}
	conn.out <- "MODE "+t+mode
}

// Away() sends an AWAY command to the server
//   Away() resets away status
//   Away(message) sets away with the given message
func (conn *Conn) Away(message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "AWAY"+msg
}

// Invite() sends an INVITE command to the server
func (conn *Conn) Invite(nick, channel string) {
	conn.out <- "INVITE "+nick+" "+channel
}

// Oper() sends an OPER command to the server
func (conn *Conn) Oper(user, pass string) {
	conn.out <- "OPER "+user+" "+pass
}
<commit_msg>Enforce upper-case CTCP commands.<commit_after>package client

import "strings"

// this file contains the various commands you can
// send to the server using an Conn connection

// This could be a lot less ugly with the ability to manipulate
// the symbol table and add methods/functions on the fly
// [ CMD, FMT, FMTARGS ] etc.

// Raw() sends a raw line to the server, should really only be used for
// debugging purposes but may well come in handy.
func (conn *Conn) Raw(rawline string) { conn.out <- rawline }

// Pass() sends a PASS command to the server
func (conn *Conn) Pass(password string) { conn.out <- "PASS "+password }

// Nick() sends a NICK command to the server
func (conn *Conn) Nick(nick string) { conn.out <- "NICK "+nick }

// User() sends a USER command to the server
func (conn *Conn) User(ident, name string) {
	conn.out <- "USER "+ident+" 12 * :"+name
}

// Join() sends a JOIN command to the server
func (conn *Conn) Join(channel string) { conn.out <- "JOIN "+channel }

// Part() sends a PART command to the server with an optional part message
func (conn *Conn) Part(channel string, message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "PART "+channel+msg
}

// Kick() sends a KICK command to remove a nick from a channel
func (conn *Conn) Kick(channel, nick string, message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "KICK "+channel+" "+nick+msg
}

// Quit() sends a QUIT command to the server with an optional quit message
func (conn *Conn) Quit(message ...string) {
	msg := strings.Join(message, " ")
	if msg == "" {
		msg = "GoBye!"
	}
	conn.out <- "QUIT :"+msg
}

// Whois() sends a WHOIS command to the server
func (conn *Conn) Whois(nick string) { conn.out <- "WHOIS "+nick }

//Who() sends a WHO command to the server
func (conn *Conn) Who(nick string) { conn.out <- "WHO "+nick }

// Privmsg() sends a PRIVMSG to the target t
func (conn *Conn) Privmsg(t, msg string) { conn.out <- "PRIVMSG "+t+" :"+msg }

// Notice() sends a NOTICE to the target t
func (conn *Conn) Notice(t, msg string) { conn.out <- "NOTICE "+t+" :"+msg }

// Ctcp() sends a (generic) CTCP message to the target t
// with an optional argument
func (conn *Conn) Ctcp(t, ctcp string, arg ...string) {
	msg := strings.Join(arg, " ")
	if msg != "" {
		msg = " " + msg
	}
	conn.Privmsg(t, "\001"+strings.ToUpper(ctcp)+msg+"\001")
}

// CtcpReply() sends a generic CTCP reply to the target t
// with an optional argument
func (conn *Conn) CtcpReply(t, ctcp string, arg ...string) {
	msg := strings.Join(arg, " ")
	if msg != "" {
		msg = " " + msg
	}
	conn.Notice(t, "\001"+strings.ToUpper(ctcp)+msg+"\001")
}

// Version() sends a CTCP "VERSION" to the target t
func (conn *Conn) Version(t string) { conn.Ctcp(t, "VERSION") }

// Action() sends a CTCP "ACTION" to the target t
func (conn *Conn) Action(t, msg string) { conn.Ctcp(t, "ACTION", msg) }

// Topic() sends a TOPIC command to the channel
//   Topic(channel) retrieves the current channel topic (see "332" handler)
//   Topic(channel, topic) sets the topic for the channel
func (conn *Conn) Topic(channel string, topic ...string) {
	t := strings.Join(topic, " ")
	if t != "" {
		t = " :" + t
	}
	conn.out <- "TOPIC "+channel+t
}

// Mode() sends a MODE command to the server. This one can get complicated if
// we try to be too clever, so it's deliberately simple:
//   Mode(t) retrieves the user or channel modes for target t
//   Mode(t, "modestring") sets user or channel modes for target t, where...
//     modestring == e.g. "+o <nick>" or "+ntk <key>" or "-is"
// This means you'll need to do your own mode work. It may be linked in with
// the state tracking and ChanMode/NickMode/ChanPrivs objects later...
func (conn *Conn) Mode(t string, modestring ...string) {
	mode := strings.Join(modestring, " ")
	if mode != "" {
		mode = " " + mode
	}
	conn.out <- "MODE "+t+mode
}

// Away() sends an AWAY command to the server
//   Away() resets away status
//   Away(message) sets away with the given message
func (conn *Conn) Away(message ...string) {
	msg := strings.Join(message, " ")
	if msg != "" {
		msg = " :" + msg
	}
	conn.out <- "AWAY"+msg
}

// Invite() sends an INVITE command to the server
func (conn *Conn) Invite(nick, channel string) {
	conn.out <- "INVITE "+nick+" "+channel
}

// Oper() sends an OPER command to the server
func (conn *Conn) Oper(user, pass string) {
	conn.out <- "OPER "+user+" "+pass
}
<|endoftext|>