<commit_before>package pqx

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
)

type conn struct {
	conn          net.Conn          // the underlying TCP or unix domain socket connection
	rowDesc       rowDescription    // current query rowDescription
	buf           []byte            // work buffer to avoid constant alloc and dealloc
	pid           int32             // backend pid
	secretKey     int32             // key to use to send a cancel query message to the server
	runtimeParams map[string]string // parameters that have been reported by the server
}

func Connect(options map[string]string) (c *conn, err error) {
	c = new(conn)

	var present bool
	var socket string

	if socket, present = options["socket"]; present {
		c.conn, err = net.Dial("unix", socket)
		if err != nil {
			return nil, err
		}
	}

	c.buf = make([]byte, 1024)
	c.runtimeParams = make(map[string]string)

	// conn, err := net.Dial("tcp", "localhost:5432")

	msg := newStartupMessage()
	msg.options["user"] = "jack"
	c.txStartupMessage(msg)

	var response interface{}
	response, err = c.processMsg()

	for {
		response, err = c.processMsg()
		if err != nil {
			return nil, err
		}
		fmt.Println(response)
		if _, ok := response.(*readyForQuery); ok {
			break
		}
	}

	fmt.Println(c.runtimeParams)

	return c, nil
}

func (c *conn) Close() (err error) {
	buf := c.getBuf(5)
	buf[0] = 'X'
	binary.BigEndian.PutUint32(buf[1:], 4)
	_, err = c.conn.Write(buf)
	return
}

func (c *conn) Query(sql string) (rows []map[string]string, err error) {
	if err = c.sendSimpleQuery(sql); err != nil {
		return
	}

	var response interface{}
	for {
		response, err = c.processMsg()
		if err != nil {
			fmt.Println(err)
			return nil, err
		}
		fmt.Println(response)
		if _, ok := response.(*readyForQuery); ok {
			break
		}
	}

	return nil, err
}

func (c *conn) sendSimpleQuery(sql string) (err error) {
	bufSize := 5 + len(sql) + 1 // message identifier (1), message size (4), null string terminator (1)
	buf := c.getBuf(bufSize)
	buf[0] = 'Q'
	binary.BigEndian.PutUint32(buf[1:5], uint32(bufSize-1))
	copy(buf[5:], sql)
	buf[bufSize-1] = 0

	_, err = c.conn.Write(buf)
	return err
}

func (c *conn) processMsg() (msg interface{}, err error) {
	var t byte
	var body []byte
	t, body, err = c.rxMsg()
	if err != nil {
		return
	}

	return c.parseMsg(t, body)
}

// Processes messages that could potentially occur in multiple contexts
func (c *conn) processCommonMsg(t byte, body []byte) (err error) {
	switch t {
	case 'S':
		c.rxParameterStatus(body)
		return nil
	default:
		return fmt.Errorf("Received unknown message type: %c", t)
	}

	panic("Unreachable")

}

func (c *conn) parseMsg(t byte, body []byte) (msg interface{}, err error) {
	switch t {
	case 'K':
		c.rxBackendKeyData(body)
		return nil, nil
	case 'R':
		return c.rxAuthenticationX(body)
	case 'Z':
		return c.rxReadyForQuery(body), nil
	case 'T':
		return c.rxRowDescription(body)
	case 'D':
		return c.rxDataRow(body)
	case 'C':
		return c.rxCommandComplete(body), nil
	default:
		return nil, c.processCommonMsg(t, body)
	}

	panic("Unreachable")
}

func (c *conn) rxMsg() (t byte, body []byte, err error) {
	var bodySize int32
	t, bodySize, err = c.rxMsgHeader()
	if err != nil {
		return
	}

	body, err = c.rxMsgBody(bodySize)
	return
}

func (c *conn) rxMsgHeader() (t byte, bodySize int32, err error) {
	buf := c.buf[:5]
	if _, err = io.ReadFull(c.conn, buf); err != nil {
		return 0, 0, err
	}

	t = buf[0]
	bodySize = int32(binary.BigEndian.Uint32(buf[1:5])) - 4
	return t, bodySize, nil
}

func (c *conn) rxMsgBody(bodySize int32) (buf []byte, err error) {
	buf = c.getBuf(int(bodySize))
	_, err = io.ReadFull(c.conn, buf)
	return
}

func (c *conn) rxAuthenticationX(buf []byte) (msg interface{}, err error) {
	code := binary.BigEndian.Uint32(buf[:4])
	switch code {
	case 0:
		return &authenticationOk{}, nil
	default:
		return nil, errors.New("Received unknown authentication message")
	}

	panic("Unreachable")
}

func (c *conn) rxParameterStatus(buf []byte) {
	r := newMessageReader(buf)
	key := r.readString()
	value := r.readString()
	c.runtimeParams[key] = value
}

func (c *conn) rxBackendKeyData(buf []byte) {
	r := newMessageReader(buf)
	c.pid = r.readInt32()
	c.secretKey = r.readInt32()
}

func (c *conn) rxReadyForQuery(buf []byte) (msg *readyForQuery) {
	msg = new(readyForQuery)
	msg.txStatus = buf[0]
	return
}

func (c *conn) rxRowDescription(buf []byte) (msg *rowDescription, err error) {
	r := newMessageReader(buf)
	fieldCount := r.readInt16()
	c.rowDesc.fields = make([]fieldDescription, fieldCount)
	for i := int16(0); i < fieldCount; i++ {
		f := &c.rowDesc.fields[i]
		f.name = r.readString()
		f.table = r.readOid()
		f.attributeNumber = r.readInt16()
		f.dataType = r.readOid()
		f.dataTypeSize = r.readInt16()
		f.modifier = r.readInt32()
		f.formatCode = r.readInt16()
	}
	return
}

func (c *conn) rxDataRow(buf []byte) (row map[string]string, err error) {
	r := newMessageReader(buf)
	fieldCount := r.readInt16()

	if fieldCount != int16(len(c.rowDesc.fields)) {
		return nil, fmt.Errorf("Received DataRow with %d fields, expected %d fields", fieldCount, c.rowDesc.fields)
	}

	row = make(map[string]string, fieldCount)
	for i := int16(0); i < fieldCount; i++ {
		// TODO - handle nulls
		size := r.readInt32()
		fmt.Println(size)
		row[c.rowDesc.fields[i].name] = r.readByteString(size)
	}
	return
}

func (c *conn) rxCommandComplete(buf []byte) string {
	r := newMessageReader(buf)
	return r.readString()
}

func (c *conn) txStartupMessage(msg *startupMessage) (err error) {
	_, err = c.conn.Write(msg.Bytes())
	return
}

// Gets a []byte of n length. If possible it will reuse the connection buffer
// otherwise it will allocate a new buffer
func (c *conn) getBuf(n int) (buf []byte) {
	if n <= cap(c.buf) {
		buf = c.buf[:n]
	} else {
		buf = make([]byte, n)
	}
	return
}
<commit_msg>Rename processCommonMsg to processContextFeeMsg<commit_after>package pqx

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
)

type conn struct {
	conn          net.Conn          // the underlying TCP or unix domain socket connection
	rowDesc       rowDescription    // current query rowDescription
	buf           []byte            // work buffer to avoid constant alloc and dealloc
	pid           int32             // backend pid
	secretKey     int32             // key to use to send a cancel query message to the server
	runtimeParams map[string]string // parameters that have been reported by the server
}

func Connect(options map[string]string) (c *conn, err error) {
	c = new(conn)

	var present bool
	var socket string

	if socket, present = options["socket"]; present {
		c.conn, err = net.Dial("unix", socket)
		if err != nil {
			return nil, err
		}
	}

	c.buf = make([]byte, 1024)
	c.runtimeParams = make(map[string]string)

	// conn, err := net.Dial("tcp", "localhost:5432")

	msg := newStartupMessage()
	msg.options["user"] = "jack"
	c.txStartupMessage(msg)

	var response interface{}
	response, err = c.processMsg()

	for {
		response, err = c.processMsg()
		if err != nil {
			return nil, err
		}
		fmt.Println(response)
		if _, ok := response.(*readyForQuery); ok {
			break
		}
	}

	fmt.Println(c.runtimeParams)

	return c, nil
}

func (c *conn) Close() (err error) {
	buf := c.getBuf(5)
	buf[0] = 'X'
	binary.BigEndian.PutUint32(buf[1:], 4)
	_, err = c.conn.Write(buf)
	return
}

func (c *conn) Query(sql string) (rows []map[string]string, err error) {
	if err = c.sendSimpleQuery(sql); err != nil {
		return
	}

	var response interface{}
	for {
		response, err = c.processMsg()
		if err != nil {
			fmt.Println(err)
			return nil, err
		}
		fmt.Println(response)
		if _, ok := response.(*readyForQuery); ok {
			break
		}
	}

	return nil, err
}

func (c *conn) sendSimpleQuery(sql string) (err error) {
	bufSize := 5 + len(sql) + 1 // message identifier (1), message size (4), null string terminator (1)
	buf := c.getBuf(bufSize)
	buf[0] = 'Q'
	binary.BigEndian.PutUint32(buf[1:5], uint32(bufSize-1))
	copy(buf[5:], sql)
	buf[bufSize-1] = 0

	_, err = c.conn.Write(buf)
	return err
}

func (c *conn) processMsg() (msg interface{}, err error) {
	var t byte
	var body []byte
	t, body, err = c.rxMsg()
	if err != nil {
		return
	}

	return c.parseMsg(t, body)
}

// Processes messages that are not exclusive to one context such as authentication sdakl sdafj sda sda sd ds  ds sad sd sa sd sad dsfsd af
func (c *conn) processContextFreeMsg(t byte, body []byte) (err error) {
	switch t {
	case 'S':
		c.rxParameterStatus(body)
		return nil
	default:
		return fmt.Errorf("Received unknown message type: %c", t)
	}

	panic("Unreachable")

}

func (c *conn) parseMsg(t byte, body []byte) (msg interface{}, err error) {
	switch t {
	case 'K':
		c.rxBackendKeyData(body)
		return nil, nil
	case 'R':
		return c.rxAuthenticationX(body)
	case 'Z':
		return c.rxReadyForQuery(body), nil
	case 'T':
		return c.rxRowDescription(body)
	case 'D':
		return c.rxDataRow(body)
	case 'C':
		return c.rxCommandComplete(body), nil
	default:
		return nil, c.processContextFreeMsg(t, body)
	}

	panic("Unreachable")
}

func (c *conn) rxMsg() (t byte, body []byte, err error) {
	var bodySize int32
	t, bodySize, err = c.rxMsgHeader()
	if err != nil {
		return
	}

	body, err = c.rxMsgBody(bodySize)
	return
}

func (c *conn) rxMsgHeader() (t byte, bodySize int32, err error) {
	buf := c.buf[:5]
	if _, err = io.ReadFull(c.conn, buf); err != nil {
		return 0, 0, err
	}

	t = buf[0]
	bodySize = int32(binary.BigEndian.Uint32(buf[1:5])) - 4
	return t, bodySize, nil
}

func (c *conn) rxMsgBody(bodySize int32) (buf []byte, err error) {
	buf = c.getBuf(int(bodySize))
	_, err = io.ReadFull(c.conn, buf)
	return
}

func (c *conn) rxAuthenticationX(buf []byte) (msg interface{}, err error) {
	code := binary.BigEndian.Uint32(buf[:4])
	switch code {
	case 0:
		return &authenticationOk{}, nil
	default:
		return nil, errors.New("Received unknown authentication message")
	}

	panic("Unreachable")
}

