<commit_before>package sxchange

import (
	"context"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"log"
	"net"
	"sync"
	"time"
	"unsafe"
)

const (
	verHI = 1
	verLO = 1
)

var (
	crc32q          = crc32.MakeTable(crc32.Koopman)
	errPartialWrite = errors.New("Partial write")
	errPartialRead  = errors.New("Partial read")
)

// CB type for callback function for each type of transfered data
type CB func([]byte, *Connection)

// DataTypeCB describes
type DataTypeCB struct {
	SizeBytes int8  // -1 for fixed size, 0 for no data (ping?), 1 for 0-255 bytes, 2 for 0-65535 bytes...
	FixedSize int32 // if some struct has fixed fize no other header needed
	Callback  CB    // which function to run after data received
}

// Connection informaion both for client or server
type Connection struct {
	conn           *net.TCPConn         // real connection
	AESKey         string               // AES-128/192/256 key in hex for connecton encryption
	eWriter        *cipher.StreamWriter // just StreamWriter object to simplify encryption
	eReader        *cipher.StreamReader // the same for reader
	writeMutex     sync.Mutex           // we need to lock on write operations
	Types          map[uint8]DataTypeCB // map of type->params&callback
	KeepAlive      time.Duration        // tcp keep-alive
	ReadTimeout    time.Duration        // we need to receive new message at least once per this duration
	WriteTimeout   time.Duration        // maximal duration for every write operation
	ConnectTimeout time.Duration        // maximum duration of net.Dial
	MaxSize        uint32               // maximum number of bytes for one record/message
	Ctx            context.Context      // context for some values like server id
	CloseChan      chan interface{}     // channel for closing incoming messages circle
}

const (
	initialPacketSize = 1292 // we need to compare it manualy to be sure that compiler doesn't change aligment!
)

type initialPacket struct {
	Header    [8]uint8 // sxchngXY where X.Y is version of protocol
	MaxSize   uint32
	SizeBytes [256]int8
	FixedSize [256]int32
}

func (c *Connection) readAll(buf []byte, size int, ne bool) error {

	totalDeadline := time.Now().Add(c.ReadTimeout)
	c.conn.SetReadDeadline(totalDeadline)

	var (
		i   int
		err error
	)

	if ne || nil == c.eReader {
		i, err = io.ReadFull(c.conn, buf[:size])
	} else {
		i, err = io.ReadFull(c.eReader, buf[:size])
	}

	if nil != err {
		return err
	}
	if i != size {
		return errPartialRead
	}

	return nil
}

func (c *Connection) writeAll(buf []byte, size int, ne bool) error {
	totalDeadline := time.Now().Add(c.WriteTimeout)
	c.conn.SetWriteDeadline(totalDeadline)

	var (
		i   int
		err error
	)

	if ne || nil == c.eWriter {
		i, err = c.conn.Write(buf[:size])
	} else {
		i, err = c.eWriter.Write(buf[:size])
	}

	if nil != err {
		return err
	}
	if i != size {
		return errPartialWrite
	}

	return nil
}

func (c *Connection) encSetup() error {
	if "" != c.AESKey {
		aesKey, err := hex.DecodeString(c.AESKey)
		if err != nil {
			return err
		}

		block, err := aes.NewCipher(aesKey)
		if err != nil {
			return err
		}

		var iv [aes.BlockSize]byte
		if _, err := io.ReadFull(rand.Reader, iv[:]); nil != err {
			return err
		}

		c.conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
		i, err := c.conn.Write(iv[:])
		if nil != err {
			return err
		}
		if i != len(iv) {
			return errPartialWrite
		}

		c.eWriter = &cipher.StreamWriter{S: cipher.NewCTR(block, iv[:]), W: c.conn}

		c.conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))

		var ivread [aes.BlockSize]byte

		i, err = io.ReadFull(c.conn, ivread[:])
		if nil != err {
			return err
		}
		if i != len(ivread) {
			return errPartialRead
		}

		c.eReader = &cipher.StreamReader{S: cipher.NewCTR(block, ivread[:]), R: c.conn}
	}

	return nil
}

func (c *Connection) initConnection() error {
	if c.KeepAlive != 0 {
		c.conn.SetKeepAlivePeriod(c.KeepAlive)
		c.conn.SetKeepAlive(true)
	}

	// initial packets exchange
	initial := c.prepareInitialPacket()
	initialBuf := (*[initialPacketSize]byte)(unsafe.Pointer(&initial))[:]
	received := initialPacket{}
	receivedBuf := (*[initialPacketSize]byte)(unsafe.Pointer(&received))[:]

	// send out version
	err := c.writeAll(initialBuf, initialPacketSize, true)
	if nil != err {
		return err
	}

	err = c.readAll(receivedBuf, initialPacketSize, true)
	if nil != err {
		return err
	}

	if received.Header != initial.Header {
		return errors.New("HS error - different protocol version")
	}

	if received.MaxSize != initial.MaxSize {
		return errors.New("HS error - different message maximal size")
	}

	if (received.FixedSize != initial.FixedSize) || (received.MaxSize != received.MaxSize) {
		return errors.New("HS error - different set of datatypes")
	}

	err = c.encSetup()
	if nil != err {
		return err
	}

	return nil
}

// internal run function
func (c *Connection) run() error {

	defer c.conn.Close()

	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in sxconnection.run", r)
		}
	}()

	var (
		sbuf [5]byte
		t    [1]byte
		msg  = make([]byte, 0, c.MaxSize)
		crcI uint32
		crcB = (*[4]byte)(unsafe.Pointer(&crcI))
	)

	for {

		select {
		case <-c.CloseChan:
			return nil
		default:
		}

		err := c.readAll(t[:], 1, false)
		if nil != err {
			return err
		}

		dt, ok := c.Types[t[0]]

		if !ok {
			return fmt.Errorf("Structure type %d is not defined", t[0])
		}

		var size2read int
		if dt.SizeBytes > 0 {
			err = c.readAll(sbuf[0:dt.SizeBytes], int(dt.SizeBytes), false)
			if nil != err {
				return err
			}
		}

		switch dt.SizeBytes {
		case -1:
			size2read = int(dt.FixedSize)
		case 0:
			size2read = 0
		case 1:
			size2read = int(sbuf[0])
		case 2:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8)
		case 3:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8) | (int(sbuf[2]) << 16)
		case 4:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8) | (int(sbuf[2]) << 16) | (int(sbuf[3]) << 24)
		default:
			return fmt.Errorf("Structure type %d has invalid SizeBytes setting (%d)", t[0], dt.SizeBytes)
		}

		if size2read > int(c.MaxSize) {
			return fmt.Errorf("Size of message is greater than maximum (%d/%d)", size2read, c.MaxSize)
		}

		err = c.readAll(msg, size2read, false)
		if nil != err {
			return err
		}

		// one more check on done channel - we don't want to call callback after it has been closed
		select {
		case <-c.CloseChan:
			return nil
		default:
		}

		if 0 != size2read {
			err = c.readAll((*crcB)[:], 4, false)
			if nil != err {
				return err
			}
			if crc32.Checksum(msg[0:size2read], crc32q) != crcI {
				return errors.New("crc failed on read")
			}
		}

		// we need to allow types that only can be send by one of the side, but also defined
		if nil != dt.Callback {
			dt.Callback(msg[0:size2read], c)
		}
	}
}