func (c *conn) rxParameterStatus(buf []byte) {
	r := newMessageReader(buf)
	key := r.readString()
	value := r.readString()
	c.runtimeParams[key] = value
}

func (c *conn) rxBackendKeyData(buf []byte) {
	r := newMessageReader(buf)
	c.pid = r.readInt32()
	c.secretKey = r.readInt32()
}

func (c *conn) rxReadyForQuery(buf []byte) (msg *readyForQuery) {
	msg = new(readyForQuery)
	msg.txStatus = buf[0]
	return
}

func (c *conn) rxRowDescription(buf []byte) (msg *rowDescription, err error) {
	r := newMessageReader(buf)
	fieldCount := r.readInt16()
	c.rowDesc.fields = make([]fieldDescription, fieldCount)
	for i := int16(0); i < fieldCount; i++ {
		f := &c.rowDesc.fields[i]
		f.name = r.readString()
		f.table = r.readOid()
		f.attributeNumber = r.readInt16()
		f.dataType = r.readOid()
		f.dataTypeSize = r.readInt16()
		f.modifier = r.readInt32()
		f.formatCode = r.readInt16()
	}
	return
}

func (c *conn) rxDataRow(buf []byte) (row map[string]string, err error) {
	r := newMessageReader(buf)
	fieldCount := r.readInt16()

	if fieldCount != int16(len(c.rowDesc.fields)) {
		return nil, fmt.Errorf("Received DataRow with %d fields, expected %d fields", fieldCount, c.rowDesc.fields)
	}

	row = make(map[string]string, fieldCount)
	for i := int16(0); i < fieldCount; i++ {
		// TODO - handle nulls
		size := r.readInt32()
		fmt.Println(size)
		row[c.rowDesc.fields[i].name] = r.readByteString(size)
	}
	return
}

func (c *conn) rxCommandComplete(buf []byte) string {
	r := newMessageReader(buf)
	return r.readString()
}

func (c *conn) txStartupMessage(msg *startupMessage) (err error) {
	_, err = c.conn.Write(msg.Bytes())
	return
}

// Gets a []byte of n length. If possible it will reuse the connection buffer
// otherwise it will allocate a new buffer
func (c *conn) getBuf(n int) (buf []byte) {
	if n <= cap(c.buf) {
		buf = c.buf[:n]
	} else {
		buf = make([]byte, n)
	}
	return
}
<|endoftext|>


<commit_before>package engineio

import (
	"io"
	"net/http"
)

type MessageType int // func(*PayloadEncoder, PacketType) (io.WriteCloser, error)

const (
	MessageText MessageType = iota
	MessageBinary
)

func (t MessageType) String() string {
	switch t {
	case MessageText:
		return "message text"
	case MessageBinary:
		return "message binary"
	}
	return "message known"
}

type Conn interface {
	Request() *http.Request
	Upgraded() bool
	Close() error
	NextReader() (MessageType, io.ReadCloser, error)
	NextWriter(messageType MessageType) (io.WriteCloser, error)
	// SetReadDeadline(t time.Time) error
	// SetWriteDeadline(t time.Time) error
	// ReadJSON(v interface{}) error
	// WriteJSON(v interface{}) error

	transport() Transport
	upgrade(transport Transport)
	onMessage(r *PacketDecoder)
	onClose()
}

type conn struct {
	id         string
	server     *Server
	t          Transport
	upgraded   bool
	isClosed   bool
	readerChan chan *connReader
	req        *http.Request
}

func newSocket(id string, server *Server, transport Transport, req *http.Request) *conn {
	ret := &conn{
		id:         id,
		server:     server,
		t:          transport,
		upgraded:   false,
		isClosed:   false,
		readerChan: make(chan *connReader),
		req:        req,
	}
	transport.SetSocket(ret)

	return ret
}

func (s *conn) Request() *http.Request {
	return s.req
}

func (s *conn) Upgraded() bool {
	return s.upgraded
}

func (s *conn) Close() error {
	if s.isClosed {
		return nil
	}
	s.isClosed = true
	return s.transport().Close()
}

type connReader struct {
	*PacketDecoder
	closeChan chan struct{}
}

func (r *connReader) Close() error {
	if r.closeChan == nil {
		return nil
	}
	r.closeChan <- struct{}{}
	r.closeChan = nil
	return nil
}

func (s *conn) NextReader() (MessageType, io.ReadCloser, error) {
	if s.isClosed {
		return MessageText, nil, io.EOF
	}
	reader := <-s.readerChan
	if reader == nil {
		return MessageText, nil, io.EOF
	}

	return reader.MessageType(), reader, nil
}

func (s *conn) NextWriter(messageType MessageType) (io.WriteCloser, error) {
	if s.isClosed {
		return nil, io.EOF
	}
	return s.transport().NextWriter(messageType, MESSAGE)
}

func (s *conn) transport() Transport {
	return s.t
}

func (s *conn) upgrade(transport Transport) {
	s.t.Upgraded()
	transport.SetSocket(s)
	s.t = transport
	s.upgraded = true
}

func (s *conn) onMessage(decoder *PacketDecoder) {
	if s.isClosed {
		return
	}

	closeChan := make(chan struct{})
	reader := &connReader{
		PacketDecoder: decoder,
		closeChan:     closeChan,
	}
	s.readerChan <- reader
	<-closeChan
	close(closeChan)
}

func (s *conn) onClose() {
	s.isClosed = true
	close(s.readerChan)
	s.server.onClose(s)
}
<commit_msg>add Socket.Id()<commit_after>package engineio

import (
	"io"
	"net/http"
)

type MessageType int // func(*PayloadEncoder, PacketType) (io.WriteCloser, error)

const (
	MessageText MessageType = iota
	MessageBinary
)

func (t MessageType) String() string {
	switch t {
	case MessageText:
		return "message text"
	case MessageBinary:
		return "message binary"
	}
	return "message known"
}

type Conn interface {
	Id() string
	Request() *http.Request
	Upgraded() bool
	Close() error
	NextReader() (MessageType, io.ReadCloser, error)
	NextWriter(messageType MessageType) (io.WriteCloser, error)
	// SetReadDeadline(t time.Time) error
	// SetWriteDeadline(t time.Time) error
	// ReadJSON(v interface{}) error
	// WriteJSON(v interface{}) error

	transport() Transport
	upgrade(transport Transport)
	onMessage(r *PacketDecoder)
	onClose()
}

type conn struct {
	id         string
	server     *Server
	t          Transport
	upgraded   bool
	isClosed   bool
	readerChan chan *connReader
	req        *http.Request
}

func newSocket(id string, server *Server, transport Transport, req *http.Request) *conn {
	ret := &conn{
		id:         id,
		server:     server,
		t:          transport,
		upgraded:   false,
		isClosed:   false,
		readerChan: make(chan *connReader),
		req:        req,
	}
	transport.SetSocket(ret)

	return ret
}

func (s *conn) Id() string {
	return s.id
}

func (s *conn) Request() *http.Request {
	return s.req
}

func (s *conn) Upgraded() bool {
	return s.upgraded
}

func (s *conn) Close() error {
	if s.isClosed {
		return nil
	}
	s.isClosed = true
	return s.transport().Close()
}

type connReader struct {
	*PacketDecoder
	closeChan chan struct{}
}

func (r *connReader) Close() error {
	if r.closeChan == nil {
		return nil
	}
	r.closeChan <- struct{}{}
	r.closeChan = nil
	return nil
}

func (s *conn) NextReader() (MessageType, io.ReadCloser, error) {
	if s.isClosed {
		return MessageText, nil, io.EOF
	}
	reader := <-s.readerChan
	if reader == nil {
		return MessageText, nil, io.EOF
	}

	return reader.MessageType(), reader, nil
}

func (s *conn) NextWriter(messageType MessageType) (io.WriteCloser, error) {
	if s.isClosed {
		return nil, io.EOF
	}
	return s.transport().NextWriter(messageType, MESSAGE)
}

func (s *conn) transport() Transport {
	return s.t
}

func (s *conn) upgrade(transport Transport) {
	s.t.Upgraded()
	transport.SetSocket(s)
	s.t = transport
	s.upgraded = true
}

func (s *conn) onMessage(decoder *PacketDecoder) {
	if s.isClosed {
		return
	}

	closeChan := make(chan struct{})
	reader := &connReader{
		PacketDecoder: decoder,
		closeChan:     closeChan,
	}
	s.readerChan <- reader
	<-closeChan
	close(closeChan)
}

func (s *conn) onClose() {
	s.isClosed = true
	close(s.readerChan)
	s.server.onClose(s)
}
<|endoftext|>


<commit_before>package rhynock

import (
	"github.com/gorilla/websocket"
	"net/http"
	"time"
	"log"
)

// Some defaults for pinging
// Needs to be settable from outside
const (
	writeWait = 10 * time.Second
	pongWait = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10
	maxMessageSize = 512
)

// Conn encapsulates our websocket
type Conn struct {
	// Exported so everything can be messed with from outside
	Ws      *websocket.Conn
	Send    chan []byte
	Dst     BottleDst
	Quit    chan []byte
	wait    chan bool
}

//
// Convenience function so you dont have to use the Send channel
//
func (c *Conn) SendMsg(message string) {
	// Basically just typecasting for convenience
	c.Send <- []byte(message)
}

//
// Convenience function to call the quit channel with a message
//
func (c *Conn) CloseMsg(message string) {
	c.Quit <- []byte(message)
}

//
// This function chews through the power cables
//
func (c *Conn) Close() {
	// Send ourself the quit signal with no message
	c.Quit <- []byte("")
}

//
// Used to write a single message to the client and report any errors
//
func (c *Conn) write(t int, payload []byte) error {
	log.Println("Writing ", payload)
	c.Ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.Ws.WriteMessage(t, payload)
}

//
// Maintains both a reader and a writer, cleans up both if one fails
//
func (c *Conn) read_write() {
	// Ping timer
	ticker := time.NewTicker(pingPeriod)

	// Clean up Connection and Connection resources
	defer func() {
		ticker.Stop()
		close(c.Send)
		close(c.Quit)
		c.Ws.Close()
		close(c.wait) // Unblocks the ConnectionHandler
	}()

	// Config websocket settings
	c.Ws.SetReadLimit(maxMessageSize)
	c.Ws.SetReadDeadline(time.Now().Add(pongWait))
	c.Ws.SetPongHandler(func(string) error {
		// Give each client pongWait seconds after the ping to respond
		c.Ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// Start a reading goroutine
	// The reader will stop when the c.Ws.Close is called at
	// in the defered cleanup function, so we do not manually
	// have to close the reader
	go func() {
		for {
			// This blocks until it reads EOF or an error
			// occurs trying to read, the error can be
			// used to detect when the client closes the Connection
			_, message, err := c.Ws.ReadMessage()
			if err != nil {
				break // If we get an error escape the loop
			}

			// Bottle the message with its sender
			bottle := &Bottle{
				Sender: c,
				Message: message,
			}

			// Send to the destination for processing
			c.Dst.GetBottleChan() <- bottle
		}
		// The reader has been terminated, alert the writer
		c.Close()
	}()

	// Main writing loop
	for {
		select {
		case message, ok := <- c.Send:
			// Our send channel has something in it or the channel closed
			if !ok {
				// Our channel was closed, gracefully close socket Conn
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			// Attempt to write the message to the websocket
			if err := c.write(websocket.TextMessage, message); err != nil {
				// If we get an error we can no longer communcate with client
				// return, no need to send CloseMessage since that would
				// just yield another error
				return
			}

		case <- ticker.C:
			// Ping ticker went off. We need to ping to check for connectivity.
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				// We got an error pinging, return and call defer
				// defer will close the socket which will kill the reader
				return
			}

		case bytes := <- c.Quit:
			// Close connection and send a final message
			c.write(websocket.TextMessage, bytes)
			c.write(websocket.CloseMessage, []byte{})
			return
		}
	}
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r* http.Request) bool { return true }}

//
// Hanlder function to start a websocket connection
//
func ConnectionHandler(w http.ResponseWriter, r *http.Request, dst BottleDst) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// Create new connection object
	c := &Conn{
		Send: make(chan []byte, 256),
		Ws: ws,
		Dst: dst,
		Quit: make(chan []byte),
		wait: make(chan bool),
	}

	// Start read/write loop
	go c.read_write()

	// Alert the destination that a new connection has opened
	dst.ConnectionOpened(c)

	// Make sure connections that are opened will get closed
	defer func() {
		dst.ConnectionClosed(c)
	}()

	<- c.wait
}
<commit_msg>Old way was fine. Channel is buffered<commit_after>package rhynock