// WriteMsg creates header and then writes msg buffer via TCP connection
func (c *Connection) WriteMsg(msgType uint8, msg []byte) error {

	dt, ok := c.Types[msgType]
	if !ok {
		return fmt.Errorf("Unknown msg type %d", msgType)
	}

	var (
		crcI uint32
		crcB = (*[4]byte)(unsafe.Pointer(&crcI))
	)

	header := [6]byte{}
	header[0] = msgType

	size2write := 0
	headerSize := 1

	switch dt.SizeBytes {
	case -1:
		size2write = int(dt.FixedSize)
	case 0:
		size2write = 0
	case 1:
		if len(msg) > 255 {
			return fmt.Errorf("Structure type %d has 1-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg))
		size2write = len(msg)
		headerSize = 2
	case 2:
		if len(msg) > 255*255 {
			return fmt.Errorf("Structure type %d has 2-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		size2write = len(msg)
		headerSize = 3

	case 3:
		if len(msg) > 255*255*255 {
			return fmt.Errorf("Structure type %d has 3-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		header[3] = byte((len(msg) & 0xff0000) >> 16)
		size2write = len(msg)
		headerSize = 4

	case 4:
		if len(msg) > 255*255*255*255 {
			return fmt.Errorf("Structure type %d has 4-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		header[3] = byte((len(msg) & 0xff0000) >> 16)
		header[4] = byte((len(msg) & 0xff000000) >> 24)
		size2write = len(msg)
		headerSize = 5

	default:
		return fmt.Errorf("Structure type %d has invalid SizeBytes setting (%d)", msgType, dt.SizeBytes)
	}

	if size2write > len(msg) {
		return fmt.Errorf("Unable to write %d bytes for structure %d, have only %d in buffer", msgType, size2write, len(msg))
	}

	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()

	err := c.writeAll(header[:], headerSize, false)
	if nil != err {
		return err
	}

	err = c.writeAll(msg, size2write, false)
	if nil != err {
		return err
	}

	if size2write > 0 {
		crcI = crc32.Checksum(msg[0:size2write], crc32q)
		err = c.writeAll((*crcB)[:], 4, false)
		if nil != err {
			return err
		}
	}

	return nil
}

// Remote address retrive
func (c *Connection) Remote() net.Addr {
	if nil == c.conn {
		return nil
	}

	return c.conn.RemoteAddr()
}

func (c *Connection) prepareInitialPacket() initialPacket {
	result := initialPacket{MaxSize: c.MaxSize, Header: [8]byte{'s', 'x', 'c', 'h', 'n', 'g', verHI, verLO}}
	if "" != c.AESKey {
		result.Header[4] = 'E'
	}

	for i := 0; i < 256; i++ {
		result.FixedSize[i] = c.Types[uint8(i)].FixedSize
		result.SizeBytes[i] = c.Types[uint8(i)].SizeBytes
	}

	return result
}

func init() {
	if initialPacketSize != unsafe.Sizeof(initialPacket{}) {
		log.Fatalln("Golang uses different aligment withing structure, please modify sxchnge code!")
	}
}
<commit_msg>Make linter happy<commit_after>package sxchange

import (
	"context"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"log"
	"net"
	"sync"
	"time"
	"unsafe"
)

const (
	verHI = 1
	verLO = 1
)

var (
	crc32q          = crc32.MakeTable(crc32.Koopman)
	errPartialWrite = errors.New("partial write")
	errPartialRead  = errors.New("partial read")
)

// CB type for callback function for each type of transfered data
type CB func([]byte, *Connection)

// DataTypeCB describes
type DataTypeCB struct {
	SizeBytes int8  // -1 for fixed size, 0 for no data (ping?), 1 for 0-255 bytes, 2 for 0-65535 bytes...
	FixedSize int32 // if some struct has fixed fize no other header needed
	Callback  CB    // which function to run after data received
}

// Connection informaion both for client or server
type Connection struct {
	conn           *net.TCPConn         // real connection
	AESKey         string               // AES-128/192/256 key in hex for connecton encryption
	eWriter        *cipher.StreamWriter // just StreamWriter object to simplify encryption
	eReader        *cipher.StreamReader // the same for reader
	writeMutex     sync.Mutex           // we need to lock on write operations
	Types          map[uint8]DataTypeCB // map of type->params&callback
	KeepAlive      time.Duration        // tcp keep-alive
	ReadTimeout    time.Duration        // we need to receive new message at least once per this duration
	WriteTimeout   time.Duration        // maximal duration for every write operation
	ConnectTimeout time.Duration        // maximum duration of net.Dial
	MaxSize        uint32               // maximum number of bytes for one record/message
	Ctx            context.Context      // context for some values like server id
	CloseChan      chan interface{}     // channel for closing incoming messages circle
}

const (
	initialPacketSize = 1292 // we need to compare it manualy to be sure that compiler doesn't change aligment!
)

type initialPacket struct {
	Header    [8]uint8 // sxchngXY where X.Y is version of protocol
	MaxSize   uint32
	SizeBytes [256]int8
	FixedSize [256]int32
}

func (c *Connection) readAll(buf []byte, size int, ne bool) error {

	totalDeadline := time.Now().Add(c.ReadTimeout)
	c.conn.SetReadDeadline(totalDeadline)

	var (
		i   int
		err error
	)

	if ne || nil == c.eReader {
		i, err = io.ReadFull(c.conn, buf[:size])
	} else {
		i, err = io.ReadFull(c.eReader, buf[:size])
	}

	if nil != err {
		return err
	}
	if i != size {
		return errPartialRead
	}

	return nil
}

func (c *Connection) writeAll(buf []byte, size int, ne bool) error {
	totalDeadline := time.Now().Add(c.WriteTimeout)
	c.conn.SetWriteDeadline(totalDeadline)

	var (
		i   int
		err error
	)

	if ne || nil == c.eWriter {
		i, err = c.conn.Write(buf[:size])
	} else {
		i, err = c.eWriter.Write(buf[:size])
	}

	if nil != err {
		return err
	}
	if i != size {
		return errPartialWrite
	}

	return nil
}

func (c *Connection) encSetup() error {
	if c.AESKey != "" {
		aesKey, err := hex.DecodeString(c.AESKey)
		if err != nil {
			return err
		}

		block, err := aes.NewCipher(aesKey)
		if err != nil {
			return err
		}

		var iv [aes.BlockSize]byte
		if _, err := io.ReadFull(rand.Reader, iv[:]); nil != err {
			return err
		}

		c.conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
		i, err := c.conn.Write(iv[:])
		if nil != err {
			return err
		}
		if i != len(iv) {
			return errPartialWrite
		}

		c.eWriter = &cipher.StreamWriter{S: cipher.NewCTR(block, iv[:]), W: c.conn}

		c.conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))

		var ivread [aes.BlockSize]byte

		i, err = io.ReadFull(c.conn, ivread[:])
		if nil != err {
			return err
		}
		if i != len(ivread) {
			return errPartialRead
		}

		c.eReader = &cipher.StreamReader{S: cipher.NewCTR(block, ivread[:]), R: c.conn}
	}

	return nil
}

func (c *Connection) initConnection() error {
	if c.KeepAlive != 0 {
		c.conn.SetKeepAlivePeriod(c.KeepAlive)
		c.conn.SetKeepAlive(true)
	}

	// initial packets exchange
	initial := c.prepareInitialPacket()
	initialBuf := (*[initialPacketSize]byte)(unsafe.Pointer(&initial))[:]
	received := initialPacket{}
	receivedBuf := (*[initialPacketSize]byte)(unsafe.Pointer(&received))[:]

	// send out version
	err := c.writeAll(initialBuf, initialPacketSize, true)
	if nil != err {
		return err
	}

	err = c.readAll(receivedBuf, initialPacketSize, true)
	if nil != err {
		return err
	}

	if received.Header != initial.Header {
		return errors.New("HS error - different protocol version")
	}

	if received.MaxSize != initial.MaxSize {
		return errors.New("HS error - different message maximal size")
	}

	if (received.FixedSize != initial.FixedSize) || (received.MaxSize != initial.MaxSize) {
		return errors.New("HS error - different set of datatypes")
	}

	err = c.encSetup()
	if nil != err {
		return err
	}

	return nil
}

// internal run function
func (c *Connection) run() error {

	defer c.conn.Close()

	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in sxconnection.run", r)
		}
	}()

	var (
		sbuf [5]byte
		t    [1]byte
		msg  = make([]byte, 0, c.MaxSize)
		crcI uint32
		crcB = (*[4]byte)(unsafe.Pointer(&crcI))
	)

	for {

		select {
		case <-c.CloseChan:
			return nil
		default:
		}

		err := c.readAll(t[:], 1, false)
		if nil != err {
			return err
		}

		dt, ok := c.Types[t[0]]

		if !ok {
			return fmt.Errorf("structure type %d is not defined", t[0])
		}

		var size2read int
		if dt.SizeBytes > 0 {
			err = c.readAll(sbuf[0:dt.SizeBytes], int(dt.SizeBytes), false)
			if nil != err {
				return err
			}
		}

		switch dt.SizeBytes {
		case -1:
			size2read = int(dt.FixedSize)
		case 0:
			size2read = 0
		case 1:
			size2read = int(sbuf[0])
		case 2:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8)
		case 3:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8) | (int(sbuf[2]) << 16)
		case 4:
			size2read = int(sbuf[0]) | (int(sbuf[1]) << 8) | (int(sbuf[2]) << 16) | (int(sbuf[3]) << 24)
		default:
			return fmt.Errorf("structure type %d has invalid SizeBytes setting (%d)", t[0], dt.SizeBytes)
		}

		if size2read > int(c.MaxSize) {
			return fmt.Errorf("size of message is greater than maximum (%d/%d)", size2read, c.MaxSize)
		}

		err = c.readAll(msg, size2read, false)
		if nil != err {
			return err
		}

		// one more check on done channel - we don't want to call callback after it has been closed
		select {
		case <-c.CloseChan:
			return nil
		default:
		}

		if size2read != 0 {
			err = c.readAll((*crcB)[:], 4, false)
			if nil != err {
				return err
			}
			if crc32.Checksum(msg[0:size2read], crc32q) != crcI {
				return errors.New("crc failed on read")
			}
		}

		// we need to allow types that only can be send by one of the side, but also defined
		if nil != dt.Callback {
			dt.Callback(msg[0:size2read], c)
		}
	}
}

// WriteMsg creates header and then writes msg buffer via TCP connection
func (c *Connection) WriteMsg(msgType uint8, msg []byte) error {

	dt, ok := c.Types[msgType]
	if !ok {
		return fmt.Errorf("unknown msg type %d", msgType)
	}

	var (
		crcI uint32
		crcB = (*[4]byte)(unsafe.Pointer(&crcI))
	)

	header := [6]byte{}
	header[0] = msgType

	size2write := 0
	headerSize := 1

	switch dt.SizeBytes {
	case -1:
		size2write = int(dt.FixedSize)
	case 0:
		size2write = 0
	case 1:
		if len(msg) > 255 {
			return fmt.Errorf("structure type %d has 1-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg))
		size2write = len(msg)
		headerSize = 2
	case 2:
		if len(msg) > 255*255 {
			return fmt.Errorf("structure type %d has 2-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		size2write = len(msg)
		headerSize = 3

	case 3:
		if len(msg) > 255*255*255 {
			return fmt.Errorf("structure type %d has 3-byte size header but %d bytes givven", msgType, len(msg))
		}
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		header[3] = byte((len(msg) & 0xff0000) >> 16)
		size2write = len(msg)
		headerSize = 4

	case 4:
		header[1] = byte(len(msg) & 0xff)
		header[2] = byte((len(msg) & 0xff00) >> 8)
		header[3] = byte((len(msg) & 0xff0000) >> 16)
		header[4] = byte((len(msg) & 0xff000000) >> 24)
		size2write = len(msg)
		headerSize = 5

	default:
		return fmt.Errorf("structure type %d has invalid SizeBytes setting (%d)", msgType, dt.SizeBytes)
	}

	if size2write > len(msg) {
		return fmt.Errorf("unable to write %d bytes for structure %d, have only %d in buffer", msgType, size2write, len(msg))
	}

	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()

	err := c.writeAll(header[:], headerSize, false)
	if nil != err {
		return err
	}

	err = c.writeAll(msg, size2write, false)
	if nil != err {
		return err
	}

	if size2write > 0 {
		crcI = crc32.Checksum(msg[0:size2write], crc32q)
		err = c.writeAll((*crcB)[:], 4, false)
		if nil != err {
			return err
		}
	}

	return nil
}

// Remote address retrive
func (c *Connection) Remote() net.Addr {
	if nil == c.conn {
		return nil
	}

	return c.conn.RemoteAddr()
}

func (c *Connection) prepareInitialPacket() initialPacket {
	result := initialPacket{MaxSize: c.MaxSize, Header: [8]byte{'s', 'x', 'c', 'h', 'n', 'g', verHI, verLO}}
	if c.AESKey != "" {
		result.Header[4] = 'E'
	}

	for i := 0; i < 256; i++ {
		result.FixedSize[i] = c.Types[uint8(i)].FixedSize
		result.SizeBytes[i] = c.Types[uint8(i)].SizeBytes
	}

	return result
}

func init() {
	if initialPacketSize != unsafe.Sizeof(initialPacket{}) {
		log.Fatalln("Golang uses different aligment withing structure, please modify sxchnge code!")
	}
}
<|endoftext|>


<commit_before>package goproxmox

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

	"github.com/hashicorp/logutils"
)

const (
	libraryVersion  = "0.1.0"
	logLevelEnvName = "GOPROXMOX_LOGLEVEL"
	apiBasePath     = "/api2/json/"
	mediaType       = "application/json"
)

func init() {
	logLevel := os.Getenv(logLevelEnvName)
	if logLevel == "" {
		logLevel = "INFO"
	}

	filter := &logutils.LevelFilter{
		Levels:   []logutils.LogLevel{"DEBUG", "INFO"},
		MinLevel: logutils.LogLevel(logLevel),
		Writer:   os.Stderr,
	}
	log.SetOutput(filter)
}

// Client manages communication with proxmox API.
type Client struct {
	// HTTP client used to communicate with the proxmox API.
	client *http.Client

	// Base URL for API requests.
	BaseURL *url.URL

	// Control panel username
	Username string

	// Control panel password
	Password string

	Ticket    string
	CSRFToken string

	// Services used for communicating with the API
	Nodes NodesService
	VMs   QemuService

	// Optional function called after every successful request made to the proxmox API
	onRequestCompleted RequestCompletionCallback
}

// RequestCompletionCallback defines the type of the request callback function
type RequestCompletionCallback func(*http.Request, *http.Response)

// An ErrorResponse reports the error caused by an API request
type ErrorResponse struct {
	Success bool

	// HTTP response that caused this error
	Response *http.Response

	// Error message
	Message string `json:"ResultMessage"`

	// ResultCode returned from the API
	ResultCode int `json:"ResultCode"`
}

// NewClient returns a new proxmox API client.
func NewClient(host, username, password, ticket, csrfToken string) *Client {

	httpClient := http.DefaultClient

	apiServerBaseUrl := fmt.Sprintf("%s%s", host, apiBasePath)
	baseURL, _ := url.Parse(apiServerBaseUrl)

	c := &Client{client: httpClient, BaseURL: baseURL, Ticket: ticket, CSRFToken: csrfToken}

	log.Printf("[DEBUG] Base URL: %s\n", baseURL)

	c.Nodes = &NodesServiceOp{client: c}
	c.VMs = &QemuServiceOp{client: c}

	return c
}

// NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included in as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

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

	req.Header.Add("Content-Type", mediaType)
	req.Header.Add("Accept", mediaType)

	req.Header.Add("cookie", fmt.Sprintf("PVEAuthCookie=%s", c.Ticket)) // TODO: Make custom http client
	if method != "GET" {
		req.Header.Add("CSRFPreventionToken", c.CSRFToken)
	}

	return req, nil
}

// OnRequestCompleted sets the API request completion callback
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
	c.onRequestCompleted = rc
}

// Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value
// pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface,
// the raw response will be written to v, without attempting to decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	if c.onRequestCompleted != nil {
		c.onRequestCompleted(req, resp)
	}

	defer func() {
		if rerr := resp.Body.Close(); err == nil {
			err = rerr
		}
	}()
	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				return nil, err
			}
		} else {
			//bodyBytes, _ := ioutil.ReadAll(resp.Body)
			//log.Printf("[DEBUG] Response: %s\n", string(bodyBytes))
			err = json.NewDecoder(resp.Body).Decode(v)
			if err != nil {
				return nil, err
			}
		}
	}
	return resp, err
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%s. Result code: %d", r.Message, r.ResultCode)
}

// CheckResponse checks the API response for errors, and returns them if present. A response is considered an
// error if it has a status code outside the 200 range. API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; c >= 200 && c <= 299 {
		return nil
	}

	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && len(data) > 0 {
		err := json.Unmarshal(data, errorResponse)
		if err != nil {
			return err
		}
	}

	return errorResponse
}
<commit_msg>not using default httpClient<commit_after>package goproxmox

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

	"crypto/tls"

	"github.com/hashicorp/logutils"
)

const (
	libraryVersion  = "0.1.0"
	logLevelEnvName = "GOPROXMOX_LOGLEVEL"
	apiBasePath     = "/api2/json/"
	mediaType       = "application/json"
)

func init() {
	logLevel := os.Getenv(logLevelEnvName)
	if logLevel == "" {
		logLevel = "INFO"
	}

	filter := &logutils.LevelFilter{
		Levels:   []logutils.LogLevel{"DEBUG", "INFO"},
		MinLevel: logutils.LogLevel(logLevel),
		Writer:   os.Stderr,
	}
	log.SetOutput(filter)
}

// Client manages communication with proxmox API.
type Client struct {
	// HTTP client used to communicate with the proxmox API.
	client *http.Client

	// Base URL for API requests.
	BaseURL *url.URL

	// Control panel username
	Username string

	// Control panel password
	Password string

	Ticket    string
	CSRFToken string

	// Services used for communicating with the API
	Nodes NodesService
	VMs   QemuService

	// Optional function called after every successful request made to the proxmox API
	onRequestCompleted RequestCompletionCallback
}

// RequestCompletionCallback defines the type of the request callback function
type RequestCompletionCallback func(*http.Request, *http.Response)

// An ErrorResponse reports the error caused by an API request
type ErrorResponse struct {
	Success bool

	// HTTP response that caused this error
	Response *http.Response

	// Error message
	Message string `json:"ResultMessage"`

	// ResultCode returned from the API
	ResultCode int `json:"ResultCode"`
}

// NewClient returns a new proxmox API client.
func NewClient(host, username, password, ticket, csrfToken string) *Client {
	transport := &http.Transport{
		TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
	}
	httpClient := &http.Client{Transport: transport}

	apiServerBaseUrl := fmt.Sprintf("%s%s", host, apiBasePath)
	baseURL, _ := url.Parse(apiServerBaseUrl)

	c := &Client{client: httpClient, BaseURL: baseURL, Ticket: ticket, CSRFToken: csrfToken}

	log.Printf("[DEBUG] Base URL: %s\n", baseURL)

	c.Nodes = &NodesServiceOp{client: c}
	c.VMs = &QemuServiceOp{client: c}

	return c
}

// NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the
// value pointed to by body is JSON encoded and included in as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err = json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

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

	req.Header.Add("Content-Type", mediaType)
	req.Header.Add("Accept", mediaType)

	req.Header.Add("Cookie", fmt.Sprintf("PVEAuthCookie=%s", c.Ticket)) // TODO: Make custom http client
	if method != "GET" {
		req.Header.Add("CSRFPreventionToken", c.CSRFToken)
	}

	return req, nil
}

// OnRequestCompleted sets the API request completion callback
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
	c.onRequestCompleted = rc
}

// Do sends an API request and returns the API response. The API response is JSON decoded and stored in the value
// pointed to by v, or returned as an error if an API error has occurred. If v implements the io.Writer interface,
// the raw response will be written to v, without attempting to decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	if c.onRequestCompleted != nil {
		c.onRequestCompleted(req, resp)
	}

	defer func() {
		if rerr := resp.Body.Close(); err == nil {
			err = rerr
		}
	}()
	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			_, err = io.Copy(w, resp.Body)
			if err != nil {
				return nil, err
			}
		} else {
			//bodyBytes, _ := ioutil.ReadAll(resp.Body)
			//log.Printf("[DEBUG] Response: %s\n", string(bodyBytes))
			err = json.NewDecoder(resp.Body).Decode(v)
			if err != nil {
				return nil, err
			}
		}
	}
	return resp, err
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%s. Result code: %d", r.Message, r.ResultCode)
}

// CheckResponse checks the API response for errors, and returns them if present. A response is considered an
// error if it has a status code outside the 200 range. API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; c >= 200 && c <= 299 {
		return nil
	}

	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && len(data) > 0 {
		err := json.Unmarshal(data, errorResponse)
		if err != nil {
			return err
		}
	}

	return errorResponse
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	. "polydawn.net/pogo/gosh"
)

func main() {
	echo := Sh("echo")("-n", "-e")(DefaultIO)
	echo("wat\n", "\t\033[0;31mred and indented\033[0m\n")()

	// basic commands
	Sh("head")("--bytes=20", "/dev/zero")()

	// making your own shorthand
	aptget := Sh("apt-get")("install")
	aptyes := aptget("-y")
	// now `aptyes("git")` will install git and the `-y` argument means it will proceed automatically

	// we'll do shorthand for a shell, so we can use the shell's echo for the rest of the demo.
	shell := Sh("bash")("-c")

	// output rules
	shell("echo 'default output is quiet'")()    // gosh defaults to NullIO.
	shell(DefaultIO)("echo 'such a message!'")() // *now* your termnial gets it!
	shell = shell(DefaultIO)                     // let's always use DefaultIO now :)

	// environment rules
	shell("echo path=$PATH")()                           // your default env is retained
	shell(ClearEnv{})("echo path=$PATH")()               // unless you don't want that, of course
	shell(Env{"VAR": "59"})("echo some_var=$SOME_VAR")() // you can easily set an env var for just this command
	shell = shell(Env{"VAR": "59"})                      // or make any env var part of the command template (try it with $PATH -- no more bashrc needed every again!)

	// directing input and output
	cat := Sh("cat")
	catIn := cat.BakeArgs("-")
	catIn(Opts{In: "piping in things is easy!\n", Out: os.Stdout})()

	// collecting output

	// channelling output

	// changing the working directory

	// failed command automatically gets you the heck outta here

	// accepting exit codes
	shell(Env{"VAR": "59"})(Opts{OkExit: []int{59}})("exit $VAR")()
}
<commit_msg>fix unused var compile error in example.<commit_after>package main

import (
	"os"
	. "polydawn.net/pogo/gosh"
)

func main() {
	echo := Sh("echo")("-n", "-e")(DefaultIO)
	echo("wat\n", "\t\033[0;31mred and indented\033[0m\n")()

	// basic commands
	Sh("head")("--bytes=20", "/dev/zero")()

	// making your own shorthand
	aptget := Sh("apt-get")("install")
	aptyes := aptget("-y")
	// now `aptyes("git")` will install git and the `-y` argument means it will proceed automatically
	_ = aptyes

	// we'll do shorthand for a shell, so we can use the shell's echo for the rest of the demo.
	shell := Sh("bash")("-c")

	// output rules
	shell("echo 'default output is quiet'")()    // gosh defaults to NullIO.
	shell(DefaultIO)("echo 'such a message!'")() // *now* your termnial gets it!
	shell = shell(DefaultIO)                     // let's always use DefaultIO now :)

	// environment rules
	shell("echo path=$PATH")()                           // your default env is retained
	shell(ClearEnv{})("echo path=$PATH")()               // unless you don't want that, of course
	shell(Env{"VAR": "59"})("echo some_var=$SOME_VAR")() // you can easily set an env var for just this command
	shell = shell(Env{"VAR": "59"})                      // or make any env var part of the command template (try it with $PATH -- no more bashrc needed every again!)

	// directing input and output
	cat := Sh("cat")
	catIn := cat.BakeArgs("-")
	catIn(Opts{In: "piping in things is easy!\n", Out: os.Stdout})()

	// collecting output

	// channelling output

	// changing the working directory

	// failed command automatically gets you the heck outta here

	// accepting exit codes
	shell(Env{"VAR": "59"})(Opts{OkExit: []int{59}})("exit $VAR")()
}
<|endoftext|>


<commit_before>package gosseract

import (
  . "os"
  "os/exec"
  "io/ioutil"
  "bytes"
  "strings"
)

type AnywayArgs struct {
  SourcePath  string
  Destination string
}
var (
  TMPDIR = "/tmp"
  OUTEXT = ".txt"
  COMMAND = "tesseract"
  VERSION = "0.0.1"
)

func Greeting() string {
  return "Hello,Gosseract!"
}

/**
 * とにかくパラメータ喰わせて一発でOCRしたい場合の
 * コマンドラッパー
 */
func Anyway(args AnywayArgs) string {
  // 最終的な返り値
  out := ""

  // 引数で行き先を指定されない場合は
  // (とりあえず) `/tmp/anyway,txt`に置く
  // tesseractが標準出力に対応してるハズ
  // tesseractのバージョンを見るようなメソッドを用意しないとアカンなこれ
  if args.Destination == "" {
    args.Destination = TMPDIR + "/anyway"
  }

  // tesseractコマンドを実行
  command := exec.Command(COMMAND, args.SourcePath, args.Destination)
  e := command.Run()
  if e != nil {
    panic(e)
  }

  // 出力を読む
  // tesseractの出力はコマンドラインの第二引数に.txtを付けたものに置かれる
  fn := args.Destination + OUTEXT
  f, _ := OpenFile(fn, 1, 1)
  buf, _ := ioutil.ReadFile(f.Name())
  out = string(buf)

  return out
}

/**
 * privateなメソッドってどうやって定義するんだ？
 */
func getTesseractVersion() string {
  command := exec.Command(COMMAND, "--version")
  var stderr bytes.Buffer
  command.Stderr = &stderr //謎に標準エラーで来るw
  e := command.Run()
  if e != nil {
    panic(e)
  }
  // なんかクズい
  tesseractInfo := strings.Split(stderr.String(), " ")[1]
  return strings.TrimRight(tesseractInfo, "\n")
}
/**
 * 利用可能な言語の一覧を取得する
 */
func getAvailableLanguages() []string {
  command := exec.Command(COMMAND, "--list-langs")
  var stderr bytes.Buffer
  command.Stderr = &stderr //謎に標準エラーで来るw
  e := command.Run()
  if e != nil {
    panic(e)
  }
  langs := strings.Split(stderr.String(), "\n")
  langs = langs[1:len(langs) - 1]
  return langs
}
<commit_msg>Do not dirt global namespace<commit_after>package gosseract

import (
  "os"
  "os/exec"
  "io/ioutil"
  "bytes"
  "strings"
)

type AnywayArgs struct {
  SourcePath  string
  Destination string
}
var (
  TMPDIR = "/tmp"
  OUTEXT = ".txt"
  COMMAND = "tesseract"
  VERSION = "0.0.1"
)

func Greeting() string {
  return "Hello,Gosseract!"
}

/**
 * とにかくパラメータ喰わせて一発でOCRしたい場合の
 * コマンドラッパー
 */
func Anyway(args AnywayArgs) string {
  // 最終的な返り値
  out := ""

  // 引数で行き先を指定されない場合は
  // (とりあえず) `/tmp/anyway,txt`に置く
  // tesseractが標準出力に対応してるハズ
  // tesseractのバージョンを見るようなメソッドを用意しないとアカンなこれ
  if args.Destination == "" {
    args.Destination = TMPDIR + "/anyway"
  }

  // tesseractコマンドを実行
  command := exec.Command(COMMAND, args.SourcePath, args.Destination)
  e := command.Run()
  if e != nil {
    panic(e)
  }

  // 出力を読む
  // tesseractの出力はコマンドラインの第二引数に.txtを付けたものに置かれる
  fn := args.Destination + OUTEXT
  f, _ := os.OpenFile(fn, 1, 1)
  buf, _ := ioutil.ReadFile(f.Name())
  out = string(buf)

  return out
}

/**
 * privateなメソッドってどうやって定義するんだ？
 */
func getTesseractVersion() string {
  command := exec.Command(COMMAND, "--version")
  var stderr bytes.Buffer
  command.Stderr = &stderr //謎に標準エラーで来るw
  e := command.Run()
  if e != nil {
    panic(e)
  }
  // なんかクズい
  tesseractInfo := strings.Split(stderr.String(), " ")[1]
  return strings.TrimRight(tesseractInfo, "\n")
}
/**
 * 利用可能な言語の一覧を取得する
 */