import (
	"github.com/gorilla/websocket"
	"net/http"
	"time"
	"log"
)

// Some defaults for pinging
// Needs to be settable from outside
const (
	writeWait = 10 * time.Second
	pongWait = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10
	maxMessageSize = 512
)

// Conn encapsulates our websocket
type Conn struct {
	// Exported so everything can be messed with from outside
	Ws      *websocket.Conn
	Send    chan []byte
	Dst     BottleDst
	Quit    chan []byte
	wait    chan bool
}

//
// Convenience function so you dont have to use the Send channel
//
func (c *Conn) SendMsg(message string) {
	// Basically just typecasting for convenience
	c.Send <- []byte(message)
}

//
// Convenience function to call the quit channel with a message
//
func (c *Conn) CloseMsg(message string) {
	c.Quit <- []byte(message)
}

//
// This function chews through the power cables
//
func (c *Conn) Close() {
	// Send ourself the quit signal with no message
	c.Quit <- []byte("")
}

//
// Used to write a single message to the client and report any errors
//
func (c *Conn) write(t int, payload []byte) error {
	log.Println("Writing ", payload)
	c.Ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.Ws.WriteMessage(t, payload)
}

//
// Maintains both a reader and a writer, cleans up both if one fails
//
func (c *Conn) read_write() {
	// Ping timer
	ticker := time.NewTicker(pingPeriod)

	// Clean up Connection and Connection resources
	defer func() {
		ticker.Stop()
		close(c.Send)
		close(c.Quit)
		c.Ws.Close()
		close(c.wait) // Unblocks the ConnectionHandler
	}()

	// Config websocket settings
	c.Ws.SetReadLimit(maxMessageSize)
	c.Ws.SetReadDeadline(time.Now().Add(pongWait))
	c.Ws.SetPongHandler(func(string) error {
		// Give each client pongWait seconds after the ping to respond
		c.Ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// Start a reading goroutine
	// The reader will stop when the c.Ws.Close is called at
	// in the defered cleanup function, so we do not manually
	// have to close the reader
	go func() {
		for {
			// This blocks until it reads EOF or an error
			// occurs trying to read, the error can be
			// used to detect when the client closes the Connection
			_, message, err := c.Ws.ReadMessage()
			if err != nil {
				break // If we get an error escape the loop
			}

			// Bottle the message with its sender
			bottle := &Bottle{
				Sender: c,
				Message: message,
			}

			// Send to the destination for processing
			c.Dst.GetBottleChan() <- bottle
		}
		// The reader has been terminated, alert the writer
		c.Close()
	}()

	// Main writing loop
	for {
		select {
		case message, ok := <- c.Send:
			// Our send channel has something in it or the channel closed
			if !ok {
				// Our channel was closed, gracefully close socket Conn
				c.write(websocket.CloseMessage, []byte{})
				return
			}
			// Attempt to write the message to the websocket
			if err := c.write(websocket.TextMessage, message); err != nil {
				// If we get an error we can no longer communcate with client
				// return, no need to send CloseMessage since that would
				// just yield another error
				return
			}

		case <- ticker.C:
			// Ping ticker went off. We need to ping to check for connectivity.
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				// We got an error pinging, return and call defer
				// defer will close the socket which will kill the reader
				return
			}

		case bytes := <- c.Quit:
			// Close connection and send a final message
			c.write(websocket.TextMessage, bytes)
			c.write(websocket.CloseMessage, []byte{})
			return
		}
	}
}

var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r* http.Request) bool { return true }}

//
// Hanlder function to start a websocket connection
//
func ConnectionHandler(w http.ResponseWriter, r *http.Request, dst BottleDst) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// Create new connection object
	c := &Conn{
		Send: make(chan []byte, 256),
		Ws: ws,
		Dst: dst,
		Quit: make(chan []byte),
		wait: make(chan bool),
	}

	// Alert the destination that a new connection has opened
	dst.ConnectionOpened(c)

	// Make sure connections that are opened will get closed
	defer func() {
		dst.ConnectionClosed(c)
	}()

	// Start read write loop blocking
	c.read_write()
}
<|endoftext|>


<commit_before>package sftp

import (
	"encoding"
	"io"
	"sync"

	"github.com/pkg/errors"
)

// conn implements a bidirectional channel on which client and server
// connections are multiplexed.
type conn struct {
	io.Reader
	io.WriteCloser
	// this is the same allocator used in packet manager
	alloc      *allocator
	sync.Mutex // used to serialise writes to sendPacket
	// sendPacketTest is needed to replicate packet issues in testing
	sendPacketTest func(w io.Writer, m encoding.BinaryMarshaler) error
}

// the orderID is used in server mode if the allocator is enabled.
// For the client mode just pass 0
func (c *conn) recvPacket(orderID uint32) (uint8, []byte, error) {
	return recvPacket(c, c.alloc, orderID)
}

func (c *conn) sendPacket(m encoding.BinaryMarshaler) error {
	c.Lock()
	defer c.Unlock()
	if c.sendPacketTest != nil {
		return c.sendPacketTest(c, m)
	}
	return sendPacket(c, m)
}

func (c *conn) Close() error {
	c.Lock()
	defer c.Unlock()
	return c.WriteCloser.Close()
}

type clientConn struct {
	conn
	wg sync.WaitGroup

	sync.Mutex                          // protects inflight
	inflight   map[uint32]chan<- result // outstanding requests

	closed chan struct{}
	err    error
}

// Wait blocks until the conn has shut down, and return the error
// causing the shutdown. It can be called concurrently from multiple
// goroutines.
func (c *clientConn) Wait() error {
	<-c.closed
	return c.err
}

// Close closes the SFTP session.
func (c *clientConn) Close() error {
	defer c.wg.Wait()
	return c.conn.Close()
}

func (c *clientConn) loop() {
	defer c.wg.Done()
	err := c.recv()
	if err != nil {
		c.broadcastErr(err)
	}
}

// recv continuously reads from the server and forwards responses to the
// appropriate channel.
func (c *clientConn) recv() error {
	defer c.conn.Close()

	for {
		typ, data, err := c.recvPacket(0)
		if err != nil {
			return err
		}
		sid, _ := unmarshalUint32(data)

		ch, ok := c.getChannel(sid)
		if !ok {
			// This is an unexpected occurrence. Send the error
			// back to all listeners so that they terminate
			// gracefully.
			return errors.Errorf("sid: %v not fond", sid)
		}

		ch <- result{typ: typ, data: data}
	}
}

func (c *clientConn) putChannel(ch chan<- result, sid uint32) bool {
	c.Lock()
	defer c.Unlock()

	select {
	case <-c.closed:
		// already closed with broadcastErr, return error on chan.
		ch <- result{err: errors.New("unexpected server disconnect")}
		return false
	default:
	}

	c.inflight[sid] = ch
	return true
}

func (c *clientConn) getChannel(sid uint32) (chan<- result, bool) {
	c.Lock()
	defer c.Unlock()

	ch, ok := c.inflight[sid]
	delete(c.inflight, sid)

	return ch, ok
}

// result captures the result of receiving the a packet from the server
type result struct {
	typ  byte
	data []byte
	err  error
}

type idmarshaler interface {
	id() uint32
	encoding.BinaryMarshaler
}

func (c *clientConn) sendPacket(ch chan result, p idmarshaler) (byte, []byte, error) {
	if cap(ch) < 1 {
		ch = make(chan result, 1)
	}

	c.dispatchRequest(ch, p)
	s := <-ch
	return s.typ, s.data, s.err
}

// dispatchRequest should ideally only be called by race-detection tests outside of this file,
// where you have to ensure two packets are in flight sequentially after each other.
func (c *clientConn) dispatchRequest(ch chan<- result, p idmarshaler) {
	sid := p.id()

	if !c.putChannel(ch, sid) {
		// already closed.
		return
	}

	if err := c.conn.sendPacket(p); err != nil {
		if ch, ok := c.getChannel(sid); ok {
			ch <- result{err: err}
		}
	}
}

// broadcastErr sends an error to all goroutines waiting for a response.
func (c *clientConn) broadcastErr(err error) {
	c.Lock()
	defer c.Unlock()

	bcastRes := result{err: errors.New("unexpected server disconnect")}
	for sid, ch := range c.inflight {
		ch <- bcastRes

		// Replace the chan in inflight,
		// we have hijacked this chan,
		// and this guarantees always-only-once sending.
		c.inflight[sid] = make(chan<- result, 1)
	}

	c.err = err
	close(c.closed)
}

type serverConn struct {
	conn
}

func (s *serverConn) sendError(p ider, err error) error {
	return s.sendPacket(statusFromError(p, err))
}
<commit_msg>The SSH_FX_CONNECTION_LOST exists precisely for this<commit_after>package sftp

import (
	"encoding"
	"io"
	"sync"

	"github.com/pkg/errors"
)

// conn implements a bidirectional channel on which client and server
// connections are multiplexed.
type conn struct {
	io.Reader
	io.WriteCloser
	// this is the same allocator used in packet manager
	alloc      *allocator
	sync.Mutex // used to serialise writes to sendPacket
	// sendPacketTest is needed to replicate packet issues in testing
	sendPacketTest func(w io.Writer, m encoding.BinaryMarshaler) error
}

// the orderID is used in server mode if the allocator is enabled.
// For the client mode just pass 0
func (c *conn) recvPacket(orderID uint32) (uint8, []byte, error) {
	return recvPacket(c, c.alloc, orderID)
}

func (c *conn) sendPacket(m encoding.BinaryMarshaler) error {
	c.Lock()
	defer c.Unlock()
	if c.sendPacketTest != nil {
		return c.sendPacketTest(c, m)
	}
	return sendPacket(c, m)
}

func (c *conn) Close() error {
	c.Lock()
	defer c.Unlock()
	return c.WriteCloser.Close()
}

type clientConn struct {
	conn
	wg sync.WaitGroup

	sync.Mutex                          // protects inflight
	inflight   map[uint32]chan<- result // outstanding requests

	closed chan struct{}
	err    error
}

// Wait blocks until the conn has shut down, and return the error
// causing the shutdown. It can be called concurrently from multiple
// goroutines.
func (c *clientConn) Wait() error {
	<-c.closed
	return c.err
}

// Close closes the SFTP session.
func (c *clientConn) Close() error {
	defer c.wg.Wait()
	return c.conn.Close()
}

func (c *clientConn) loop() {
	defer c.wg.Done()
	err := c.recv()
	if err != nil {
		c.broadcastErr(err)
	}
}

// recv continuously reads from the server and forwards responses to the
// appropriate channel.
func (c *clientConn) recv() error {
	defer c.conn.Close()

	for {
		typ, data, err := c.recvPacket(0)
		if err != nil {
			return err
		}
		sid, _ := unmarshalUint32(data)

		ch, ok := c.getChannel(sid)
		if !ok {
			// This is an unexpected occurrence. Send the error
			// back to all listeners so that they terminate
			// gracefully.
			return errors.Errorf("sid: %v not fond", sid)
		}

		ch <- result{typ: typ, data: data}
	}
}

func (c *clientConn) putChannel(ch chan<- result, sid uint32) bool {
	c.Lock()
	defer c.Unlock()

	select {
	case <-c.closed:
		// already closed with broadcastErr, return error on chan.
		ch <- result{err: ErrSSHFxConnectionLost}
		return false
	default:
	}

	c.inflight[sid] = ch
	return true
}

func (c *clientConn) getChannel(sid uint32) (chan<- result, bool) {
	c.Lock()
	defer c.Unlock()

	ch, ok := c.inflight[sid]
	delete(c.inflight, sid)

	return ch, ok
}

// result captures the result of receiving the a packet from the server
type result struct {
	typ  byte
	data []byte
	err  error
}

type idmarshaler interface {
	id() uint32
	encoding.BinaryMarshaler
}

func (c *clientConn) sendPacket(ch chan result, p idmarshaler) (byte, []byte, error) {
	if cap(ch) < 1 {
		ch = make(chan result, 1)
	}

	c.dispatchRequest(ch, p)
	s := <-ch
	return s.typ, s.data, s.err
}

// dispatchRequest should ideally only be called by race-detection tests outside of this file,
// where you have to ensure two packets are in flight sequentially after each other.
func (c *clientConn) dispatchRequest(ch chan<- result, p idmarshaler) {
	sid := p.id()

	if !c.putChannel(ch, sid) {
		// already closed.
		return
	}

	if err := c.conn.sendPacket(p); err != nil {
		if ch, ok := c.getChannel(sid); ok {
			ch <- result{err: err}
		}
	}
}

// broadcastErr sends an error to all goroutines waiting for a response.
func (c *clientConn) broadcastErr(err error) {
	c.Lock()
	defer c.Unlock()

	bcastRes := result{err: ErrSSHFxConnectionLost}
	for sid, ch := range c.inflight {
		ch <- bcastRes

		// Replace the chan in inflight,
		// we have hijacked this chan,
		// and this guarantees always-only-once sending.
		c.inflight[sid] = make(chan<- result, 1)
	}

	c.err = err
	close(c.closed)
}

type serverConn struct {
	conn
}

func (s *serverConn) sendError(p ider, err error) error {
	return s.sendPacket(statusFromError(p, err))
}
<|endoftext|>


<commit_before>package erede

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/http"
	"text/template"
)

var (
	User        string
	Password    string
	Environment = 1
	Verbose     = false
)

const (
	OrderTypeCredit = "credit"
	URLDEV          = "https://scommerce.redecard.com.br/Beta/wsTransaction"
	URLPROD         = "https://ecommerce.userede.com.br/Transaction/wsTransaction"
)

const (
	DevelopmentEnv = 0
	ProductionEnv  = 1
)

func SetProductionEnv() {
	Environment = ProductionEnv
}

func SetDevelopmentEnv() {
	Environment = DevelopmentEnv
}

func URL() string {
	if Environment == ProductionEnv {
		return URLPROD
	}
	return URLDEV
}

type Transaction struct {
	CardNumber          string
	CardExpiryDate      CardExpDate
	CVC2                string
	OrderID             string
	OrderMoneyAmount    float64
	OrderType           string
	Installments        int
	DeliveryDetails     TransactionDelivery
	BillingAddress      TransactionAddress
	Products            []TransactionProduct
	Buyer               TransactionBuyer
	skipRisk            bool
	skipAddressDetails  bool
	skipShippingDetails bool
	skipBillingDetails  bool
	skipOrderDetails    bool
	skipLineItems       bool
	location            string
}

type CardExpDate struct {
	Month string
	Year  string
}

type TransactionBuyer struct {
	BuyerID string
	Email   string
	IPv4    string
	Phone1  string
	Phone2  string
	DOB     TransactionDate
	RG      string
	Name    string
	Surname string
	Address TransactionAddress
}

type TransactionDate struct {
	Year  string
	Month string
	Day   string
}

type TransactionAddress struct {
	Line1   string
	Line2   string
	City    string
	State   string
	Country string
	ZIP     string
}

type TransactionDelivery struct {
	Date         TransactionDate
	DeliveryKind string // SEDEX 10
	Address      TransactionAddress
}

type TransactionProduct struct {
	ProductId   string
	Description string
	Category    string
	Quantity    int
	MoneyAmount float64
	Risk        string // High | Low
}

/* ~~~~~ Transaction ~~~~~ */

func (t *Transaction) AddProduct(id, description, category string, quantity int, moneyAmount float64) *TransactionProduct {
	t.skipLineItems = false
	i0 := TransactionProduct{id, description, category, quantity, moneyAmount, "low"}
	t.Products = append(t.Products, i0)
	return &t.Products[len(t.Products)-1]
}

func (t *Transaction) SetVendorLocation(loc string) *Transaction {
	t.location = loc
	return t
}

func (t *Transaction) SetSkipAddressDetails(val bool) *Transaction {
	t.skipAddressDetails = val
	return t
}

func (t *Transaction) SetSkipRisk(val bool) *Transaction {
	t.skipRisk = val
	return t
}

func (t *Transaction) SetSkipShippingDetails(val bool) *Transaction {
	t.skipShippingDetails = val
	return t
}

func (t *Transaction) SetSkipBillingDetails(val bool) *Transaction {
	t.skipBillingDetails = val
	return t
}

func FulFillTxn(gatewayReference, authcode string) string {
	vals := make(map[string]interface{}, 0)
	vals["User"] = User
	vals["Password"] = Password
	vals["GatewayReference"] = gatewayReference
	vals["AuthCode"] = authcode

	tpl := template.New("xml")
	tpl = template.Must(tpl.Parse(tpl_fulfill))
	var buffer bytes.Buffer
	tpl.Execute(&buffer, vals)
	log.Println(URL())
	log.Println(buffer.String())
	resp, err := http.Post(URL(), "application/xml", &buffer)
	if err != nil {
		return err.Error()
		//return nil, err
	}
	//tr := &TransactionResponse{}
	buffer.Truncate(0)
	defer resp.Body.Close()
	io.Copy(&buffer, resp.Body)
	if Verbose {
		log.Println(buffer.String())
	}

	return buffer.String()
	//err = xml.Unmarshal(buffer.Bytes(), tr)
	//return tr, err
}

func (t *Transaction) GetXML() *bytes.Buffer {
	if t.skipLineItems && t.skipBillingDetails {
		t.skipOrderDetails = true
	} else {
		t.skipOrderDetails = false
	}
	vals := make(map[string]interface{}, 0)
	vals["User"] = User
	vals["Password"] = Password
	// <Transaction>
	vals["CC"] = t.CardNumber
	vals["ExpiryDate"] = t.CardExpiryDate.String()
	vals["CCVC2"] = t.CVC2
	vals["TipoTransacao"] = t.OrderType
	vals["Method"] = "auth" // pre ou auth // mostra se é pré autorização ou não!
	vals["MReference"] = t.OrderID
	vals["Amount"] = fmt.Sprintf("%v", t.OrderMoneyAmount)
	//
	vals["VMLocation"] = t.location
	vals["VChannel"] = "W" // ???
	vals["VuserId"] = t.Buyer.BuyerID
	vals["Vmail"] = t.Buyer.Email
	vals["VIP"] = t.Buyer.IPv4
	vals["PFone1"] = t.Buyer.Phone1
	vals["PFone2"] = t.Buyer.Phone2
	vals["PDateBirth"] = t.Buyer.DOB.String()
	vals["PIDNumber"] = t.Buyer.RG
	vals["PIDType"] = "2" // RG ?
	vals["PFName"] = t.Buyer.Name
	vals["PLName"] = t.Buyer.Surname
	//
	vals["Address1"] = t.Buyer.Address.Line1
	vals["Address2"] = t.Buyer.Address.Line2
	vals["AddressCity"] = t.Buyer.Address.City
	vals["AddressState"] = t.Buyer.Address.State
	vals["AddressCountry"] = t.Buyer.Address.Country
	vals["AddressZIP"] = t.Buyer.Address.ZIP
	//
	vals["DeliveryDate"] = t.DeliveryDetails.Date.String()
	vals["DeliveryMethod"] = t.DeliveryDetails.DeliveryKind
	vals["DeliveryAddress1"] = t.DeliveryDetails.Address.Line1
	vals["DeliveryAddress2"] = t.DeliveryDetails.Address.Line2
	vals["DeliveryCity"] = t.DeliveryDetails.Address.City
	vals["DeliveryState"] = t.DeliveryDetails.Address.State
	vals["DeliveryCountry"] = t.DeliveryDetails.Address.Country
	vals["DeliveryZIP"] = t.DeliveryDetails.Address.ZIP
	//
	vals["Cobranca1"] = t.BillingAddress.Line1
	vals["Cobranca2"] = t.BillingAddress.Line2
	vals["CobrancaCity"] = t.BillingAddress.City
	vals["CobrancaState"] = t.BillingAddress.State
	vals["CobrancaCountry"] = t.BillingAddress.Country
	vals["CobrancaZIP"] = t.BillingAddress.ZIP

	if t.Installments > 1 {
		//TODO: support interest
		vals["TipoParcelado"] = "zero_interest"
		vals["NumParcelas"] = t.Installments
	}

	//
	// items
	i0 := make([]map[string]interface{}, len(t.Products))
	for k, v := range t.Products {
		i0[k] = make(map[string]interface{})
		i0[k]["ProductCode"] = v.ProductId
		i0[k]["ProductDescription"] = v.Description
		i0[k]["ProductCategory"] = v.Category
		i0[k]["OrderQuantity"] = fmt.Sprintf("%v", v.Quantity)
		i0[k]["UnitPrice"] = fmt.Sprintf("%v", v.MoneyAmount)
		i0[k]["ProductRisk"] = v.Risk
	}
	vals["OrderItems"] = i0

	vals["SkipRisk"] = t.skipRisk
	vals["SkipAddressDetails"] = t.skipAddressDetails
	vals["SkipBillingDetails"] = t.skipBillingDetails
	vals["SkipLineItems"] = t.skipLineItems
	vals["SkipOrderDetails"] = t.skipOrderDetails
	vals["SkipShippingDetails"] = t.skipShippingDetails

	// </Transaction>
	tpl := template.New("xml")
	tpl = template.Must(tpl.Parse(tpl_request_cc))
	buffer := new(bytes.Buffer)
	tpl.Execute(buffer, vals)
	return buffer
}

func (t *Transaction) Submit() (*TransactionResponse, error) {
	buffer := t.GetXML()
	log.Println(URL())
	log.Println(buffer.String())
	resp, err := http.Post(URL(), "application/xml", buffer)
	if err != nil {
		return nil, err
	}
	tr := &TransactionResponse{}
	buffer.Truncate(0)
	defer resp.Body.Close()
	io.Copy(buffer, resp.Body)
	if Verbose {
		log.Println(buffer.String())
	}
	err = xml.Unmarshal(buffer.Bytes(), tr)
	return tr, err
}