func getAvailableLanguages() []string {
  command := exec.Command(COMMAND, "--list-langs")
  var stderr bytes.Buffer
  command.Stderr = &stderr //謎に標準エラーで来るw
  e := command.Run()
  if e != nil {
    panic(e)
  }
  langs := strings.Split(stderr.String(), "\n")
  langs = langs[1:len(langs) - 1]
  return langs
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package graph

import (
	"github.com/OWASP/Amass/v3/graphdb"
	"github.com/OWASP/Amass/v3/stringset"
	"github.com/OWASP/Amass/v3/viz"
)

// VizData returns the current state of the Graph as viz package Nodes and Edges.
func (g *Graph) VizData(uuid string) ([]viz.Node, []viz.Edge) {
	event, err := g.db.ReadNode(uuid, "event")
	if err != nil {
		return nil, nil
	}

	discovered, err := g.db.ReadOutEdges(event)
	if err != nil {
		return nil, nil
	}

	nodeIdx := make(map[string]int)
	nodes := g.vizNodes(uuid, discovered, nodeIdx)
	edges := g.vizEdges(nodes, nodeIdx)

	return nodes, edges
}

// Identify unique nodes that should be included in the visualization
func (g *Graph) vizNodes(uuid string, edges []*graphdb.Edge, nodeToIdx map[string]int) []viz.Node {
	var idx int
	var nodes []viz.Node
	ids := stringset.New()

	for _, d := range edges {
		if id := g.db.NodeToID(d.To); id != "" && !ids.Has(id) {
			ids.Insert(id)

			properties, err := g.db.ReadProperties(d.To, "type")
			if err != nil || len(properties) == 0 || properties[0].Value == "source" {
				continue
			}

			if g.IsTLDNode(id) {
				continue
			}

			if n := g.buildVizNode(d.To, properties[0].Value, uuid); n != nil {
				n.ID = idx
				// Keep track of which indices nodes were assigned to
				nodeToIdx[id] = idx
				idx++
				nodes = append(nodes, *n)
			}
		}
	}

	return nodes
}

// Identify the edges between nodes that should be included in the visualization
func (g *Graph) vizEdges(nodes []viz.Node, nodeToIdx map[string]int) []viz.Edge {
	var edges []viz.Edge

	for _, n := range nodes {
		node, err := g.db.ReadNode(n.Label, n.Type)
		if err != nil {
			continue
		}

		e, err := g.db.ReadOutEdges(node, "root", "cname_record",
			"a_record", "aaaa_record", "ptr_record", "service",
			"srv_record", "ns_record", "mx_record", "contains", "prefix")
		if err != nil || len(e) == 0 {
			continue
		}

		for _, edge := range e {
			if toID, found := nodeToIdx[g.db.NodeToID(edge.To)]; found {
				edges = append(edges, viz.Edge{
					From:  n.ID,
					To:    toID,
					Title: edge.Predicate,
				})
			}
		}
	}

	return edges
}

func (g *Graph) buildVizNode(node graphdb.Node, ntype, uuid string) *viz.Node {
	id := g.db.NodeToID(node)

	edges, err := g.db.ReadInEdges(node)
	if err != nil && len(edges) == 0 {
		return nil
	}

	var sources []string
	// Select one of the data sources to be used in the visualization
	for _, edge := range edges {
		if g.db.NodeToID(edge.From) == uuid {
			sources = append(sources, edge.Predicate)
		}
	}

	if len(sources) == 0 {
		return nil
	}
	src := sources[randomIndex(len(sources))]

	ntype = g.convertNodeType(id, ntype, edges)

	title := ntype + ": " + id
	if ntype == "as" {
		title = title + ", Desc: " + g.ReadASDescription(id)
	}

	return &viz.Node{
		Type:   ntype,
		Label:  id,
		Title:  title,
		Source: src,
	}
}

// Update the type names for visualization
func (g *Graph) convertNodeType(id, ntype string, edges []*graphdb.Edge) string {
	if ntype == "fqdn" {
		var pred string
		// Look for edge predicates of interest
		for _, edge := range edges {
			if edge.Predicate == "root" ||
				edge.Predicate == "mx_record" ||
				edge.Predicate == "ns_record" {
				pred = edge.Predicate
				break
			}
		}

		if pred != "" {
			switch pred {
			case "root":
				ntype = "domain"
			case "ns_record":
				ntype = "ns"
			case "mx_record":
				ntype = "mx"
			}
		} else if g.IsPTRNode(id) {
			ntype = "ptr"
		} else {
			ntype = "subdomain"
		}
	} else if ntype == "ipaddr" {
		ntype = "address"
	}

	return ntype
}
<commit_msg>made some small fixes<commit_after>// Copyright 2017-2020 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package graph

import (
	"github.com/OWASP/Amass/v3/graphdb"
	"github.com/OWASP/Amass/v3/stringset"
	"github.com/OWASP/Amass/v3/viz"
)

// VizData returns the current state of the Graph as viz package Nodes and Edges.
func (g *Graph) VizData(uuid string) ([]viz.Node, []viz.Edge) {
	event, err := g.db.ReadNode(uuid, "event")
	if err != nil {
		return nil, nil
	}

	discovered, err := g.db.ReadOutEdges(event)
	if err != nil {
		return nil, nil
	}

	nodes, nodeIdx := g.vizNodes(uuid, discovered)
	edges := g.vizEdges(nodes, nodeIdx)

	return nodes, edges
}

// Identify unique nodes that should be included in the visualization
func (g *Graph) vizNodes(uuid string, edges []*graphdb.Edge) ([]viz.Node, map[string]int) {
	var idx int
	var nodes []viz.Node
	ids := stringset.New()
	nodeToIdx := make(map[string]int)

	for _, d := range edges {
		if id := g.db.NodeToID(d.To); id != "" && !ids.Has(id) {
			ids.Insert(id)

			properties, err := g.db.ReadProperties(d.To, "type")
			// We do not print the source nodes in the graph visualizations
			if err != nil || len(properties) == 0 || properties[0].Value == "source" {
				continue
			}

			// We do not print the TLD nodes in the graph visualizations
			if g.IsTLDNode(id) {
				continue
			}

			if n := g.buildVizNode(d.To, properties[0].Value, uuid); n != nil {
				n.ID = idx
				// Keep track of which indices nodes were assigned to
				nodeToIdx[id] = idx
				idx++
				nodes = append(nodes, *n)
			}
		}
	}

	return nodes, nodeToIdx
}

// Identify the edges between nodes that should be included in the visualization
func (g *Graph) vizEdges(nodes []viz.Node, nodeToIdx map[string]int) []viz.Edge {
	var edges []viz.Edge

	for _, n := range nodes {
		node, err := g.db.ReadNode(n.Label, n.ActualType)
		if err != nil {
			continue
		}

		e, err := g.db.ReadOutEdges(node, "root", "cname_record",
			"a_record", "aaaa_record", "ptr_record", "service",
			"srv_record", "ns_record", "mx_record", "contains", "prefix")
		if err != nil || len(e) == 0 {
			continue
		}

		for _, edge := range e {
			if toID, found := nodeToIdx[g.db.NodeToID(edge.To)]; found {
				edges = append(edges, viz.Edge{
					From:  n.ID,
					To:    toID,
					Title: edge.Predicate,
				})
			}
		}
	}

	return edges
}

func (g *Graph) buildVizNode(node graphdb.Node, ntype, uuid string) *viz.Node {
	id := g.db.NodeToID(node)

	edges, err := g.db.ReadInEdges(node)
	if err != nil && len(edges) == 0 {
		return nil
	}

	var sources []string
	// Select one of the data sources to be used in the visualization
	for _, edge := range edges {
		if g.db.NodeToID(edge.From) == uuid {
			sources = append(sources, edge.Predicate)
		}
	}

	if len(sources) == 0 {
		return nil
	}
	src := sources[randomIndex(len(sources))]

	newtype := g.convertNodeType(id, ntype, edges)

	title := newtype + ": " + id
	if newtype == "as" {
		title = title + ", Desc: " + g.ReadASDescription(id)
	}

	return &viz.Node{
		Type:       newtype,
		Label:      id,
		Title:      title,
		Source:     src,
		ActualType: ntype,
	}
}

// Update the type names for visualization
func (g *Graph) convertNodeType(id, ntype string, edges []*graphdb.Edge) string {
	if ntype == "fqdn" {
		var pred string

		// Look for edge predicates of interest
		for _, edge := range edges {
			if edge.Predicate == "root" ||
				edge.Predicate == "mx_record" ||
				edge.Predicate == "ns_record" {
				pred = edge.Predicate
				break
			}
		}

		if pred != "" {
			switch pred {
			case "root":
				ntype = "domain"
			case "ns_record":
				ntype = "ns"
			case "mx_record":
				ntype = "mx"
			}
		} else if g.IsPTRNode(id) {
			ntype = "ptr"
		} else {
			ntype = "subdomain"
		}
	} else if ntype == "ipaddr" {
		ntype = "address"
	}

	return ntype
}
<|endoftext|>


<commit_before>package testutils

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"
	"time"

	"github.com/cozy/checkup"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/globals"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/stack"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/errors"
	"github.com/labstack/echo"
)

// Fatal prints a message and immediately exit the process
func Fatal(msg ...interface{}) {
	fmt.Println(msg...)
	os.Exit(1)
}

// NeedCouchdb kill the process if there is no couchdb running
func NeedCouchdb() {
	db, err := checkup.HTTPChecker{URL: config.CouchURL().String()}.Check()
	if err != nil || db.Status() != checkup.Healthy {
		Fatal("This test need couchdb to run.")
	}
}

// TestSetup is a wrapper around a testing.M which handles
// setting up instance, client, VFSContext, testserver
// and cleaning up after itself
type TestSetup struct {
	testingM *testing.M
	name     string
	host     string
	inst     *instance.Instance
	ts       *httptest.Server
	cleanup  func()
}

// NewSetup returns a new TestSetup
// name is used to prevent bug when tests are run in parallel
func NewSetup(testingM *testing.M, name string) *TestSetup {
	setup := TestSetup{
		name:     name,
		testingM: testingM,
		host:     name + "_" + utils.RandomString(10) + ".cozy.local",
		cleanup:  func() {},
	}

	return &setup
}

// CleanupAndDie cleanup the TestSetup, prints a message and 	close the process
func (c *TestSetup) CleanupAndDie(msg ...interface{}) {
	c.cleanup()
	Fatal(msg...)
}

// Cleanup cleanup the TestSetup
func (c *TestSetup) Cleanup() {
	c.cleanup()
}

// AddCleanup adds a function to be run when the test is finished.
func (c *TestSetup) AddCleanup(f func() error) {
	next := c.cleanup
	c.cleanup = func() {
		err := f()
		if err != nil {
			fmt.Println("Error while cleanup", err)
		}
		next()
	}
}

// GetTmpDirectory creates a temporary directory
// The directory will be removed on container cleanup
func (c *TestSetup) GetTmpDirectory() string {
	tempdir, err := ioutil.TempDir("", "cozy-stack")
	if err != nil {
		c.CleanupAndDie("Could not create temporary directory.", err)
	}
	c.AddCleanup(func() error { return os.RemoveAll(tempdir) })
	return tempdir
}

// GetTestInstance creates an instance with a random host
// The instance will be removed on container cleanup
func (c *TestSetup) GetTestInstance(opts ...*instance.Options) *instance.Instance {
	if c.inst != nil {
		return c.inst
	}
	b, s, _, err := stack.Start()
	if err != nil {
		c.CleanupAndDie("Error while starting job system", err)
	}
	globals.Set(b, s)
	if len(opts) == 0 {
		opts = []*instance.Options{{}}
	}
	if opts[0].Domain == "" {
		opts[0].Domain = c.host
	} else {
		c.host = opts[0].Domain
	}
	err = instance.Destroy(c.host)
	if err != nil && err != instance.ErrNotFound {
		c.CleanupAndDie("Error while destroying instance", err)
	}
	i, err := instance.Create(opts[0])

	if err != nil {
		c.CleanupAndDie("Cannot create test instance", err)
	}
	c.AddCleanup(func() error { err := instance.Destroy(i.Domain); return err })
	c.inst = i
	return i
}

// GetTestClient creates an oauth client and associated token
func (c *TestSetup) GetTestClient(scopes string) (*oauth.Client, string) {
	inst := c.GetTestInstance()
	client := oauth.Client{
		RedirectURIs: []string{"http://localhost/oauth/callback"},
		ClientName:   "client-" + c.host,
		SoftwareID:   "github.com/cozy/cozy-stack/testing/" + c.name,
	}
	client.Create(inst)
	token, err := c.inst.MakeJWT(permissions.AccessTokenAudience,
		client.ClientID, scopes, "", time.Now())

	if err != nil {
		c.CleanupAndDie("Cannot create oauth token", err)
	}

	return &client, token
}