/* ~~~~~ TransactionProduct ~~~~~ */

func (t *TransactionProduct) SetHighRisk() *TransactionProduct {
	t.Risk = "High"
	return t
}

func (t *TransactionProduct) SetMediumRisk() *TransactionProduct {
	t.Risk = "Medium"
	return t
}

func (t *TransactionProduct) SetLowRisk() *TransactionProduct {
	t.Risk = "Low"
	return t
}

/* ~~~~~ CardExpDate ~~~~~ */

func (c *CardExpDate) String() string {
	return c.Month + "/" + c.Year
}

/* ~~~~~ TransactionDate ~~~~~ */

func (t *TransactionDate) String() string {
	if len(t.Year) < 1 || len(t.Month) < 1 || len(t.Day) < 1 {
		return ""
	}
	return t.Year + "-" + t.Month + "-" + t.Day
}
<commit_msg>writes response xml to buffer if an io.Writer is passed<commit_after>package erede

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/http"
	"text/template"
)

var (
	User        string
	Password    string
	Environment = 1
	Verbose     = false
)

const (
	OrderTypeCredit = "credit"
	URLDEV          = "https://scommerce.redecard.com.br/Beta/wsTransaction"
	URLPROD         = "https://ecommerce.userede.com.br/Transaction/wsTransaction"
)

const (
	DevelopmentEnv = 0
	ProductionEnv  = 1
)

func SetProductionEnv() {
	Environment = ProductionEnv
}

func SetDevelopmentEnv() {
	Environment = DevelopmentEnv
}

func URL() string {
	if Environment == ProductionEnv {
		return URLPROD
	}
	return URLDEV
}

type Transaction struct {
	CardNumber          string
	CardExpiryDate      CardExpDate
	CVC2                string
	OrderID             string
	OrderMoneyAmount    float64
	OrderType           string
	Installments        int
	DeliveryDetails     TransactionDelivery
	BillingAddress      TransactionAddress
	Products            []TransactionProduct
	Buyer               TransactionBuyer
	skipRisk            bool
	skipAddressDetails  bool
	skipShippingDetails bool
	skipBillingDetails  bool
	skipOrderDetails    bool
	skipLineItems       bool
	location            string
}

type CardExpDate struct {
	Month string
	Year  string
}

type TransactionBuyer struct {
	BuyerID string
	Email   string
	IPv4    string
	Phone1  string
	Phone2  string
	DOB     TransactionDate
	RG      string
	Name    string
	Surname string
	Address TransactionAddress
}

type TransactionDate struct {
	Year  string
	Month string
	Day   string
}

type TransactionAddress struct {
	Line1   string
	Line2   string
	City    string
	State   string
	Country string
	ZIP     string
}

type TransactionDelivery struct {
	Date         TransactionDate
	DeliveryKind string // SEDEX 10
	Address      TransactionAddress
}

type TransactionProduct struct {
	ProductId   string
	Description string
	Category    string
	Quantity    int
	MoneyAmount float64
	Risk        string // High | Low
}

/* ~~~~~ Transaction ~~~~~ */

func (t *Transaction) AddProduct(id, description, category string, quantity int, moneyAmount float64) *TransactionProduct {
	t.skipLineItems = false
	i0 := TransactionProduct{id, description, category, quantity, moneyAmount, "low"}
	t.Products = append(t.Products, i0)
	return &t.Products[len(t.Products)-1]
}

func (t *Transaction) SetVendorLocation(loc string) *Transaction {
	t.location = loc
	return t
}

func (t *Transaction) SetSkipAddressDetails(val bool) *Transaction {
	t.skipAddressDetails = val
	return t
}

func (t *Transaction) SetSkipRisk(val bool) *Transaction {
	t.skipRisk = val
	return t
}

func (t *Transaction) SetSkipShippingDetails(val bool) *Transaction {
	t.skipShippingDetails = val
	return t
}

func (t *Transaction) SetSkipBillingDetails(val bool) *Transaction {
	t.skipBillingDetails = val
	return t
}

func FulFillTxn(gatewayReference, authcode string) string {
	vals := make(map[string]interface{}, 0)
	vals["User"] = User
	vals["Password"] = Password
	vals["GatewayReference"] = gatewayReference
	vals["AuthCode"] = authcode

	tpl := template.New("xml")
	tpl = template.Must(tpl.Parse(tpl_fulfill))
	var buffer bytes.Buffer
	tpl.Execute(&buffer, vals)
	log.Println(URL())
	log.Println(buffer.String())
	resp, err := http.Post(URL(), "application/xml", &buffer)
	if err != nil {
		return err.Error()
		//return nil, err
	}
	//tr := &TransactionResponse{}
	buffer.Truncate(0)
	defer resp.Body.Close()
	io.Copy(&buffer, resp.Body)
	if Verbose {
		log.Println(buffer.String())
	}

	return buffer.String()
	//err = xml.Unmarshal(buffer.Bytes(), tr)
	//return tr, err
}

func (t *Transaction) GetXML() *bytes.Buffer {
	if t.skipLineItems && t.skipBillingDetails {
		t.skipOrderDetails = true
	} else {
		t.skipOrderDetails = false
	}
	vals := make(map[string]interface{}, 0)
	vals["User"] = User
	vals["Password"] = Password
	// <Transaction>
	vals["CC"] = t.CardNumber
	vals["ExpiryDate"] = t.CardExpiryDate.String()
	vals["CCVC2"] = t.CVC2
	vals["TipoTransacao"] = t.OrderType
	vals["Method"] = "auth" // pre ou auth // mostra se é pré autorização ou não!
	vals["MReference"] = t.OrderID
	vals["Amount"] = fmt.Sprintf("%v", t.OrderMoneyAmount)
	//
	vals["VMLocation"] = t.location
	vals["VChannel"] = "W" // ???
	vals["VuserId"] = t.Buyer.BuyerID
	vals["Vmail"] = t.Buyer.Email
	vals["VIP"] = t.Buyer.IPv4
	vals["PFone1"] = t.Buyer.Phone1
	vals["PFone2"] = t.Buyer.Phone2
	vals["PDateBirth"] = t.Buyer.DOB.String()
	vals["PIDNumber"] = t.Buyer.RG
	vals["PIDType"] = "2" // RG ?
	vals["PFName"] = t.Buyer.Name
	vals["PLName"] = t.Buyer.Surname
	//
	vals["Address1"] = t.Buyer.Address.Line1
	vals["Address2"] = t.Buyer.Address.Line2
	vals["AddressCity"] = t.Buyer.Address.City
	vals["AddressState"] = t.Buyer.Address.State
	vals["AddressCountry"] = t.Buyer.Address.Country
	vals["AddressZIP"] = t.Buyer.Address.ZIP
	//
	vals["DeliveryDate"] = t.DeliveryDetails.Date.String()
	vals["DeliveryMethod"] = t.DeliveryDetails.DeliveryKind
	vals["DeliveryAddress1"] = t.DeliveryDetails.Address.Line1
	vals["DeliveryAddress2"] = t.DeliveryDetails.Address.Line2
	vals["DeliveryCity"] = t.DeliveryDetails.Address.City
	vals["DeliveryState"] = t.DeliveryDetails.Address.State
	vals["DeliveryCountry"] = t.DeliveryDetails.Address.Country
	vals["DeliveryZIP"] = t.DeliveryDetails.Address.ZIP
	//
	vals["Cobranca1"] = t.BillingAddress.Line1
	vals["Cobranca2"] = t.BillingAddress.Line2
	vals["CobrancaCity"] = t.BillingAddress.City
	vals["CobrancaState"] = t.BillingAddress.State
	vals["CobrancaCountry"] = t.BillingAddress.Country
	vals["CobrancaZIP"] = t.BillingAddress.ZIP

	if t.Installments > 1 {
		//TODO: support interest
		vals["TipoParcelado"] = "zero_interest"
		vals["NumParcelas"] = t.Installments
	}

	//
	// items
	i0 := make([]map[string]interface{}, len(t.Products))
	for k, v := range t.Products {
		i0[k] = make(map[string]interface{})
		i0[k]["ProductCode"] = v.ProductId
		i0[k]["ProductDescription"] = v.Description
		i0[k]["ProductCategory"] = v.Category
		i0[k]["OrderQuantity"] = fmt.Sprintf("%v", v.Quantity)
		i0[k]["UnitPrice"] = fmt.Sprintf("%v", v.MoneyAmount)
		i0[k]["ProductRisk"] = v.Risk
	}
	vals["OrderItems"] = i0

	vals["SkipRisk"] = t.skipRisk
	vals["SkipAddressDetails"] = t.skipAddressDetails
	vals["SkipBillingDetails"] = t.skipBillingDetails
	vals["SkipLineItems"] = t.skipLineItems
	vals["SkipOrderDetails"] = t.skipOrderDetails
	vals["SkipShippingDetails"] = t.skipShippingDetails

	// </Transaction>
	tpl := template.New("xml")
	tpl = template.Must(tpl.Parse(tpl_request_cc))
	buffer := new(bytes.Buffer)
	tpl.Execute(buffer, vals)
	return buffer
}

func (t *Transaction) Submit(xmlw ...io.Writer) (*TransactionResponse, error) {
	buffer := t.GetXML()
	if Verbose {
		log.Println(URL())
		log.Println(buffer.String())
	}
	resp, err := http.Post(URL(), "application/xml", buffer)
	if err != nil {
		return nil, err
	}
	tr := &TransactionResponse{}
	buffer.Truncate(0)
	defer resp.Body.Close()
	io.Copy(buffer, resp.Body)
	bs := buffer.Bytes()
	if Verbose {
		log.Println(string(bs))
	}
	if len(xmlw) > 0 {
		xmlw[0].Write(bs)
	}
	err = xml.Unmarshal(bs, tr)
	return tr, err
}

/* ~~~~~ TransactionProduct ~~~~~ */

func (t *TransactionProduct) SetHighRisk() *TransactionProduct {
	t.Risk = "High"
	return t
}

func (t *TransactionProduct) SetMediumRisk() *TransactionProduct {
	t.Risk = "Medium"
	return t
}

func (t *TransactionProduct) SetLowRisk() *TransactionProduct {
	t.Risk = "Low"
	return t
}

/* ~~~~~ CardExpDate ~~~~~ */

func (c *CardExpDate) String() string {
	return c.Month + "/" + c.Year
}

/* ~~~~~ TransactionDate ~~~~~ */

func (t *TransactionDate) String() string {
	if len(t.Year) < 1 || len(t.Month) < 1 || len(t.Day) < 1 {
		return ""
	}
	return t.Year + "-" + t.Month + "-" + t.Day
}
<|endoftext|>


<commit_before>package main

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

const (
	GET     = "GET"
	POST    = "POST"
	PUT     = "PUT"
	DELETE  = "DELETE"
	OPTIONS = "OPTIONS"
)

var all = strings.Join([]string{OPTIONS, GET, POST, PUT, DELETE}, ", ")

type GetMethod interface {
	Get(url.Values) (int, interface{})
}

type PostMethod interface {
	Post(url.Values) (int, interface{})
}

type PutMethod interface {
	Put(url.Values) (int, interface{})
}

type DeleteMethod interface {
	Delete(url.Values) (int, interface{})
}