// GetTestServer start a testServer with a single group on prefix
// The server will be closed on container cleanup
func (c *TestSetup) GetTestServer(prefix string, routes func(*echo.Group),
	mws ...func(*echo.Echo) *echo.Echo) *httptest.Server {
	return c.GetTestServerMultipleRoutes(map[string]func(*echo.Group){prefix: routes}, mws...)
}

// GetTestServerMultipleRoutes starts a testServer and creates a group for each
// pair of (prefix, routes) given.
// The server will be closed on container cleanup.
func (c *TestSetup) GetTestServerMultipleRoutes(mpr map[string]func(*echo.Group), mws ...func(*echo.Echo) *echo.Echo) *httptest.Server {
	handler := echo.New()

	for prefix, routes := range mpr {
		group := handler.Group(prefix, func(next echo.HandlerFunc) echo.HandlerFunc {
			return func(context echo.Context) error {
				context.Set("instance", c.inst)
				return next(context)
			}
		})

		routes(group)
	}

	for _, mw := range mws {
		handler = mw(handler)
	}
	handler.HTTPErrorHandler = errors.ErrorHandler
	ts := httptest.NewServer(handler)
	c.AddCleanup(func() error { ts.Close(); return nil })
	c.ts = ts
	return ts
}

// Run runs the underlying testing.M and cleanup
func (c *TestSetup) Run() int {
	value := c.testingM.Run()
	c.cleanup()
	return value
}

// CookieJar is a http.CookieJar which always returns all cookies.
// NOTE golang stdlib uses cookies for the URL (ie the testserver),
// not for the host (ie the instance), so we do it manually
type CookieJar struct {
	Jar *cookiejar.Jar
	URL *url.URL
}

// Cookies implements http.CookieJar interface
func (j *CookieJar) Cookies(u *url.URL) (cookies []*http.Cookie) {
	return j.Jar.Cookies(j.URL)
}

// SetCookies implements http.CookieJar interface
func (j *CookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
	j.Jar.SetCookies(j.URL, cookies)
}

// GetCookieJar returns a cookie jar valable for test
// the jar discard the url passed to Cookies and SetCookies and always use
// the setup instance URL instead.
func (c *TestSetup) GetCookieJar() http.CookieJar {
	instance := c.GetTestInstance()
	instanceURL, err := url.Parse("https://" + instance.Domain + "/")
	if err != nil {
		c.CleanupAndDie("Cant create cookie jar url", err)
	}
	j, err := cookiejar.New(nil)
	if err != nil {
		c.CleanupAndDie("Cant create cookie jar", err)
	}
	return &CookieJar{
		Jar: j,
		URL: instanceURL,
	}
}

// func resetDBAndViews(db couchdb.Database, doctype string) error {
// 	if err := couchdb.ResetDB(db, doctype); err != nil {
// 		return err
// 	}
//
// 	if err := couchdb.DefineIndexes(db, consts.IndexesByDoctype(doctype)); err != nil {
// 		return err
// 	}
//
// 	if err := couchdb.DefineViews(db, consts.ViewsByDoctype(doctype)); err != nil {
// 		return err
// 	}
//
// 	return nil
// }
//
// func (c *TestSetup) GetCleanDB(db couchdb.Database, doctype string) {
// 	err := resetDBAndViews()
// 	if err != nil {
// 		c.CleanupAndDie(err)
// 	}
// 	c.addCleanup(func() { couchdb.DeleteDB(db, doctype) })
//
// }
<commit_msg>Remove dead code<commit_after>package testutils

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/http/httptest"
	"net/url"
	"os"
	"testing"
	"time"

	"github.com/cozy/checkup"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/globals"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/stack"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/errors"
	"github.com/labstack/echo"
)

// Fatal prints a message and immediately exit the process
func Fatal(msg ...interface{}) {
	fmt.Println(msg...)
	os.Exit(1)
}

// NeedCouchdb kill the process if there is no couchdb running
func NeedCouchdb() {
	db, err := checkup.HTTPChecker{URL: config.CouchURL().String()}.Check()
	if err != nil || db.Status() != checkup.Healthy {
		Fatal("This test need couchdb to run.")
	}
}

// TestSetup is a wrapper around a testing.M which handles
// setting up instance, client, VFSContext, testserver
// and cleaning up after itself
type TestSetup struct {
	testingM *testing.M
	name     string
	host     string
	inst     *instance.Instance
	ts       *httptest.Server
	cleanup  func()
}

// NewSetup returns a new TestSetup
// name is used to prevent bug when tests are run in parallel
func NewSetup(testingM *testing.M, name string) *TestSetup {
	setup := TestSetup{
		name:     name,
		testingM: testingM,
		host:     name + "_" + utils.RandomString(10) + ".cozy.local",
		cleanup:  func() {},
	}

	return &setup
}

// CleanupAndDie cleanup the TestSetup, prints a message and 	close the process
func (c *TestSetup) CleanupAndDie(msg ...interface{}) {
	c.cleanup()
	Fatal(msg...)
}

// Cleanup cleanup the TestSetup
func (c *TestSetup) Cleanup() {
	c.cleanup()
}

// AddCleanup adds a function to be run when the test is finished.
func (c *TestSetup) AddCleanup(f func() error) {
	next := c.cleanup
	c.cleanup = func() {
		err := f()
		if err != nil {
			fmt.Println("Error while cleanup", err)
		}
		next()
	}
}

// GetTmpDirectory creates a temporary directory
// The directory will be removed on container cleanup
func (c *TestSetup) GetTmpDirectory() string {
	tempdir, err := ioutil.TempDir("", "cozy-stack")
	if err != nil {
		c.CleanupAndDie("Could not create temporary directory.", err)
	}
	c.AddCleanup(func() error { return os.RemoveAll(tempdir) })
	return tempdir
}

// GetTestInstance creates an instance with a random host
// The instance will be removed on container cleanup
func (c *TestSetup) GetTestInstance(opts ...*instance.Options) *instance.Instance {
	if c.inst != nil {
		return c.inst
	}
	b, s, _, err := stack.Start()
	if err != nil {
		c.CleanupAndDie("Error while starting job system", err)
	}
	globals.Set(b, s)
	if len(opts) == 0 {
		opts = []*instance.Options{{}}
	}
	if opts[0].Domain == "" {
		opts[0].Domain = c.host
	} else {
		c.host = opts[0].Domain
	}
	err = instance.Destroy(c.host)
	if err != nil && err != instance.ErrNotFound {
		c.CleanupAndDie("Error while destroying instance", err)
	}
	i, err := instance.Create(opts[0])

	if err != nil {
		c.CleanupAndDie("Cannot create test instance", err)
	}
	c.AddCleanup(func() error { err := instance.Destroy(i.Domain); return err })
	c.inst = i
	return i
}

// GetTestClient creates an oauth client and associated token
func (c *TestSetup) GetTestClient(scopes string) (*oauth.Client, string) {
	inst := c.GetTestInstance()
	client := oauth.Client{
		RedirectURIs: []string{"http://localhost/oauth/callback"},
		ClientName:   "client-" + c.host,
		SoftwareID:   "github.com/cozy/cozy-stack/testing/" + c.name,
	}
	client.Create(inst)
	token, err := c.inst.MakeJWT(permissions.AccessTokenAudience,
		client.ClientID, scopes, "", time.Now())

	if err != nil {
		c.CleanupAndDie("Cannot create oauth token", err)
	}

	return &client, token
}

// GetTestServer start a testServer with a single group on prefix
// The server will be closed on container cleanup
func (c *TestSetup) GetTestServer(prefix string, routes func(*echo.Group),
	mws ...func(*echo.Echo) *echo.Echo) *httptest.Server {
	return c.GetTestServerMultipleRoutes(map[string]func(*echo.Group){prefix: routes}, mws...)
}

// GetTestServerMultipleRoutes starts a testServer and creates a group for each
// pair of (prefix, routes) given.
// The server will be closed on container cleanup.
func (c *TestSetup) GetTestServerMultipleRoutes(mpr map[string]func(*echo.Group), mws ...func(*echo.Echo) *echo.Echo) *httptest.Server {
	handler := echo.New()

	for prefix, routes := range mpr {
		group := handler.Group(prefix, func(next echo.HandlerFunc) echo.HandlerFunc {
			return func(context echo.Context) error {
				context.Set("instance", c.inst)
				return next(context)
			}
		})

		routes(group)
	}

	for _, mw := range mws {
		handler = mw(handler)
	}
	handler.HTTPErrorHandler = errors.ErrorHandler
	ts := httptest.NewServer(handler)
	c.AddCleanup(func() error { ts.Close(); return nil })
	c.ts = ts
	return ts
}

// Run runs the underlying testing.M and cleanup
func (c *TestSetup) Run() int {
	value := c.testingM.Run()
	c.cleanup()
	return value
}

// CookieJar is a http.CookieJar which always returns all cookies.
// NOTE golang stdlib uses cookies for the URL (ie the testserver),
// not for the host (ie the instance), so we do it manually
type CookieJar struct {
	Jar *cookiejar.Jar
	URL *url.URL
}

// Cookies implements http.CookieJar interface
func (j *CookieJar) Cookies(u *url.URL) (cookies []*http.Cookie) {
	return j.Jar.Cookies(j.URL)
}

// SetCookies implements http.CookieJar interface
func (j *CookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
	j.Jar.SetCookies(j.URL, cookies)
}