// Dispatches an HTTP error with the given code
func Abort(rw *http.ResponseWriter, code int) {
	err := fmt.Sprintf("%d %s", code, http.StatusText(code))
	http.Error(*rw, err, code)
}

// Reflects the different HTTP verbs into the given interface, allows the
// following methods: `Get`, `Post`, `Put`, `Delete`.
//
// Based on a Doug Black code:
// https://github.com/dougblack/sleepy/blob/master/core.go
func RestController(c interface{}) http.HandlerFunc {
	return func(rw http.ResponseWriter, r *http.Request) {
		log := NewHttpLogger(*r)
		defer log.Print()
		// Add some usefull headers
		h := rw.Header()
		h.Add("Content-Type", "application/json; charset=utf-8")
		h.Add("Access-Control-Allow-Origin", "*")
		h.Add("Access-Control-Allow-Methods", all)
		h.Add("Connection", "close")
		// Parse sent data
		if r.ParseForm() != nil {
			Abort(&rw, http.StatusBadRequest)
			return
		}

		var handler func(url.Values) (int, interface{})

		switch r.Method {
		case GET:
			if c, ok := c.(GetMethod); ok {
				handler = c.Get
			}
		case POST:
			if c, ok := c.(PostMethod); ok {
				handler = c.Post
			}
		case PUT:
			if c, ok := c.(PutMethod); ok {
				handler = c.Put
			}
		case DELETE:
			if c, ok := c.(DeleteMethod); ok {
				handler = c.Delete
			}
		case OPTIONS:
			handler = func(_ url.Values) (int, interface{}) {
				return http.StatusOK, ""
			}
		}
		// Abort with a 405 status
		if handler == nil {
			h.Add("Allow", all)
			Abort(&rw, http.StatusMethodNotAllowed)
			return
		}
		// Create the params from GET and POST values
		params, _ := url.ParseQuery(fmt.Sprintf("%s&%s",
			r.URL.Query().Encode(), r.Form.Encode()))
		// Call the handler
		code, data := handler(params)
		// Set a default
		if data == nil {
			data = map[string]interface{}{
				"status": code,
				"text":   http.StatusText(code),
			}
		}
		// Encode
		content, err := json.Marshal(data)
		if err != nil {
			Abort(&rw, http.StatusInternalServerError)
			return
		}
		// Write to response
		rw.WriteHeader(code)
		rw.Write(content)
	}
}

// Simple HTTP request logger
type HttpLogger struct {
	initTime time.Time
	request  http.Request
}

// Print with the method, url and request time
func (l *HttpLogger) Print() {
	log.Printf("%s \t %s %s",
		time.Since(l.initTime).String(),
		l.request.Method,
		l.request.URL.Path)
}

// Return a new instance of the HTTP logger
func NewHttpLogger(r http.Request) *HttpLogger {
	l := new(HttpLogger)
	l.initTime = time.Now()
	l.request = r
	return l
}
<commit_msg>Add Access-Control-Allow-Headers to the response header<commit_after>package main

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

const (
	GET     = "GET"
	POST    = "POST"
	PUT     = "PUT"
	DELETE  = "DELETE"
	OPTIONS = "OPTIONS"
)

var all = strings.Join([]string{OPTIONS, GET, POST, PUT, DELETE}, ", ")

type GetMethod interface {
	Get(url.Values) (int, interface{})
}

type PostMethod interface {
	Post(url.Values) (int, interface{})
}

type PutMethod interface {
	Put(url.Values) (int, interface{})
}

type DeleteMethod interface {
	Delete(url.Values) (int, interface{})
}

// Dispatches an HTTP error with the given code
func Abort(rw *http.ResponseWriter, code int) {
	err := fmt.Sprintf("%d %s", code, http.StatusText(code))
	http.Error(*rw, err, code)
}

// Reflects the different HTTP verbs into the given interface, allows the
// following methods: `Get`, `Post`, `Put`, `Delete`.
//
// Based on a Doug Black code:
// https://github.com/dougblack/sleepy/blob/master/core.go
func RestController(c interface{}) http.HandlerFunc {
	return func(rw http.ResponseWriter, r *http.Request) {
		log := NewHttpLogger(*r)
		defer log.Print()
		// Add some usefull headers
		h := rw.Header()
		h.Add("Content-Type", "application/json; charset=utf-8")
		h.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, "+
			"Content-Type, Accept")
		h.Add("Access-Control-Allow-Origin", "*")
		h.Add("Access-Control-Allow-Methods", all)
		h.Add("Connection", "close")
		// Parse sent data
		if r.ParseForm() != nil {
			Abort(&rw, http.StatusBadRequest)
			return
		}

		var handler func(url.Values) (int, interface{})

		switch r.Method {
		case GET:
			if c, ok := c.(GetMethod); ok {
				handler = c.Get
			}
		case POST:
			if c, ok := c.(PostMethod); ok {
				handler = c.Post
			}
		case PUT:
			if c, ok := c.(PutMethod); ok {
				handler = c.Put
			}
		case DELETE:
			if c, ok := c.(DeleteMethod); ok {
				handler = c.Delete
			}
		case OPTIONS:
			handler = func(_ url.Values) (int, interface{}) {
				return http.StatusOK, ""
			}
		}
		// Abort with a 405 status
		if handler == nil {
			h.Add("Allow", all)
			Abort(&rw, http.StatusMethodNotAllowed)
			return
		}
		// Create the params from GET and POST values
		params, _ := url.ParseQuery(fmt.Sprintf("%s&%s",
			r.URL.Query().Encode(), r.Form.Encode()))
		// Call the handler
		code, data := handler(params)
		// Set a default
		if data == nil {
			data = map[string]interface{}{
				"status": code,
				"text":   http.StatusText(code),
			}
		}
		// Encode
		content, err := json.Marshal(data)
		if err != nil {
			Abort(&rw, http.StatusInternalServerError)
			return
		}
		// Write to response
		rw.WriteHeader(code)
		rw.Write(content)
	}
}

// Simple HTTP request logger
type HttpLogger struct {
	initTime time.Time
	request  http.Request
}

// Print with the method, url and request time
func (l *HttpLogger) Print() {
	log.Printf("%s \t %s %s",
		time.Since(l.initTime).String(),
		l.request.Method,
		l.request.URL.Path)
}

// Return a new instance of the HTTP logger
func NewHttpLogger(r http.Request) *HttpLogger {
	l := new(HttpLogger)
	l.initTime = time.Now()
	l.request = r
	return l
}
<|endoftext|>


<commit_before>/*
Package cors is net/http handler to handle CORS related requests
as defined by http://www.w3.org/TR/cors/

You can configure it by passing an option struct to cors.New:

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"foo.com"},
        AllowedMethods: []string{"GET", "POST", "DELETE"},
        AllowCredentials: true,
    })

Then insert the handler in the chain:

    handler = c.Handler(handler)

See Options documentation for more options.

The resulting handler is a standard net/http handler.
*/
package cors

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

// Options is a configuration container to setup the CORS middleware.
type Options struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// An origin may contain a wildcard (*) to replace 0 or more characters
	// (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
	// Only one wildcard can be used per origin.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowOriginFunc is a custom function to validate the origin. It take the origin
	// as argument and returns true if allowed or false otherwise. If this option is
	// set, the content of AllowedOrigins is ignored.
	AllowOriginFunc func(origin string) bool
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (HEAD, GET and POST).
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	// If the special "*" value is present in the list, all headers will be allowed.
	// Default value is [] but "Origin" is always appended to the list.
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
	// OptionsPassthrough instructs preflight to let other potential next handlers to
	// process the OPTIONS method. Turn this on if your application handles OPTIONS.
	OptionsPassthrough bool
	// Debugging flag adds additional output to debug server side CORS issues
	Debug bool
}

// Cors http handler
type Cors struct {
	// Debug logger
	Log *log.Logger
	// Set to true when allowed origins contains a "*"
	allowedOriginsAll bool
	// Normalized list of plain allowed origins
	allowedOrigins []string
	// List of allowed origins containing wildcards
	allowedWOrigins []wildcard
	// Optional origin validator function
	allowOriginFunc func(origin string) bool
	// Set to true when allowed headers contains a "*"
	allowedHeadersAll bool
	// Normalized list of allowed headers
	allowedHeaders []string
	// Normalized list of allowed methods
	allowedMethods []string
	// Normalized list of exposed headers
	exposedHeaders    []string
	allowCredentials  bool
	maxAge            int
	optionPassthrough bool
}

// New creates a new Cors handler with the provided options.
func New(options Options) *Cors {
	c := &Cors{
		exposedHeaders:    convert(options.ExposedHeaders, http.CanonicalHeaderKey),
		allowOriginFunc:   options.AllowOriginFunc,
		allowCredentials:  options.AllowCredentials,
		maxAge:            options.MaxAge,
		optionPassthrough: options.OptionsPassthrough,
	}
	if options.Debug {
		c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
	}

	// Normalize options
	// Note: for origins and methods matching, the spec requires a case-sensitive matching.
	// As it may error prone, we chose to ignore the spec here.

	// Allowed Origins
	if len(options.AllowedOrigins) == 0 {
		if options.AllowOriginFunc == nil {
			// Default is all origins
			c.allowedOriginsAll = true
		}
	} else {
		c.allowedOrigins = []string{}
		c.allowedWOrigins = []wildcard{}
		for _, origin := range options.AllowedOrigins {
			// Normalize
			origin = strings.ToLower(origin)
			if origin == "*" {
				// If "*" is present in the list, turn the whole list into a match all
				c.allowedOriginsAll = true
				c.allowedOrigins = nil
				c.allowedWOrigins = nil
				break
			} else if i := strings.IndexByte(origin, '*'); i >= 0 {
				// Split the origin in two: start and end string without the *
				w := wildcard{origin[0:i], origin[i+1 : len(origin)]}
				c.allowedWOrigins = append(c.allowedWOrigins, w)
			} else {
				c.allowedOrigins = append(c.allowedOrigins, origin)
			}
		}
	}

	// Allowed Headers
	if len(options.AllowedHeaders) == 0 {
		// Use sensible defaults
		c.allowedHeaders = []string{"Origin", "Accept", "Content-Type"}
	} else {
		// Origin is always appended as some browsers will always request for this header at preflight
		c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
		for _, h := range options.AllowedHeaders {
			if h == "*" {
				c.allowedHeadersAll = true
				c.allowedHeaders = nil
				break
			}
		}
	}

	// Allowed Methods
	if len(options.AllowedMethods) == 0 {
		// Default is spec's "simple" methods
		c.allowedMethods = []string{"GET", "POST", "HEAD"}
	} else {
		c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
	}

	return c
}

// Default creates a new Cors handler with default options.
func Default() *Cors {
	return New(Options{})
}

// AllowAll create a new Cors handler with permissive configuration allowing all
// origins with all standard methods with any header and credentials.
func AllowAll() *Cors {
	return New(Options{
		AllowedOrigins:   []string{"*"},
		AllowedMethods:   []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"},
		AllowedHeaders:   []string{"*"},
		AllowCredentials: true,
	})
}

// Handler apply the CORS specification on the request, and add relevant CORS headers
// as necessary.
func (c *Cors) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
			c.logf("Handler: Preflight request")
			c.handlePreflight(w, r)
			// Preflight requests are standalone and should stop the chain as some other
			// middleware may not handle OPTIONS requests correctly. One typical example
			// is authentication middleware ; OPTIONS requests won't carry authentication
			// headers (see #1)
			if c.optionPassthrough {
				h.ServeHTTP(w, r)
			} else {
				w.WriteHeader(http.StatusOK)
			}
		} else {
			c.logf("Handler: Actual request")
			c.handleActualRequest(w, r)
			h.ServeHTTP(w, r)
		}
	})
}