// GetCookieJar returns a cookie jar valable for test
// the jar discard the url passed to Cookies and SetCookies and always use
// the setup instance URL instead.
func (c *TestSetup) GetCookieJar() http.CookieJar {
	instance := c.GetTestInstance()
	instanceURL, err := url.Parse("https://" + instance.Domain + "/")
	if err != nil {
		c.CleanupAndDie("Cant create cookie jar url", err)
	}
	j, err := cookiejar.New(nil)
	if err != nil {
		c.CleanupAndDie("Cant create cookie jar", err)
	}
	return &CookieJar{
		Jar: j,
		URL: instanceURL,
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 The cef2go authors. All rights reserved.
// License: BSD 3-clause.
// Website: https://github.com/CzarekTomczak/cef2go

package cef

/*
CEF capi fixes
--------------

In cef_string.h:
this => typedef cef_string_utf16_t cef_string_t;
to => #define cef_string_t cef_string_utf16_t

Sandbox functions aren't available in capi. Defined them
in the comment above the import "C".

*/

/*
#cgo CFLAGS: -I./../../
#cgo LDFLAGS: -L./../../Release -llibcef
#include <stdlib.h>
#include "include/capi/cef_app_capi.h"
void* cef_sandbox_info_create();
void cef_sandbox_info_destroy(void* sandbox_info);
*/
import "C"
import "unsafe"
import "os"
import "fmt"
import "syscall"
import "runtime"

type Settings struct {
    CachePath string
    LogSeverity int
}

type BrowserSettings struct {
}

var g_mainArgs C.struct__cef_main_args_t
var g_app C.cef_app_t // needs reference counting
var g_clientHandler C.struct__cef_client_t // needs reference counting

// Sandbox is disabled. Including the "cef_sandbox.lib"
// library results in lots of GCC warnings/errors. It is
// compatible only with VS 2010. It would be required to
// build it using GCC. Add -lcef_sandbox to LDFLAGS.
var g_sandboxInfo unsafe.Pointer = nil

const (
    LOGSEVERITY_DEFAULT = C.LOGSEVERITY_DEFAULT
    LOGSEVERITY_VERBOSE = C.LOGSEVERITY_VERBOSE
    LOGSEVERITY_INFO = C.LOGSEVERITY_INFO
    LOGSEVERITY_WARNING = C.LOGSEVERITY_WARNING
    LOGSEVERITY_ERROR = C.LOGSEVERITY_ERROR
    LOGSEVERITY_ERROR_REPORT = C.LOGSEVERITY_ERROR_REPORT
    LOGSEVERITY_DISABLE = C.LOGSEVERITY_DISABLE
)

func ExecuteProcess(appHandle syscall.Handle) {
    g_mainArgs.instance = (C.HINSTANCE)(unsafe.Pointer(appHandle))

    // Sandbox info needs to be passed to both cef_execute_process()
    // and cef_initialize().
    // OFF: g_sandboxInfo = C.cef_sandbox_info_create()

    var exitCode C.int = C.cef_execute_process(&g_mainArgs, nil,
            g_sandboxInfo)
    if (exitCode >= 0) {
        os.Exit(int(exitCode))
    }
}

func Initialize(settings Settings) {
    var cefSettings C.struct__cef_settings_t

    // cache_path
    var cachePath *C.char = C.CString(settings.CachePath)
    defer C.free(unsafe.Pointer(cachePath))
    C.cef_string_from_utf8(cachePath, C.strlen(cachePath),
            &cefSettings.cache_path)

    // log_severity
    cefSettings.log_severity =
            (C.cef_log_severity_t)(C.int(settings.LogSeverity))

    ret := C.cef_initialize(&g_mainArgs, &cefSettings, nil, g_sandboxInfo)
    fmt.Printf("cef2go: cef_initialize() returned %v\n", ret)
}

func CreateBrowser(hwnd syscall.Handle, settings BrowserSettings,
        url string) {
    var rect C.RECT
    if (runtime.GOOS == "windows") {
        var result C.BOOL = C.GetWindowRect(
                (C.HWND)(unsafe.Pointer(hwnd)),
                (*C.struct_tagRECT)(unsafe.Pointer(&rect)))
        if (int(result) == 0) {
            fmt.Printf("cef2go: CreateBrowser(): GetWindowRect() failed")
            return
        }
    } else {
        fmt.Printf("cef2go: CreateBrowser(): Unsupported OS\n")
        os.Exit(1)
    }

    // windowInfo
    var windowInfo C.cef_window_info_t
    if (runtime.GOOS == "windows") {
        windowInfo.style = C.WS_CHILD | C.WS_CLIPCHILDREN | C.WS_CLIPSIBLINGS |
                C.WS_TABSTOP | C.WS_VISIBLE
    } else {
        fmt.Printf("cef2go: CreateBrowser(): Unsupported OS\n")
        os.Exit(1)
    }
    windowInfo.parent_window = (C.HWND)(unsafe.Pointer(hwnd))
    windowInfo.x = C.int(rect.left)
    windowInfo.y = C.int(rect.top)
    windowInfo.width = C.int(rect.right - rect.left)
    windowInfo.height = C.int(rect.bottom - rect.top)

    // url
    var cefUrl C.cef_string_t
    var charUrl *C.char = C.CString(url)
    defer C.free(unsafe.Pointer(charUrl))
    C.cef_string_from_utf8(charUrl, C.strlen(charUrl), &cefUrl)

    // create browser
    var cefSettings C.struct__cef_browser_settings_t

    // TODO: reference counting, see:
    // https://code.google.com/p/chromiumembedded/wiki/UsingTheCAPI
    // --
    // What about C struct alignment issues in Go?
    // var refcnt unsafe.Pointer = unsafe.Pointer(&g_clientHandler)
    // refcnt += (unsafe.Pointer)(unsafe.Sizeof(g_clientHandler[0]))
    // C.InterlockedIncrement(refcnt)
    // C.InterlockedIncrement(&g_clientHandler{0})
    // C.InterlockedDecrement()
    // --

    // Must call synchronously so that a call to WindowResize()
    // works, after this function returns.
    C.cef_browser_host_create_browser_sync(&windowInfo, nil, &cefUrl,
            &cefSettings, nil)
}

func RunMessageLoop() {
    C.cef_run_message_loop()
}

func QuitMessageLoop() {
    C.cef_quit_message_loop()
}

func Shutdown() {
    C.cef_shutdown()
    // OFF: cef_sandbox_info_destroy(g_sandboxInfo)
}

func WindowResized(hwnd syscall.Handle) {
    var rect C.RECT;
    C.GetClientRect(
            (C.HWND)(unsafe.Pointer(hwnd)),
            (*C.struct_tagRECT)(unsafe.Pointer(&rect)))
    var hdwp C.HDWP = C.BeginDeferWindowPos(1)
    var cefHwnd C.HWND = C.GetWindow(
            (C.HWND)(unsafe.Pointer(hwnd)), C.GW_CHILD)
    hdwp = C.DeferWindowPos(hdwp, cefHwnd, nil,
            C.int(rect.left), C.int(rect.top),
            C.int(rect.right - rect.left),
            C.int(rect.bottom - rect.top),
            C.SWP_NOZORDER)
    C.EndDeferWindowPos(hdwp)
}
<commit_msg>Changes sandbox info comments.<commit_after>// Copyright (c) 2014 The cef2go authors. All rights reserved.
// License: BSD 3-clause.
// Website: https://github.com/CzarekTomczak/cef2go

package cef

/*
CEF capi fixes
--------------

In cef_string.h:
this => typedef cef_string_utf16_t cef_string_t;
to => #define cef_string_t cef_string_utf16_t

*/

/*
#cgo CFLAGS: -I./../../
#cgo LDFLAGS: -L./../../Release -llibcef
#include <stdlib.h>
#include "include/capi/cef_app_capi.h"
*/
import "C"
import "unsafe"
import "os"
import "fmt"
import "syscall"
import "runtime"

type Settings struct {
    CachePath string
    LogSeverity int
}

type BrowserSettings struct {
}

var g_mainArgs C.struct__cef_main_args_t
var g_app C.cef_app_t // needs reference counting
var g_clientHandler C.struct__cef_client_t // needs reference counting

// Sandbox is disabled. Including the "cef_sandbox.lib"
// library results in lots of GCC warnings/errors. It is
// compatible only with VS 2010. It would be required to
// build it using GCC. Add -lcef_sandbox to LDFLAGS.
// capi doesn't expose sandbox functions, you need do add
// these before import "C":
// void* cef_sandbox_info_create();
// void cef_sandbox_info_destroy(void* sandbox_info);
var g_sandboxInfo unsafe.Pointer = nil

const (
    LOGSEVERITY_DEFAULT = C.LOGSEVERITY_DEFAULT
    LOGSEVERITY_VERBOSE = C.LOGSEVERITY_VERBOSE
    LOGSEVERITY_INFO = C.LOGSEVERITY_INFO
    LOGSEVERITY_WARNING = C.LOGSEVERITY_WARNING
    LOGSEVERITY_ERROR = C.LOGSEVERITY_ERROR
    LOGSEVERITY_ERROR_REPORT = C.LOGSEVERITY_ERROR_REPORT
    LOGSEVERITY_DISABLE = C.LOGSEVERITY_DISABLE
)

func ExecuteProcess(appHandle syscall.Handle) {
    g_mainArgs.instance = (C.HINSTANCE)(unsafe.Pointer(appHandle))

    // Sandbox info needs to be passed to both cef_execute_process()
    // and cef_initialize().
    // OFF: g_sandboxInfo = C.cef_sandbox_info_create()

    var exitCode C.int = C.cef_execute_process(&g_mainArgs, nil,
            g_sandboxInfo)
    if (exitCode >= 0) {
        os.Exit(int(exitCode))
    }
}

func Initialize(settings Settings) {
    var cefSettings C.struct__cef_settings_t

    // cache_path
    var cachePath *C.char = C.CString(settings.CachePath)
    defer C.free(unsafe.Pointer(cachePath))
    C.cef_string_from_utf8(cachePath, C.strlen(cachePath),
            &cefSettings.cache_path)

    // log_severity
    cefSettings.log_severity =
            (C.cef_log_severity_t)(C.int(settings.LogSeverity))

    ret := C.cef_initialize(&g_mainArgs, &cefSettings, nil, g_sandboxInfo)
    fmt.Printf("cef2go: cef_initialize() returned %v\n", ret)
}

func CreateBrowser(hwnd syscall.Handle, settings BrowserSettings,
        url string) {
    var rect C.RECT
    if (runtime.GOOS == "windows") {
        var result C.BOOL = C.GetWindowRect(
                (C.HWND)(unsafe.Pointer(hwnd)),
                (*C.struct_tagRECT)(unsafe.Pointer(&rect)))
        if (int(result) == 0) {
            fmt.Printf("cef2go: CreateBrowser(): GetWindowRect() failed")
            return
        }
    } else {
        fmt.Printf("cef2go: CreateBrowser(): Unsupported OS\n")
        os.Exit(1)
    }

    // windowInfo
    var windowInfo C.cef_window_info_t
    if (runtime.GOOS == "windows") {
        windowInfo.style = C.WS_CHILD | C.WS_CLIPCHILDREN | C.WS_CLIPSIBLINGS |
                C.WS_TABSTOP | C.WS_VISIBLE
    } else {
        fmt.Printf("cef2go: CreateBrowser(): Unsupported OS\n")
        os.Exit(1)
    }
    windowInfo.parent_window = (C.HWND)(unsafe.Pointer(hwnd))
    windowInfo.x = C.int(rect.left)
    windowInfo.y = C.int(rect.top)
    windowInfo.width = C.int(rect.right - rect.left)
    windowInfo.height = C.int(rect.bottom - rect.top)

    // url
    var cefUrl C.cef_string_t
    var charUrl *C.char = C.CString(url)
    defer C.free(unsafe.Pointer(charUrl))
    C.cef_string_from_utf8(charUrl, C.strlen(charUrl), &cefUrl)

    // create browser
    var cefSettings C.struct__cef_browser_settings_t

    // TODO: reference counting, see:
    // https://code.google.com/p/chromiumembedded/wiki/UsingTheCAPI
    // --
    // What about C struct alignment issues in Go?
    // var refcnt unsafe.Pointer = unsafe.Pointer(&g_clientHandler)
    // refcnt += (unsafe.Pointer)(unsafe.Sizeof(g_clientHandler[0]))
    // C.InterlockedIncrement(refcnt)
    // C.InterlockedIncrement(&g_clientHandler{0})
    // C.InterlockedDecrement()
    // --

    // Must call synchronously so that a call to WindowResize()
    // works, after this function returns.
    C.cef_browser_host_create_browser_sync(&windowInfo, nil, &cefUrl,
            &cefSettings, nil)
}

func RunMessageLoop() {
    C.cef_run_message_loop()
}

func QuitMessageLoop() {
    C.cef_quit_message_loop()
}

func Shutdown() {
    C.cef_shutdown()
    // OFF: cef_sandbox_info_destroy(g_sandboxInfo)
}

func WindowResized(hwnd syscall.Handle) {
    var rect C.RECT;
    C.GetClientRect(
            (C.HWND)(unsafe.Pointer(hwnd)),
            (*C.struct_tagRECT)(unsafe.Pointer(&rect)))
    var hdwp C.HDWP = C.BeginDeferWindowPos(1)
    var cefHwnd C.HWND = C.GetWindow(
            (C.HWND)(unsafe.Pointer(hwnd)), C.GW_CHILD)
    hdwp = C.DeferWindowPos(hdwp, cefHwnd, nil,
            C.int(rect.left), C.int(rect.top),
            C.int(rect.right - rect.left),
            C.int(rect.bottom - rect.top),
            C.SWP_NOZORDER)
    C.EndDeferWindowPos(hdwp)
}
<|endoftext|>


<commit_before>package gzip

import (
	"compress/gzip"
	"net/http"
	"strings"

	"github.com/codegangsta/negroni"
)

const (
	HeaderAcceptEncoding  = "Accept-Encoding"
	HeaderContentEncoding = "Content-Encoding"
	HeaderContentLength   = "Content-Length"
	HeaderContentType     = "Content-Type"
	HeaderVary            = "Vary"
)

type gzipResponseWriter struct {
	w *gzip.Writer
	negroni.ResponseWriter
}

func (grw gzipResponseWriter) Write(b []byte) (int, error) {
	if len(grw.Header().Get(HeaderContentType)) == 0 {
		grw.Header().Set(HeaderContentType, http.DetectContentType(b))
	}
	return grw.w.Write(b)
}

type Gzipper struct{}

// Returns our Gzipper that adds gzip compression to all requests
func Gzip() *Gzipper {
	return &Gzipper{}
}

func (g *Gzipper) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if !strings.Contains(r.Header.Get(HeaderAcceptEncoding), "gzip") {
		return
	}

	headers := w.Header()
	headers.Set(HeaderContentEncoding, "gzip")
	headers.Set(HeaderVary, HeaderAcceptEncoding)

	gz := gzip.NewWriter(w)
	defer gz.Close()

	gzw := gzipResponseWriter{
		gz,
		w.(negroni.ResponseWriter),
	}

	next(gzw, r)

	// delete content length after we know we have been written to
	gzw.Header().Del("Content-Length")
}
<commit_msg>Use the HeaderContentLength const when deleting that header.<commit_after>package gzip

import (
	"compress/gzip"
	"net/http"
	"strings"

	"github.com/codegangsta/negroni"
)

const (
	HeaderAcceptEncoding  = "Accept-Encoding"
	HeaderContentEncoding = "Content-Encoding"
	HeaderContentLength   = "Content-Length"
	HeaderContentType     = "Content-Type"
	HeaderVary            = "Vary"
)

type gzipResponseWriter struct {
	w *gzip.Writer
	negroni.ResponseWriter
}

func (grw gzipResponseWriter) Write(b []byte) (int, error) {
	if len(grw.Header().Get(HeaderContentType)) == 0 {
		grw.Header().Set(HeaderContentType, http.DetectContentType(b))
	}
	return grw.w.Write(b)
}

type Gzipper struct{}

// Returns our Gzipper that adds gzip compression to all requests
func Gzip() *Gzipper {
	return &Gzipper{}
}

func (g *Gzipper) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	if !strings.Contains(r.Header.Get(HeaderAcceptEncoding), "gzip") {
		return
	}

	headers := w.Header()
	headers.Set(HeaderContentEncoding, "gzip")
	headers.Set(HeaderVary, HeaderAcceptEncoding)

	gz := gzip.NewWriter(w)
	defer gz.Close()

	gzw := gzipResponseWriter{
		gz,
		w.(negroni.ResponseWriter),
	}

	next(gzw, r)

	// delete content length after we know we have been written to
	gzw.Header().Del(HeaderContentLength)
}
<|endoftext|>


<commit_before>// Package hash contains some common hash functions suitable for use in hash
// maps.
package hash

import "unsafe"

func UInt32(u uint32) uint32 {
	return u
}

func UInt64(u uint64) uint32 {
	return mul33(uint32(u>>32)) + uint32(u&0xffffffff)
}

func Pointer(p unsafe.Pointer) uint32 {
	if unsafe.Sizeof(p) == 4 {
		return UInt32(uint32(uintptr(p)))
	} else {
		return UInt64(uint64(uintptr(p)))
	}
	// NOTE: We don't care about 128-bit archs yet.
}

func String(s string) uint32 {
	h := uint32(5381)
	for i := 0; i < len(s); i++ {
		h = mul33(h) + uint32(s[i])
	}
	return h
}

func mul33(u uint32) uint32 {
	return u<<5 + u
}
<commit_msg>hash: Add DJBInit and DJBCombine.<commit_after>// Package hash contains some common hash functions suitable for use in hash
// maps.
package hash

import "unsafe"

const DJBInit = 5381

func DJBCombine(acc, h uint32) uint32 {
	return mul33(acc) + h
}

func UInt32(u uint32) uint32 {
	return u
}

func UInt64(u uint64) uint32 {
	return mul33(uint32(u>>32)) + uint32(u&0xffffffff)
}

func Pointer(p unsafe.Pointer) uint32 {
	if unsafe.Sizeof(p) == 4 {
		return UInt32(uint32(uintptr(p)))
	} else {
		return UInt64(uint64(uintptr(p)))
	}
	// NOTE: We don't care about 128-bit archs yet.
}

func String(s string) uint32 {
	h := uint32(DJBInit)
	for i := 0; i < len(s); i++ {
		h = DJBCombine(h, uint32(s[i]))
	}
	return h
}

func mul33(u uint32) uint32 {
	return u<<5 + u
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"go/format"
	"io/ioutil"
	"os"
	"testing"

	"github.com/valyala/quicktemplate"
)

func TestParseFailure(t *testing.T) {
	// unknown tag
	testParseFailure(t, "{% foobar %}")

	// unexpected tag outside func
	testParseFailure(t, "aaa{% for %}bbb{%endfor%}")
	testParseFailure(t, "{% return %}")
	testParseFailure(t, "{% break %}")
	testParseFailure(t, "{% if 1==1 %}aaa{%endif%}")
	testParseFailure(t, "{%s abc %}")
	testParseFailure(t, "{%v= aaaa(xx) %}")
	testParseFailure(t, "{%= a() %}")

	// import after func and/or code
	testParseFailure(t, `{%code var i = 0 %}{%import "fmt"%}`)
	testParseFailure(t, `{%func f()%}{%endfunc%}{%import "fmt"%}`)

	// missing endfunc
	testParseFailure(t, "{%func a() %}aaaa")

	// empty func name
	testParseFailure(t, "{% func () %}aaa{% endfunc %}")
	testParseFailure(t, "{% func (a int, b string) %}aaa{% endfunc %}")

	// empty func arguments
	testParseFailure(t, "{% func aaa %}aaa{% endfunc %}")

	// func with anonymous argument
	testParseFailure(t, "{% func a(x int, string) %}{%endfunc%}")

	// func with incorrect arguments' list
	testParseFailure(t, "{% func x(foo, bar) %}{%endfunc%}")
	testParseFailure(t, "{% func x(foo bar baz) %}{%endfunc%}")

	// empty if condition
	testParseFailure(t, "{% func a() %}{% if    %}aaaa{% endif %}{% endfunc %}")

	// missing endif
	testParseFailure(t, "{%func a() %}{%if foo %}aaa{% endfunc %}")

	// missing endfor
	testParseFailure(t, "{%func a()%}{%for %}aaa{%endfunc%}")

	// break outside for
	testParseFailure(t, "{%func a()%}{%break%}{%endfunc%}")

	// invalid if condition
	testParseFailure(t, "{%func a()%}{%if a = b %}{%endif%}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%if a { %}{%endif%}{%endfunc%}")

	// invalid for
	testParseFailure(t, "{%func a()%}{%for a = b %}{%endfor%}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%for { %}{%endfor%}{%endfunc%}")

	// invalid code inside func
	testParseFailure(t, "{%func f()%}{%code } %}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%code { %}{%endfunc%}")

	// interface inside func
	testParseFailure(t, "{%func f()%}{%interface A { Foo() } %}{%endfunc%}")

	// interface without name
	testParseFailure(t, "{%interface  { Foo() } %}")

	// invalid interface
	testParseFailure(t, "{%interface aaaa %}")
	testParseFailure(t, "{%interface aa { Foo() %}")

	// unnamed method
	testParseFailure(t, "{%func (s *S) () %}{%endfunc%}")

	// empty method arguments
	testParseFailure(t, "{%func (s *S) Foo %}{%endfunc %}")

	// method with return values
	testParseFailure(t, "{%func (s *S) Foo() string %}{%endfunc%}")
	testParseFailure(t, "{%func (s *S) Bar() (int, string) %}{%endfunc%}")
}

func TestParserSuccess(t *testing.T) {
	// empty template
	testParseSuccess(t, "")

	// template without code and funcs
	testParseSuccess(t, "foobar\nbaz")

	// template with code
	testParseSuccess(t, "{%code var a struct {}\nconst n = 123%}")

	// import
	testParseSuccess(t, `{%import "foobar"%}`)
	testParseSuccess(t, `{% import (
	"foo"
	"bar"
)%}`)
	testParseSuccess(t, `{%import "foo"%}{%import "bar"%}`)

	// func
	testParseSuccess(t, "{%func a()%}{%endfunc%}")

	// func with with condition
	testParseSuccess(t, "{%func a(x bool)%}{%if x%}foobar{%endif%}{%endfunc%}")

	// func with complex arguments
	testParseSuccess(t, "{%func f(h1, h2 func(x, y int) string, d int)%}{%endfunc%}")

	// for
	testParseSuccess(t, "{%func a()%}{%for%}aaa{%endfor%}{%endfunc%}")

	// return
	testParseSuccess(t, "{%func a()%}{%return%}{%endfunc%}")

	// nested for
	testParseSuccess(t, "{%func a()%}{%for i := 0; i < 10; i++ %}{%for j := 0; j < i; j++%}aaa{%endfor%}{%endfor%}{%endfunc%}")

	// plain containing arbitrary tags
	testParseSuccess(t, "{%func f()%}{%plain%}This {%endfunc%} is ignored{%endplain%}{%endfunc%}")

	// comment with arbitrary tags
	testParseSuccess(t, "{%func f()%}{%comment%}This {%endfunc%} is ignored{%endcomment%}{%endfunc%}")

	// complex if
	testParseSuccess(t, "{%func a()%}{%if n, err := w.Write(p); err != nil %}{%endif%}{%endfunc%}")

	// complex for
	testParseSuccess(t, "{%func a()%}{%for i, n := 0, len(s); i < n && f(i); i++ %}{%endfor%}{%endfunc%}")

	// complex code inside func
	testParseSuccess(t, `{%func f()%}{%code
		type A struct{}
		var aa []A
		for i := 0; i < 10; i++ {
			aa = append(aa, &A{})
			if i == 42 {
				break
			}
		}
		return
	%}{%endfunc%}`)

	// break inside for loop
	testParseSuccess(t, `{%func f()%}{%for%}{%code
		if a() {
			break
		} else {
			return
		}
	%}{%endfor%}{%endfunc%}`)

	// interface
	testParseSuccess(t, "{%interface Foo { Bar()\nBaz() } %}")

	// method
	testParseSuccess(t, "{%func (s *S) Foo(bar, baz string) %}{%endfunc%}")
}

func testParseFailure(t *testing.T, str string) {
	r := bytes.NewBufferString(str)
	w := &bytes.Buffer{}
	if err := parse(w, r, "memory/foobar.tpl", "memory"); err == nil {
		t.Fatalf("expecting error when parsing %q", str)
	}
}

func testParseSuccess(t *testing.T, str string) {
	r := bytes.NewBufferString(str)
	w := &bytes.Buffer{}
	if err := parse(w, r, "memory/foobar.tpl", "memory"); err != nil {
		t.Fatalf("unexpected error when parsing %q: %s", str, err)
	}
}

func TestParseFile(t *testing.T) {
	filename := "templates/test.qtpl"
	f, err := os.Open(filename)
	if err != nil {
		t.Fatalf("cannot open file %q: %s", filename, err)
	}
	defer f.Close()

	packageName, err := getPackageName(filename)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	w := quicktemplate.AcquireByteBuffer()
	if err := parse(w, f, filename, packageName); err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	code, err := format.Source(w.B)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	quicktemplate.ReleaseByteBuffer(w)

	expectedFilename := filename + ".compiled"
	expectedCode, err := ioutil.ReadFile(expectedFilename)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	if !bytes.Equal(code, expectedCode) {
		t.Fatalf("unexpected code: %q\nExpecting %q", code, expectedCode)
	}

}
<commit_msg>verify empty interface<commit_after>package main

import (
	"bytes"
	"go/format"
	"io/ioutil"
	"os"
	"testing"

	"github.com/valyala/quicktemplate"
)