// HandlerFunc provides Martini compatible handler
func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
		c.logf("HandlerFunc: Preflight request")
		c.handlePreflight(w, r)
	} else {
		c.logf("HandlerFunc: Actual request")
		c.handleActualRequest(w, r)
	}
}

// Negroni compatible interface
func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
		c.logf("ServeHTTP: Preflight request")
		c.handlePreflight(w, r)
		// Preflight requests are standalone and should stop the chain as some other
		// middleware may not handle OPTIONS requests correctly. One typical example
		// is authentication middleware ; OPTIONS requests won't carry authentication
		// headers (see #1)
		if c.optionPassthrough {
			next(w, r)
		} else {
			w.WriteHeader(http.StatusOK)
		}
	} else {
		c.logf("ServeHTTP: Actual request")
		c.handleActualRequest(w, r)
		next(w, r)
	}
}

// handlePreflight handles pre-flight CORS requests
func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	origin := r.Header.Get("Origin")

	if r.Method != http.MethodOptions {
		c.logf("  Preflight aborted: %s!=OPTIONS", r.Method)
		return
	}
	// Always set Vary headers
	// see https://github.com/rs/cors/issues/10,
	//     https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
	headers.Add("Vary", "Origin")
	headers.Add("Vary", "Access-Control-Request-Method")
	headers.Add("Vary", "Access-Control-Request-Headers")

	if origin == "" {
		c.logf("  Preflight aborted: empty origin")
		return
	}
	if !c.isOriginAllowed(origin) {
		c.logf("  Preflight aborted: origin '%s' not allowed", origin)
		return
	}

	reqMethod := r.Header.Get("Access-Control-Request-Method")
	if !c.isMethodAllowed(reqMethod) {
		c.logf("  Preflight aborted: method '%s' not allowed", reqMethod)
		return
	}
	reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
	if !c.areHeadersAllowed(reqHeaders) {
		c.logf("  Preflight aborted: headers '%v' not allowed", reqHeaders)
		return
	}
	if c.allowedOriginsAll && !c.allowCredentials {
		headers.Set("Access-Control-Allow-Origin", "*")
	} else {
		headers.Set("Access-Control-Allow-Origin", origin)
	}
	// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
	// by Access-Control-Request-Method (if supported) can be enough
	headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
	if len(reqHeaders) > 0 {

		// Spec says: Since the list of headers can be unbounded, simply returning supported headers
		// from Access-Control-Request-Headers can be enough
		headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
	}
	if c.allowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	if c.maxAge > 0 {
		headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
	}
	c.logf("  Preflight response headers: %v", headers)
}

// handleActualRequest handles simple cross-origin requests, actual request or redirects
func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	origin := r.Header.Get("Origin")

	if r.Method == http.MethodOptions {
		c.logf("  Actual request no headers added: method == %s", r.Method)
		return
	}
	// Always set Vary, see https://github.com/rs/cors/issues/10
	headers.Add("Vary", "Origin")
	if origin == "" {
		c.logf("  Actual request no headers added: missing origin")
		return
	}
	if !c.isOriginAllowed(origin) {
		c.logf("  Actual request no headers added: origin '%s' not allowed", origin)
		return
	}

	// Note that spec does define a way to specifically disallow a simple method like GET or
	// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
	// spec doesn't instruct to check the allowed methods for simple cross-origin requests.
	// We think it's a nice feature to be able to have control on those methods though.
	if !c.isMethodAllowed(r.Method) {
		c.logf("  Actual request no headers added: method '%s' not allowed", r.Method)

		return
	}
	if c.allowedOriginsAll && !c.allowCredentials {
		headers.Set("Access-Control-Allow-Origin", "*")
	} else {
		headers.Set("Access-Control-Allow-Origin", origin)
	}
	if len(c.exposedHeaders) > 0 {
		headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
	}
	if c.allowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	c.logf("  Actual response added headers: %v", headers)
}

// convenience method. checks if debugging is turned on before printing
func (c *Cors) logf(format string, a ...interface{}) {
	if c.Log != nil {
		c.Log.Printf(format, a...)
	}
}

// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (c *Cors) isOriginAllowed(origin string) bool {
	if c.allowOriginFunc != nil {
		return c.allowOriginFunc(origin)
	}
	if c.allowedOriginsAll {
		return true
	}
	origin = strings.ToLower(origin)
	for _, o := range c.allowedOrigins {
		if o == origin {
			return true
		}
	}
	for _, w := range c.allowedWOrigins {
		if w.match(origin) {
			return true
		}
	}
	return false
}

// isMethodAllowed checks if a given method can be used as part of a cross-domain request
// on the endpoing
func (c *Cors) isMethodAllowed(method string) bool {
	if len(c.allowedMethods) == 0 {
		// If no method allowed, always return false, even for preflight request
		return false
	}
	method = strings.ToUpper(method)
	if method == http.MethodOptions {
		// Always allow preflight requests
		return true
	}
	for _, m := range c.allowedMethods {
		if m == method {
			return true
		}
	}
	return false
}

// areHeadersAllowed checks if a given list of headers are allowed to used within
// a cross-domain request.
func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
	if c.allowedHeadersAll || len(requestedHeaders) == 0 {
		return true
	}
	for _, header := range requestedHeaders {
		header = http.CanonicalHeaderKey(header)
		found := false
		for _, h := range c.allowedHeaders {
			if h == header {
				found = true
			}
		}
		if !found {
			return false
		}
	}
	return true
}
<commit_msg>Make aligncheck and megacheck happy<commit_after>/*
Package cors is net/http handler to handle CORS related requests
as defined by http://www.w3.org/TR/cors/

You can configure it by passing an option struct to cors.New:

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"foo.com"},
        AllowedMethods: []string{"GET", "POST", "DELETE"},
        AllowCredentials: true,
    })

Then insert the handler in the chain:

    handler = c.Handler(handler)

See Options documentation for more options.

The resulting handler is a standard net/http handler.
*/
package cors

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

// Options is a configuration container to setup the CORS middleware.
type Options struct {
	// AllowedOrigins is a list of origins a cross-domain request can be executed from.
	// If the special "*" value is present in the list, all origins will be allowed.
	// An origin may contain a wildcard (*) to replace 0 or more characters
	// (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penalty.
	// Only one wildcard can be used per origin.
	// Default value is ["*"]
	AllowedOrigins []string
	// AllowOriginFunc is a custom function to validate the origin. It take the origin
	// as argument and returns true if allowed or false otherwise. If this option is
	// set, the content of AllowedOrigins is ignored.
	AllowOriginFunc func(origin string) bool
	// AllowedMethods is a list of methods the client is allowed to use with
	// cross-domain requests. Default value is simple methods (HEAD, GET and POST).
	AllowedMethods []string
	// AllowedHeaders is list of non simple headers the client is allowed to use with
	// cross-domain requests.
	// If the special "*" value is present in the list, all headers will be allowed.
	// Default value is [] but "Origin" is always appended to the list.
	AllowedHeaders []string
	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS
	// API specification
	ExposedHeaders []string
	// MaxAge indicates how long (in seconds) the results of a preflight request
	// can be cached
	MaxAge int
	// AllowCredentials indicates whether the request can include user credentials like
	// cookies, HTTP authentication or client side SSL certificates.
	AllowCredentials bool
	// OptionsPassthrough instructs preflight to let other potential next handlers to
	// process the OPTIONS method. Turn this on if your application handles OPTIONS.
	OptionsPassthrough bool
	// Debugging flag adds additional output to debug server side CORS issues
	Debug bool
}

// Cors http handler
type Cors struct {
	// Debug logger
	Log *log.Logger
	// Normalized list of plain allowed origins
	allowedOrigins []string
	// List of allowed origins containing wildcards
	allowedWOrigins []wildcard
	// Optional origin validator function
	allowOriginFunc func(origin string) bool
	// Normalized list of allowed headers
	allowedHeaders []string
	// Normalized list of allowed methods
	allowedMethods []string
	// Normalized list of exposed headers
	exposedHeaders []string
	maxAge         int
	// Set to true when allowed origins contains a "*"
	allowedOriginsAll bool
	// Set to true when allowed headers contains a "*"
	allowedHeadersAll bool
	allowCredentials  bool
	optionPassthrough bool
}

// New creates a new Cors handler with the provided options.
func New(options Options) *Cors {
	c := &Cors{
		exposedHeaders:    convert(options.ExposedHeaders, http.CanonicalHeaderKey),
		allowOriginFunc:   options.AllowOriginFunc,
		allowCredentials:  options.AllowCredentials,
		maxAge:            options.MaxAge,
		optionPassthrough: options.OptionsPassthrough,
	}
	if options.Debug {
		c.Log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
	}

	// Normalize options
	// Note: for origins and methods matching, the spec requires a case-sensitive matching.
	// As it may error prone, we chose to ignore the spec here.

	// Allowed Origins
	if len(options.AllowedOrigins) == 0 {
		if options.AllowOriginFunc == nil {
			// Default is all origins
			c.allowedOriginsAll = true
		}
	} else {
		c.allowedOrigins = []string{}
		c.allowedWOrigins = []wildcard{}
		for _, origin := range options.AllowedOrigins {
			// Normalize
			origin = strings.ToLower(origin)
			if origin == "*" {
				// If "*" is present in the list, turn the whole list into a match all
				c.allowedOriginsAll = true
				c.allowedOrigins = nil
				c.allowedWOrigins = nil
				break
			} else if i := strings.IndexByte(origin, '*'); i >= 0 {
				// Split the origin in two: start and end string without the *
				w := wildcard{origin[0:i], origin[i+1:]}
				c.allowedWOrigins = append(c.allowedWOrigins, w)
			} else {
				c.allowedOrigins = append(c.allowedOrigins, origin)
			}
		}
	}

	// Allowed Headers
	if len(options.AllowedHeaders) == 0 {
		// Use sensible defaults
		c.allowedHeaders = []string{"Origin", "Accept", "Content-Type"}
	} else {
		// Origin is always appended as some browsers will always request for this header at preflight
		c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
		for _, h := range options.AllowedHeaders {
			if h == "*" {
				c.allowedHeadersAll = true
				c.allowedHeaders = nil
				break
			}
		}
	}

	// Allowed Methods
	if len(options.AllowedMethods) == 0 {
		// Default is spec's "simple" methods
		c.allowedMethods = []string{"GET", "POST", "HEAD"}
	} else {
		c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
	}

	return c
}

// Default creates a new Cors handler with default options.
func Default() *Cors {
	return New(Options{})
}

// AllowAll create a new Cors handler with permissive configuration allowing all
// origins with all standard methods with any header and credentials.
func AllowAll() *Cors {
	return New(Options{
		AllowedOrigins:   []string{"*"},
		AllowedMethods:   []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"},
		AllowedHeaders:   []string{"*"},
		AllowCredentials: true,
	})
}

// Handler apply the CORS specification on the request, and add relevant CORS headers
// as necessary.
func (c *Cors) Handler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
			c.logf("Handler: Preflight request")
			c.handlePreflight(w, r)
			// Preflight requests are standalone and should stop the chain as some other
			// middleware may not handle OPTIONS requests correctly. One typical example
			// is authentication middleware ; OPTIONS requests won't carry authentication
			// headers (see #1)
			if c.optionPassthrough {
				h.ServeHTTP(w, r)
			} else {
				w.WriteHeader(http.StatusOK)
			}
		} else {
			c.logf("Handler: Actual request")
			c.handleActualRequest(w, r)
			h.ServeHTTP(w, r)
		}
	})
}