func TestParseFailure(t *testing.T) {
	// unknown tag
	testParseFailure(t, "{% foobar %}")

	// unexpected tag outside func
	testParseFailure(t, "aaa{% for %}bbb{%endfor%}")
	testParseFailure(t, "{% return %}")
	testParseFailure(t, "{% break %}")
	testParseFailure(t, "{% if 1==1 %}aaa{%endif%}")
	testParseFailure(t, "{%s abc %}")
	testParseFailure(t, "{%v= aaaa(xx) %}")
	testParseFailure(t, "{%= a() %}")

	// import after func and/or code
	testParseFailure(t, `{%code var i = 0 %}{%import "fmt"%}`)
	testParseFailure(t, `{%func f()%}{%endfunc%}{%import "fmt"%}`)

	// missing endfunc
	testParseFailure(t, "{%func a() %}aaaa")

	// empty func name
	testParseFailure(t, "{% func () %}aaa{% endfunc %}")
	testParseFailure(t, "{% func (a int, b string) %}aaa{% endfunc %}")

	// empty func arguments
	testParseFailure(t, "{% func aaa %}aaa{% endfunc %}")

	// func with anonymous argument
	testParseFailure(t, "{% func a(x int, string) %}{%endfunc%}")

	// func with incorrect arguments' list
	testParseFailure(t, "{% func x(foo, bar) %}{%endfunc%}")
	testParseFailure(t, "{% func x(foo bar baz) %}{%endfunc%}")

	// empty if condition
	testParseFailure(t, "{% func a() %}{% if    %}aaaa{% endif %}{% endfunc %}")

	// missing endif
	testParseFailure(t, "{%func a() %}{%if foo %}aaa{% endfunc %}")

	// missing endfor
	testParseFailure(t, "{%func a()%}{%for %}aaa{%endfunc%}")

	// break outside for
	testParseFailure(t, "{%func a()%}{%break%}{%endfunc%}")

	// invalid if condition
	testParseFailure(t, "{%func a()%}{%if a = b %}{%endif%}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%if a { %}{%endif%}{%endfunc%}")

	// invalid for
	testParseFailure(t, "{%func a()%}{%for a = b %}{%endfor%}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%for { %}{%endfor%}{%endfunc%}")

	// invalid code inside func
	testParseFailure(t, "{%func f()%}{%code } %}{%endfunc%}")
	testParseFailure(t, "{%func f()%}{%code { %}{%endfunc%}")

	// interface inside func
	testParseFailure(t, "{%func f()%}{%interface A { Foo() } %}{%endfunc%}")

	// interface without name
	testParseFailure(t, "{%interface  { Foo() } %}")

	// empty interface
	testParseFailure(t, "{% interface Foo {} %}")

	// invalid interface
	testParseFailure(t, "{%interface aaaa %}")
	testParseFailure(t, "{%interface aa { Foo() %}")

	// unnamed method
	testParseFailure(t, "{%func (s *S) () %}{%endfunc%}")

	// empty method arguments
	testParseFailure(t, "{%func (s *S) Foo %}{%endfunc %}")

	// method with return values
	testParseFailure(t, "{%func (s *S) Foo() string %}{%endfunc%}")
	testParseFailure(t, "{%func (s *S) Bar() (int, string) %}{%endfunc%}")
}

func TestParserSuccess(t *testing.T) {
	// empty template
	testParseSuccess(t, "")

	// template without code and funcs
	testParseSuccess(t, "foobar\nbaz")

	// template with code
	testParseSuccess(t, "{%code var a struct {}\nconst n = 123%}")

	// import
	testParseSuccess(t, `{%import "foobar"%}`)
	testParseSuccess(t, `{% import (
	"foo"
	"bar"
)%}`)
	testParseSuccess(t, `{%import "foo"%}{%import "bar"%}`)

	// func
	testParseSuccess(t, "{%func a()%}{%endfunc%}")

	// func with with condition
	testParseSuccess(t, "{%func a(x bool)%}{%if x%}foobar{%endif%}{%endfunc%}")

	// func with complex arguments
	testParseSuccess(t, "{%func f(h1, h2 func(x, y int) string, d int)%}{%endfunc%}")

	// for
	testParseSuccess(t, "{%func a()%}{%for%}aaa{%endfor%}{%endfunc%}")

	// return
	testParseSuccess(t, "{%func a()%}{%return%}{%endfunc%}")

	// nested for
	testParseSuccess(t, "{%func a()%}{%for i := 0; i < 10; i++ %}{%for j := 0; j < i; j++%}aaa{%endfor%}{%endfor%}{%endfunc%}")

	// plain containing arbitrary tags
	testParseSuccess(t, "{%func f()%}{%plain%}This {%endfunc%} is ignored{%endplain%}{%endfunc%}")

	// comment with arbitrary tags
	testParseSuccess(t, "{%func f()%}{%comment%}This {%endfunc%} is ignored{%endcomment%}{%endfunc%}")

	// complex if
	testParseSuccess(t, "{%func a()%}{%if n, err := w.Write(p); err != nil %}{%endif%}{%endfunc%}")

	// complex for
	testParseSuccess(t, "{%func a()%}{%for i, n := 0, len(s); i < n && f(i); i++ %}{%endfor%}{%endfunc%}")

	// complex code inside func
	testParseSuccess(t, `{%func f()%}{%code
		type A struct{}
		var aa []A
		for i := 0; i < 10; i++ {
			aa = append(aa, &A{})
			if i == 42 {
				break
			}
		}
		return
	%}{%endfunc%}`)

	// break inside for loop
	testParseSuccess(t, `{%func f()%}{%for%}{%code
		if a() {
			break
		} else {
			return
		}
	%}{%endfor%}{%endfunc%}`)

	// interface
	testParseSuccess(t, "{%interface Foo { Bar()\nBaz() } %}")

	// method
	testParseSuccess(t, "{%func (s *S) Foo(bar, baz string) %}{%endfunc%}")
}

func testParseFailure(t *testing.T, str string) {
	r := bytes.NewBufferString(str)
	w := &bytes.Buffer{}
	if err := parse(w, r, "memory/foobar.tpl", "memory"); err == nil {
		t.Fatalf("expecting error when parsing %q", str)
	}
}

func testParseSuccess(t *testing.T, str string) {
	r := bytes.NewBufferString(str)
	w := &bytes.Buffer{}
	if err := parse(w, r, "memory/foobar.tpl", "memory"); err != nil {
		t.Fatalf("unexpected error when parsing %q: %s", str, err)
	}
}

func TestParseFile(t *testing.T) {
	filename := "templates/test.qtpl"
	f, err := os.Open(filename)
	if err != nil {
		t.Fatalf("cannot open file %q: %s", filename, err)
	}
	defer f.Close()

	packageName, err := getPackageName(filename)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	w := quicktemplate.AcquireByteBuffer()
	if err := parse(w, f, filename, packageName); err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	code, err := format.Source(w.B)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}
	quicktemplate.ReleaseByteBuffer(w)

	expectedFilename := filename + ".compiled"
	expectedCode, err := ioutil.ReadFile(expectedFilename)
	if err != nil {
		t.Fatalf("unexpected error: %s", err)
	}

	if !bytes.Equal(code, expectedCode) {
		t.Fatalf("unexpected code: %q\nExpecting %q", code, expectedCode)
	}

}
<|endoftext|>


<commit_before>// Copyright © 2010 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package nanospec

import (
	"container/vector"
	"testing"
)

func Run(gotest *testing.T, spec func(Context)) {
	c := newContext(gotest, spec)
	c.Run()
}

type Context interface {
	Specify(name string, closure func())
	Expect(actual interface{}) Expectation
}

type runContext struct {
	out          Reporter
	rootClosure  func(Context)
	root         *aSpec
	current      *aSpec
	backtracking bool
}

func newContext(t *testing.T, spec func(Context)) *runContext {
	root := newSpec(nil, functionName(spec))
	return &runContext{gotestReporter{t}, spec, root, root, false}
}

func (this *runContext) Run() {
	safetyLimit := 10000 // just in case this program gets stuck in an infinite loop during development
	for this.root.ShouldExecute() && safetyLimit > 0 {
		this.backtracking = false
		this.root.Execute(func() { this.rootClosure(this) })
		safetyLimit--
	}
}

func (this *runContext) Specify(name string, closure func()) {
	this.enterSpec(name)
	this.processSpec(closure)
	this.exitSpec()
}

func (this *runContext) enterSpec(name string) {
	child := this.current.EnterChild(name)
	this.current = child
}

func (this *runContext) processSpec(closure func()) {
	if !this.backtracking && this.current.ShouldExecute() {
		this.current.Execute(closure)
		this.backtracking = true
	}
}

func (this *runContext) exitSpec() {
	this.current = this.current.Parent
}

func (this *runContext) Expect(actual interface{}) Expectation {
	reporter := newSpecReporter(this.out, this.current, callerLocation())
	return newExpectation(actual, reporter)
}

type aSpec struct {
	Parent                *aSpec
	Name                  string
	children              *vector.Vector
	childrenSeenOnThisRun int
	hasBeenFullyExecuted  bool
}

func newSpec(parent *aSpec, name string) *aSpec {
	return &aSpec{parent, name, new(vector.Vector), 0, false}
}

func (this *aSpec) ShouldExecute() bool {
	return !this.hasBeenFullyExecuted
}

// The closure of this spec must be passed as a parameter,
// to make sure it's fresh; no side-effects from previous runs.
func (this *aSpec) Execute(closure func()) {
	this.childrenSeenOnThisRun = 0
	closure()
	this.hasBeenFullyExecuted = this.allChildrenHaveBeenExecuted()
}

func (this *aSpec) allChildrenHaveBeenExecuted() bool {
	for _, v := range *this.children {
		child := v.(*aSpec)
		if !child.hasBeenFullyExecuted {
			return false
		}
	}
	return true
}

func (this *aSpec) EnterChild(name string) *aSpec {
	this.childrenSeenOnThisRun++
	childIndex := this.childrenSeenOnThisRun - 1

	isUnseen := childIndex >= this.children.Len()
	if isUnseen {
		child := newSpec(this, name)
		this.children.Push(child)
		return child
	}

	child := this.children.At(childIndex).(*aSpec)
	return child
}
<commit_msg>Context.Errorf()<commit_after>// Copyright © 2010 Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package nanospec

import (
	"container/vector"
	"fmt"
	"testing"
)

func Run(gotest *testing.T, spec func(Context)) {
	c := newContext(gotest, spec)
	c.Run()
}

type Context interface {
	Specify(name string, closure func())
	Expect(actual interface{}) Expectation
	Errorf(format string, args ...interface{})
}

type runContext struct {
	out          Reporter
	rootClosure  func(Context)
	root         *aSpec
	current      *aSpec
	backtracking bool
}

func newContext(t *testing.T, spec func(Context)) *runContext {
	root := newSpec(nil, functionName(spec))
	return &runContext{gotestReporter{t}, spec, root, root, false}
}

func (this *runContext) Run() {
	safetyLimit := 10000 // just in case this program gets stuck in an infinite loop during development
	for this.root.ShouldExecute() && safetyLimit > 0 {
		this.backtracking = false
		this.root.Execute(func() { this.rootClosure(this) })
		safetyLimit--
	}
}

func (this *runContext) Specify(name string, closure func()) {
	this.enterSpec(name)
	this.processSpec(closure)
	this.exitSpec()
}

func (this *runContext) enterSpec(name string) {
	child := this.current.EnterChild(name)
	this.current = child
}

func (this *runContext) processSpec(closure func()) {
	if !this.backtracking && this.current.ShouldExecute() {
		this.current.Execute(closure)
		this.backtracking = true
	}
}

func (this *runContext) exitSpec() {
	this.current = this.current.Parent
}

func (this *runContext) Expect(actual interface{}) Expectation {
	reporter := newSpecReporter(this.out, this.current, callerLocation())
	return newExpectation(actual, reporter)
}

func (this *runContext) Errorf(format string, args ...interface{}) {
	reporter := newSpecReporter(this.out, this.current, callerLocation())
	reporter.Error(fmt.Sprintf(format, args))
}

type aSpec struct {
	Parent                *aSpec
	Name                  string
	children              *vector.Vector
	childrenSeenOnThisRun int
	hasBeenFullyExecuted  bool
}

func newSpec(parent *aSpec, name string) *aSpec {
	return &aSpec{parent, name, new(vector.Vector), 0, false}
}

func (this *aSpec) ShouldExecute() bool {
	return !this.hasBeenFullyExecuted
}

// The closure of this spec must be passed as a parameter,
// to make sure it's fresh; no side-effects from previous runs.
func (this *aSpec) Execute(closure func()) {
	this.childrenSeenOnThisRun = 0
	closure()
	this.hasBeenFullyExecuted = this.allChildrenHaveBeenExecuted()
}

func (this *aSpec) allChildrenHaveBeenExecuted() bool {
	for _, v := range *this.children {
		child := v.(*aSpec)
		if !child.hasBeenFullyExecuted {
			return false
		}
	}
	return true
}

func (this *aSpec) EnterChild(name string) *aSpec {
	this.childrenSeenOnThisRun++
	childIndex := this.childrenSeenOnThisRun - 1

	isUnseen := childIndex >= this.children.Len()
	if isUnseen {
		child := newSpec(this, name)
		this.children.Push(child)
		return child
	}

	child := this.children.At(childIndex).(*aSpec)
	return child
}
<|endoftext|>