// HandlerFunc provides Martini compatible handler
func (c *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
		c.logf("HandlerFunc: Preflight request")
		c.handlePreflight(w, r)
	} else {
		c.logf("HandlerFunc: Actual request")
		c.handleActualRequest(w, r)
	}
}

// Negroni compatible interface
func (c *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
		c.logf("ServeHTTP: Preflight request")
		c.handlePreflight(w, r)
		// Preflight requests are standalone and should stop the chain as some other
		// middleware may not handle OPTIONS requests correctly. One typical example
		// is authentication middleware ; OPTIONS requests won't carry authentication
		// headers (see #1)
		if c.optionPassthrough {
			next(w, r)
		} else {
			w.WriteHeader(http.StatusOK)
		}
	} else {
		c.logf("ServeHTTP: Actual request")
		c.handleActualRequest(w, r)
		next(w, r)
	}
}

// handlePreflight handles pre-flight CORS requests
func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	origin := r.Header.Get("Origin")

	if r.Method != http.MethodOptions {
		c.logf("  Preflight aborted: %s!=OPTIONS", r.Method)
		return
	}
	// Always set Vary headers
	// see https://github.com/rs/cors/issues/10,
	//     https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
	headers.Add("Vary", "Origin")
	headers.Add("Vary", "Access-Control-Request-Method")
	headers.Add("Vary", "Access-Control-Request-Headers")

	if origin == "" {
		c.logf("  Preflight aborted: empty origin")
		return
	}
	if !c.isOriginAllowed(origin) {
		c.logf("  Preflight aborted: origin '%s' not allowed", origin)
		return
	}

	reqMethod := r.Header.Get("Access-Control-Request-Method")
	if !c.isMethodAllowed(reqMethod) {
		c.logf("  Preflight aborted: method '%s' not allowed", reqMethod)
		return
	}
	reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
	if !c.areHeadersAllowed(reqHeaders) {
		c.logf("  Preflight aborted: headers '%v' not allowed", reqHeaders)
		return
	}
	if c.allowedOriginsAll && !c.allowCredentials {
		headers.Set("Access-Control-Allow-Origin", "*")
	} else {
		headers.Set("Access-Control-Allow-Origin", origin)
	}
	// Spec says: Since the list of methods can be unbounded, simply returning the method indicated
	// by Access-Control-Request-Method (if supported) can be enough
	headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
	if len(reqHeaders) > 0 {

		// Spec says: Since the list of headers can be unbounded, simply returning supported headers
		// from Access-Control-Request-Headers can be enough
		headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
	}
	if c.allowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	if c.maxAge > 0 {
		headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
	}
	c.logf("  Preflight response headers: %v", headers)
}

// handleActualRequest handles simple cross-origin requests, actual request or redirects
func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
	headers := w.Header()
	origin := r.Header.Get("Origin")

	if r.Method == http.MethodOptions {
		c.logf("  Actual request no headers added: method == %s", r.Method)
		return
	}
	// Always set Vary, see https://github.com/rs/cors/issues/10
	headers.Add("Vary", "Origin")
	if origin == "" {
		c.logf("  Actual request no headers added: missing origin")
		return
	}
	if !c.isOriginAllowed(origin) {
		c.logf("  Actual request no headers added: origin '%s' not allowed", origin)
		return
	}

	// Note that spec does define a way to specifically disallow a simple method like GET or
	// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
	// spec doesn't instruct to check the allowed methods for simple cross-origin requests.
	// We think it's a nice feature to be able to have control on those methods though.
	if !c.isMethodAllowed(r.Method) {
		c.logf("  Actual request no headers added: method '%s' not allowed", r.Method)

		return
	}
	if c.allowedOriginsAll && !c.allowCredentials {
		headers.Set("Access-Control-Allow-Origin", "*")
	} else {
		headers.Set("Access-Control-Allow-Origin", origin)
	}
	if len(c.exposedHeaders) > 0 {
		headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
	}
	if c.allowCredentials {
		headers.Set("Access-Control-Allow-Credentials", "true")
	}
	c.logf("  Actual response added headers: %v", headers)
}

// convenience method. checks if debugging is turned on before printing
func (c *Cors) logf(format string, a ...interface{}) {
	if c.Log != nil {
		c.Log.Printf(format, a...)
	}
}

// isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
// on the endpoint
func (c *Cors) isOriginAllowed(origin string) bool {
	if c.allowOriginFunc != nil {
		return c.allowOriginFunc(origin)
	}
	if c.allowedOriginsAll {
		return true
	}
	origin = strings.ToLower(origin)
	for _, o := range c.allowedOrigins {
		if o == origin {
			return true
		}
	}
	for _, w := range c.allowedWOrigins {
		if w.match(origin) {
			return true
		}
	}
	return false
}

// isMethodAllowed checks if a given method can be used as part of a cross-domain request
// on the endpoing
func (c *Cors) isMethodAllowed(method string) bool {
	if len(c.allowedMethods) == 0 {
		// If no method allowed, always return false, even for preflight request
		return false
	}
	method = strings.ToUpper(method)
	if method == http.MethodOptions {
		// Always allow preflight requests
		return true
	}
	for _, m := range c.allowedMethods {
		if m == method {
			return true
		}
	}
	return false
}

// areHeadersAllowed checks if a given list of headers are allowed to used within
// a cross-domain request.
func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
	if c.allowedHeadersAll || len(requestedHeaders) == 0 {
		return true
	}
	for _, header := range requestedHeaders {
		header = http.CanonicalHeaderKey(header)
		found := false
		for _, h := range c.allowedHeaders {
			if h == header {
				found = true
			}
		}
		if !found {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

type thing interface {
	Id() identifier
	Name() string
	Brief() string
	Long() string
}

type actualThing struct {
	id    identifier
	name  string
	brief string
	long  string
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}

func getThingGetter(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) chan thing {
	response := make(chan chan thing)
	getGetter <- struct {
		id       identifier
		response chan chan thing
	}{id, response}
	return <-response
}

func getThing(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) thing {
	getter := getThingGetter(id, getGetter)
	return <-getter
}

func getThingSetter(id identifier, getSetter chan struct {
	id       identifier
	response chan chan struct {
		it  thing
		set chan thing
	}
},) chan struct {
	it  thing
	set chan thing
} {
	response := make(chan chan struct {
		it  thing
		set chan thing
	})
	getSetter <- struct {
		id       identifier
		response chan chan struct {
			it  thing
			set chan thing
		}
	}{id, response}
	return <-response
}

//func addThing

func initThingManager() (
	chan struct {
		id       identifier
		response chan chan thing
	},
	chan struct {
		id       identifier
		response chan chan struct {
			it  thing
		        set chan thing
		}
	},
	chan thing,
	chan identifier) {

	getGetter := make(chan struct {
		id       identifier
		response chan chan thing
	})
	getSetter := make(chan struct {
		id       identifier
		response chan chan struct {
			it  thing
			set chan thing
		}
	})
	add := make(chan thing)
	del := make(chan identifier)
	go func() {
		things := make(map[identifier]struct {
			getter chan thing
			setter chan struct {
				it  thing
				set chan thing
			}
			closer chan bool
		})
		for {
			select {
			case a := <-add:
				getter := make(chan thing)
				setter := make(chan struct {
					it  thing
					set chan thing
				})
				closer := make(chan bool)
				getter <- a
				go func() {
					it := <-getter
					itc := make(chan thing)
					for {
						select {
						case setter <- struct {
							it  thing
							set chan thing
						}{it: it, set: itc}:
							it = <-itc
						case getter <- it:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}()
				things[a.Id()] = struct {
					getter chan thing
					setter chan struct {
						it  thing
						set chan thing
					}
					closer chan bool
				}{getter, setter, closer}
			case d := <-del:
				things[d].closer <- true
				delete(things, d)
			case g := <-getGetter:
				g.response <- things[g.id].getter
			case s := <-getSetter:
				s.response <- things[s.id].setter
			}
		}
	}()
	return getGetter, getSetter, add, del
}
<commit_msg>added data.go Thing location variables<commit_after>package main

type Thing interface {
	Id() identifier
	Name() string
	Brief() string
	Long() string
	Location() identifier
	SetLocation(l identifier)
	Presences() map[identifier]bool
	AddPresence(p identifier)
	RemovePresence(p identifier)
}

type actualThing struct {
	id    identifier
	name  string
	brief string
	long  string
	location identifier
	presences map[identifier]bool
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}
func (t actualThing) Location() identifier {
	return t.location
}
func (t actualThing) SetLocation(l identifier) {
	t.location = l
}
func (t actualThing) Presences() map[identifier]bool {
	return t.presences
}
func (t actualThing) AddPresence(p identifier) {
	t.presences[p] = true
}
func (t actualThing) RemovePresence(p identifier) {
	delete(t.presences, p)
}

func getThingGetter(id identifier, getGetter chan struct {
	id       identifier
	response chan chan Thing
},) chan Thing {
	response := make(chan chan Thing)
	getGetter <- struct {
		id       identifier
		response chan chan Thing
	}{id, response}
	return <-response
}

func getThing(id identifier, getGetter chan struct {
	id       identifier
	response chan chan Thing
},) Thing {
	getter := getThingGetter(id, getGetter)
	return <-getter
}

func getThingSetter(id identifier, getSetter chan struct {
	id       identifier
	response chan chan struct {
		it  Thing
		set chan Thing
	}
},) chan struct {
	it  Thing
	set chan Thing
} {
	response := make(chan chan struct {
		it  Thing
		set chan Thing
	})
	getSetter <- struct {
		id       identifier
		response chan chan struct {
			it  Thing
			set chan Thing
		}
	}{id, response}
	return <-response
}

//func addThing

func initThingManager() (
	chan struct {
		id       identifier
		response chan chan Thing
	},
	chan struct {
		id       identifier
		response chan chan struct {
			it  Thing
		        set chan Thing
		}
	},
	chan Thing,
	chan identifier) {

	getGetter := make(chan struct {
		id       identifier
		response chan chan Thing
	})
	getSetter := make(chan struct {
		id       identifier
		response chan chan struct {
			it  Thing
			set chan Thing
		}
	})
	add := make(chan Thing)
	del := make(chan identifier)
	go func() {
		Things := make(map[identifier]struct {
			getter chan Thing
			setter chan struct {
				it  Thing
				set chan Thing
			}
			closer chan bool
		})
		for {
			select {
			case a := <-add:
				getter := make(chan Thing)
				setter := make(chan struct {
					it  Thing
					set chan Thing
				})
				closer := make(chan bool)
				getter <- a
				go func() {
					it := <-getter
					itc := make(chan Thing)
					for {
						select {
						case setter <- struct {
							it  Thing
							set chan Thing
						}{it: it, set: itc}:
							it = <-itc
						case getter <- it:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}()
				Things[a.Id()] = struct {
					getter chan Thing
					setter chan struct {
						it  Thing
						set chan Thing
					}
					closer chan bool
				}{getter, setter, closer}
			case d := <-del:
				Things[d].closer <- true
				delete(Things, d)
			case g := <-getGetter:
				g.response <- Things[g.id].getter
			case s := <-getSetter:
				s.response <- Things[s.id].setter
			}
		}
	}()
	return getGetter, getSetter, add, del
}
<|endoftext|>