<commit_before>package main

import (
	"C"
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

const (
	HWND_BROADCAST = HWND(0xffff)
)

type (
	HWND   HANDLE
	HANDLE uintptr
)

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")
	user32   = syscall.NewLazyDLL("user32.dll")

	wSleep                  = kernel32.NewProc("Sleep")
	wOpenFileMappingW       = kernel32.NewProc("OpenFileMappingW")
	wMapViewOfFile          = kernel32.NewProc("MapViewOfFile")
	wCloseHandle            = kernel32.NewProc("CloseHandle")
	wUnmapViewOfFile        = kernel32.NewProc("UnmapViewOfFile")
	wOpenEvent              = kernel32.NewProc("OpenEventW")
	wWaitForSingleObject    = kernel32.NewProc("WaitForSingleObject")
	wRegisterWindowMessageA = user32.NewProc("RegisterWindowMessageA")
	wRegisterWindowMessageW = user32.NewProc("RegisterWindowMessageW")
	wSendNotifyMessage      = user32.NewProc("SendNotifyMessageW")
)

func sleep(timeout int) error {
	_, _, err := wSleep.Call(uintptr(timeout))

	if err != nil {
		errMsg := fmt.Sprintf("Timeout failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func openFileMapping(lpName string) (uintptr, error) {
	dwDesiredAccess := syscall.FILE_MAP_READ

	hMemMapFile, _, err := wOpenFileMappingW.Call(
		uintptr(dwDesiredAccess), // DWORD
		0, // BOOL
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpName))), // LPCTSTR
	)

	if hMemMapFile == 0 {
		errMsg := fmt.Sprintf("OpenFileMapping failed (%s)", err)
		return hMemMapFile, errors.New(errMsg)
	}

	return hMemMapFile, nil
}

func mapViewOfFile(hMemMapFile uintptr, dwNumberOfBytesToMap int) (uintptr, error) {
	dwDesiredAccess := syscall.FILE_MAP_READ
	dwFileOffsetHigh := 0
	dwFileOffsetLow := 0

	sharedMemPtr, _, err := wMapViewOfFile.Call(
		hMemMapFile,
		uintptr(dwDesiredAccess),      // DWORD
		uintptr(dwFileOffsetHigh),     // DWORD
		uintptr(dwFileOffsetLow),      // DWORD
		uintptr(dwNumberOfBytesToMap), // SIZE_T
	)

	if sharedMemPtr == 0 {
		errMsg := fmt.Sprintf("MapViewOfFile failed (%s)", err)
		return hMemMapFile, errors.New(errMsg)
	}

	return sharedMemPtr, nil
}

func closeHandle(handle uintptr) error {
	result, _, err := wCloseHandle.Call(handle)

	if result == 0 {
		errMsg := fmt.Sprintf("CloseHandle failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func unmapViewOfFile(lpBaseAddress uintptr) error {
	result, _, err := wUnmapViewOfFile.Call(lpBaseAddress)

	if result == 0 {
		errMsg := fmt.Sprintf("UnmapViewOfFile failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func openEvent(lpName string) (uintptr, error) {
	dwDesiredAccess := syscall.SYNCHRONIZE
	bInheritHandle := 0

	hDataValidEvent, _, err := wOpenEvent.Call(
		uintptr(dwDesiredAccess),                                  // DWORD
		uintptr(bInheritHandle),                                   // BOOL
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpName))), // LPCTSTR
	)

	if hDataValidEvent == 0 {
		errMsg := fmt.Sprintf("OpenEvent failed (%s)", err)
		return hDataValidEvent, errors.New(errMsg)
	}

	return hDataValidEvent, nil
}

func waitForSingleObject(hDataValidEvent uintptr, timeOut int) error {
	dwMilliseconds := timeOut

	result, _, err := wWaitForSingleObject.Call(
		hDataValidEvent,         // HANDLE
		uintptr(dwMilliseconds), // DWORD
	)

	if result != 0 {
		errMsg := fmt.Sprintf("WaitForSingleObject failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func registerWindowMessageA(lpString string) (uint, error) {
	msgID, _, err := wRegisterWindowMessageW.Call(
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpString))), // LPCTSTR
	)

	if msgID == 0 {
		errMsg := fmt.Sprintf("registerWindowMessageA failed (%s)", err)
		return 0, errors.New(errMsg)
	}

	return uint(msgID), nil
}

func sendNotifyMessage(msgID uint, wParam uint32, lParam uint32) error {
	hWnd := HWND_BROADCAST

	result, _, err := wSendNotifyMessage.Call(
		uintptr(hWnd),   // HWND
		uintptr(msgID),  // UINT
		uintptr(wParam), // WPARAM
		uintptr(lParam), // LPARAM
	)

	fmt.Println(err)
	if result == 0 {
		errMsg := fmt.Sprintf("sendNotifyMessage failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func MAKELONG(lo, hi uint16) uint32 {
	return uint32(uint32(lo) | ((uint32(hi)) << 16))
}
<commit_msg>Trying to get broadcastmsg working<commit_after>package main

/*
// for timeBeginPeriod()
#pragma comment(lib, "Winmm")
// for RegisterWindowMessageA() and SendMessage()
#pragma comment(lib, "User32")
*/
import "C"
import (
	"errors"
	"fmt"
	"syscall"
	"unsafe"
)

const (
	HWND_BROADCAST = HWND(0xffff)
)

type (
	HWND   HANDLE
	HANDLE uintptr
)

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")
	user32   = syscall.NewLazyDLL("user32.dll")

	wSleep                  = kernel32.NewProc("Sleep")
	wOpenFileMappingW       = kernel32.NewProc("OpenFileMappingW")
	wMapViewOfFile          = kernel32.NewProc("MapViewOfFile")
	wCloseHandle            = kernel32.NewProc("CloseHandle")
	wUnmapViewOfFile        = kernel32.NewProc("UnmapViewOfFile")
	wOpenEvent              = kernel32.NewProc("OpenEventW")
	wWaitForSingleObject    = kernel32.NewProc("WaitForSingleObject")
	wRegisterWindowMessageA = user32.NewProc("RegisterWindowMessageA")
	wSendNotifyMessageA     = user32.NewProc("SendNotifyMessageA")
)

func sleep(timeout int) error {
	_, _, err := wSleep.Call(uintptr(timeout))

	if err != nil {
		errMsg := fmt.Sprintf("Timeout failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func openFileMapping(lpName string) (uintptr, error) {
	dwDesiredAccess := syscall.FILE_MAP_READ

	hMemMapFile, _, err := wOpenFileMappingW.Call(
		uintptr(dwDesiredAccess), // DWORD
		0, // BOOL
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpName))), // LPCTSTR
	)

	if hMemMapFile == 0 {
		errMsg := fmt.Sprintf("OpenFileMapping failed (%s)", err)
		return hMemMapFile, errors.New(errMsg)
	}

	return hMemMapFile, nil
}

func mapViewOfFile(hMemMapFile uintptr, dwNumberOfBytesToMap int) (uintptr, error) {
	dwDesiredAccess := syscall.FILE_MAP_READ
	dwFileOffsetHigh := 0
	dwFileOffsetLow := 0

	sharedMemPtr, _, err := wMapViewOfFile.Call(
		hMemMapFile,
		uintptr(dwDesiredAccess),      // DWORD
		uintptr(dwFileOffsetHigh),     // DWORD
		uintptr(dwFileOffsetLow),      // DWORD
		uintptr(dwNumberOfBytesToMap), // SIZE_T
	)

	if sharedMemPtr == 0 {
		errMsg := fmt.Sprintf("MapViewOfFile failed (%s)", err)
		return hMemMapFile, errors.New(errMsg)
	}

	return sharedMemPtr, nil
}

func closeHandle(handle uintptr) error {
	result, _, err := wCloseHandle.Call(handle)

	if result == 0 {
		errMsg := fmt.Sprintf("CloseHandle failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func unmapViewOfFile(lpBaseAddress uintptr) error {
	result, _, err := wUnmapViewOfFile.Call(lpBaseAddress)

	if result == 0 {
		errMsg := fmt.Sprintf("UnmapViewOfFile failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func openEvent(lpName string) (uintptr, error) {
	dwDesiredAccess := syscall.SYNCHRONIZE
	bInheritHandle := 0

	hDataValidEvent, _, err := wOpenEvent.Call(
		uintptr(dwDesiredAccess),                                  // DWORD
		uintptr(bInheritHandle),                                   // BOOL
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpName))), // LPCTSTR
	)

	if hDataValidEvent == 0 {
		errMsg := fmt.Sprintf("OpenEvent failed (%s)", err)
		return hDataValidEvent, errors.New(errMsg)
	}

	return hDataValidEvent, nil
}

func waitForSingleObject(hDataValidEvent uintptr, timeOut int) error {
	dwMilliseconds := timeOut

	result, _, err := wWaitForSingleObject.Call(
		hDataValidEvent,         // HANDLE
		uintptr(dwMilliseconds), // DWORD
	)

	if result != 0 {
		errMsg := fmt.Sprintf("WaitForSingleObject failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func registerWindowMessageA(lpString string) (uint, error) {
	msgID, _, err := wRegisterWindowMessageA.Call(
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpString))), // LPCTSTR
	)

	if msgID == 0 {
		errMsg := fmt.Sprintf("registerWindowMessageA failed (%s)", err)
		return 0, errors.New(errMsg)
	}

	return uint(msgID), nil
}

func sendNotifyMessage(msgID uint, wParam uint32, lParam uint32) error {
	hWnd := HWND_BROADCAST

	result, _, err := wSendNotifyMessageA.Call(
		uintptr(hWnd),   // HWND
		uintptr(msgID),  // UINT
		uintptr(wParam), // WPARAM
		uintptr(lParam), // LPARAM
	)

	fmt.Println(err)
	if result == 0 {
		errMsg := fmt.Sprintf("sendNotifyMessage failed (%s)", err)
		return errors.New(errMsg)
	}

	return nil
}

func MAKELONG(lo, hi uint16) uint32 {
	return uint32(uint32(lo) | ((uint32(hi)) << 16))
}
<|endoftext|>


<commit_before>package dal

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/jmoiron/sqlx"
	sqlx_types "github.com/jmoiron/sqlx/types"
)

var PROJECT_EPOCH = 1451606400

type InsertResult struct {
	lastInsertId int64
	rowsAffected int64
}

func (ir *InsertResult) LastInsertId() (int64, error) {
	return ir.lastInsertId, nil
}

func (ir *InsertResult) RowsAffected() (int64, error) {
	return ir.rowsAffected, nil
}

type BaseRow struct {
}

func (br *BaseRow) JSONAttrString(field sqlx_types.JSONText, attr string) string {
	unmarshalled := make(map[string]interface{})

	err := json.Unmarshal(field, &unmarshalled)
	if err != nil {
		return ""
	}

	attrInterface := unmarshalled[attr]
	if attrInterface == nil {
		return ""
	}

	return attrInterface.(string)
}

func (br *BaseRow) JSONAttrFloat64(field sqlx_types.JSONText, attr string) float64 {
	unmarshalled := make(map[string]interface{})

	err := json.Unmarshal(field, &unmarshalled)
	if err != nil {
		return -1
	}

	attrInterface := unmarshalled[attr]
	if attrInterface == nil {
		return -1
	}

	return attrInterface.(float64)
}

type Base struct {
	db    *sqlx.DB
	table string
	hasID bool
}

// NewExplicitID uses UNIX timestamp in microseconds as ID.
func (b *Base) NewExplicitID() int64 {
	currentTime := time.Now().UnixNano()
	projectEpochInNanoSeconds := int64(PROJECT_EPOCH * 1000 * 1000 * 1000)

	resultInNanoSeconds := currentTime - projectEpochInNanoSeconds
	resultInMicroSeconds := int64(math.Floor(float64(resultInNanoSeconds / 1000)))

	return resultInMicroSeconds
}

func (b *Base) newTransactionIfNeeded(tx *sqlx.Tx) (*sqlx.Tx, bool, error) {
	var err error
	wrapInSingleTransaction := false

	if tx != nil {
		return tx, wrapInSingleTransaction, nil
	}

	tx, err = b.db.Beginx()
	if err == nil {
		wrapInSingleTransaction = true
	}

	if err != nil {
		return nil, wrapInSingleTransaction, err
	}

	return tx, wrapInSingleTransaction, nil
}

func (b *Base) InsertIntoTable(tx *sqlx.Tx, data map[string]interface{}) (sql.Result, error) {
	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keys := make([]string, 0)
	dollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keys = append(keys, key)
		dollarMarks = append(dollarMarks, fmt.Sprintf("$%v", loopCounter))
		values = append(values, value)

		loopCounter++
	}

	query := fmt.Sprintf(
		"INSERT INTO %v (%v) VALUES (%v)",
		b.table,
		strings.Join(keys, ","),
		strings.Join(dollarMarks, ","))

	result := &InsertResult{}
	result.rowsAffected = 1

	if b.hasID {
		query = query + " RETURNING id"

		logrus.WithFields(logrus.Fields{
			"Method": "Base.InsertIntoTable",
			"Query":  query,
		}).Info("Insert Query")

		var lastInsertId int64
		err = tx.QueryRow(query, values...).Scan(&lastInsertId)
		if err != nil {
			return nil, err
		}

		result.lastInsertId = lastInsertId

	} else {
		logrus.WithFields(logrus.Fields{
			"Method": "Base.InsertIntoTable",
			"Query":  query,
		}).Info("Insert Query")

		_, err := tx.Exec(query, values...)
		if err != nil {
			return nil, err
		}
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateFromTable(tx *sqlx.Tx, data map[string]interface{}, where string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		where)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateFromTable",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateByID(tx *sqlx.Tx, data map[string]interface{}, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	// Add id as part of values
	values = append(values, id)

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE id=$%v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		loopCounter)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateByID",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateByKeyValueString(tx *sqlx.Tx, data map[string]interface{}, key, value string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	// Add value as part of values
	values = append(values, value)

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v=$%v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		key,
		loopCounter)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateByKeyValueString",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) DeleteFromTable(tx *sqlx.Tx, where string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v", b.table)

	if where != "" {
		query = query + " WHERE " + where
	}

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteFromTable",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}

func (b *Base) DeleteByID(tx *sqlx.Tx, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v WHERE id=$1", b.table)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteByID",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query, id)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}

func (b *Base) DeleteByClusterIDAndID(tx *sqlx.Tx, clusterID, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v WHERE id=$1 AND cluster_id=$2", b.table)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteByClusterIDAndID",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query, clusterID, id)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}
<commit_msg>fix bug on delete by cluster_id and id.<commit_after>package dal

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/jmoiron/sqlx"
	sqlx_types "github.com/jmoiron/sqlx/types"
)

var PROJECT_EPOCH = 1451606400

type InsertResult struct {
	lastInsertId int64
	rowsAffected int64
}

func (ir *InsertResult) LastInsertId() (int64, error) {
	return ir.lastInsertId, nil
}

func (ir *InsertResult) RowsAffected() (int64, error) {
	return ir.rowsAffected, nil
}

type BaseRow struct {
}

func (br *BaseRow) JSONAttrString(field sqlx_types.JSONText, attr string) string {
	unmarshalled := make(map[string]interface{})

	err := json.Unmarshal(field, &unmarshalled)
	if err != nil {
		return ""
	}

	attrInterface := unmarshalled[attr]
	if attrInterface == nil {
		return ""
	}

	return attrInterface.(string)
}

func (br *BaseRow) JSONAttrFloat64(field sqlx_types.JSONText, attr string) float64 {
	unmarshalled := make(map[string]interface{})

	err := json.Unmarshal(field, &unmarshalled)
	if err != nil {
		return -1
	}

	attrInterface := unmarshalled[attr]
	if attrInterface == nil {
		return -1
	}

	return attrInterface.(float64)
}

type Base struct {
	db    *sqlx.DB
	table string
	hasID bool
}

// NewExplicitID uses UNIX timestamp in microseconds as ID.
func (b *Base) NewExplicitID() int64 {
	currentTime := time.Now().UnixNano()
	projectEpochInNanoSeconds := int64(PROJECT_EPOCH * 1000 * 1000 * 1000)

	resultInNanoSeconds := currentTime - projectEpochInNanoSeconds
	resultInMicroSeconds := int64(math.Floor(float64(resultInNanoSeconds / 1000)))

	return resultInMicroSeconds
}

func (b *Base) newTransactionIfNeeded(tx *sqlx.Tx) (*sqlx.Tx, bool, error) {
	var err error
	wrapInSingleTransaction := false

	if tx != nil {
		return tx, wrapInSingleTransaction, nil
	}

	tx, err = b.db.Beginx()
	if err == nil {
		wrapInSingleTransaction = true
	}

	if err != nil {
		return nil, wrapInSingleTransaction, err
	}

	return tx, wrapInSingleTransaction, nil
}

func (b *Base) InsertIntoTable(tx *sqlx.Tx, data map[string]interface{}) (sql.Result, error) {
	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keys := make([]string, 0)
	dollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keys = append(keys, key)
		dollarMarks = append(dollarMarks, fmt.Sprintf("$%v", loopCounter))
		values = append(values, value)

		loopCounter++
	}

	query := fmt.Sprintf(
		"INSERT INTO %v (%v) VALUES (%v)",
		b.table,
		strings.Join(keys, ","),
		strings.Join(dollarMarks, ","))

	result := &InsertResult{}
	result.rowsAffected = 1

	if b.hasID {
		query = query + " RETURNING id"

		logrus.WithFields(logrus.Fields{
			"Method": "Base.InsertIntoTable",
			"Query":  query,
		}).Info("Insert Query")

		var lastInsertId int64
		err = tx.QueryRow(query, values...).Scan(&lastInsertId)
		if err != nil {
			return nil, err
		}

		result.lastInsertId = lastInsertId

	} else {
		logrus.WithFields(logrus.Fields{
			"Method": "Base.InsertIntoTable",
			"Query":  query,
		}).Info("Insert Query")

		_, err := tx.Exec(query, values...)
		if err != nil {
			return nil, err
		}
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateFromTable(tx *sqlx.Tx, data map[string]interface{}, where string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		where)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateFromTable",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateByID(tx *sqlx.Tx, data map[string]interface{}, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	// Add id as part of values
	values = append(values, id)

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE id=$%v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		loopCounter)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateByID",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) UpdateByKeyValueString(tx *sqlx.Tx, data map[string]interface{}, key, value string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	keysWithDollarMarks := make([]string, 0)
	values := make([]interface{}, 0)

	loopCounter := 1
	for key, value := range data {
		keysWithDollarMark := fmt.Sprintf("%v=$%v", key, loopCounter)
		keysWithDollarMarks = append(keysWithDollarMarks, keysWithDollarMark)
		values = append(values, value)

		loopCounter++
	}

	// Add value as part of values
	values = append(values, value)

	query := fmt.Sprintf(
		"UPDATE %v SET %v WHERE %v=$%v",
		b.table,
		strings.Join(keysWithDollarMarks, ","),
		key,
		loopCounter)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.UpdateByKeyValueString",
		"Query":  query,
	}).Info("Update Query")

	result, err = tx.Exec(query, values...)

	if err != nil {
		return nil, err
	}

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	return result, err
}

func (b *Base) DeleteFromTable(tx *sqlx.Tx, where string) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v", b.table)

	if where != "" {
		query = query + " WHERE " + where
	}

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteFromTable",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}

func (b *Base) DeleteByID(tx *sqlx.Tx, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v WHERE id=$1", b.table)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteByID",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query, id)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}

func (b *Base) DeleteByClusterIDAndID(tx *sqlx.Tx, clusterID, id int64) (sql.Result, error) {
	var result sql.Result

	if b.table == "" {
		return nil, errors.New("Table must not be empty.")
	}

	tx, wrapInSingleTransaction, err := b.newTransactionIfNeeded(tx)
	if tx == nil {
		return nil, errors.New("Transaction struct must not be empty.")
	}
	if err != nil {
		return nil, err
	}

	query := fmt.Sprintf("DELETE FROM %v WHERE id=$1 AND cluster_id=$2", b.table)

	logrus.WithFields(logrus.Fields{
		"Method": "Base.DeleteByClusterIDAndID",
		"Query":  query,
	}).Info("Delete Query")

	result, err = tx.Exec(query, id, clusterID)

	if wrapInSingleTransaction == true {
		err = tx.Commit()
	}

	if err != nil {
		return nil, err
	}

	return result, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math"
	"sort"
	"strings"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type MongoHandler struct {
	Session *mgo.Session
}

func (mongo *MongoHandler) Init() {
	dialInfo := &mgo.DialInfo{
		Addrs:   []string{"127.0.0.1"},
		Timeout: 10 * time.Minute,
	}

	var err error
	mongo.Session, err = mgo.DialWithInfo(dialInfo)
	if err != nil {
		log.Fatal(err)
	}
	mongo.Session.SetMode(mgo.Monotonic, true)
}

func (mongo *MongoHandler) ListDatabases() []string {
	all_dbs, err := mongo.Session.DatabaseNames()
	if err != nil {
		log.Fatal(err)
	}

	dbs := []string{}
	for _, db := range all_dbs {
		if strings.HasPrefix(db, "perf") {
			dbs = append(dbs, strings.Replace(db, "perf", "", 1))
		}
	}
	return dbs
}

func (mongo *MongoHandler) ListCollections(db string) []string {
	session := mongo.Session.New()
	defer session.Close()
	_db := session.DB(db)

	all_collections, err := _db.CollectionNames()
	if err != nil {
		log.Fatal(err)
	}

	collections := []string{}
	for _, collection := range all_collections {
		if collection != "system.indexes" {
			collections = append(collections, collection)
		}
	}
	return collections
}

func (mongo *MongoHandler) ListMetrics(db, collection string) []string {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	var metrics []string
	err := _collection.Find(bson.M{}).Distinct("m", &metrics)
	if err != nil {
		log.Fatal(err)
	}
	return metrics
}

func (mongo *MongoHandler) FindValues(db, collection, metric string) map[string]float64 {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	var docs []map[string]interface{}
	err := _collection.Find(bson.M{"m": metric}).Sort("ts").All(&docs)
	if err != nil {
		log.Fatal(err)
	}

	values := map[string]float64{}
	for _, doc := range docs {
		values[doc["ts"].(string)] = doc["v"].(float64)
	}

	return values
}

func (mongo *MongoHandler) InsertSample(db, collection string, sample map[string]interface{}) {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	err := _collection.Insert(sample)
	if err != nil {
		log.Fatal(err)
	}

	err = _collection.EnsureIndexKey("m")
	if err != nil {
		log.Fatal(err)
	}
}

func calcPercentile(data []float64, p float64) float64 {
	sort.Float64s(data)

	k := float64(len(data)-1) * p
	f := math.Floor(k)
	c := math.Ceil(k)
	if f == c {
		return data[int(k)]
	} else {
		return data[int(f)]*(c-k) + data[int(c)]*(k-f)
	}
}

func (mongo *MongoHandler) Aggregate(db, collection, metric string) map[string]interface{} {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	pipe := _collection.Pipe(
		[]bson.M{
			{
				"$match": bson.M{
					"m": metric,
				},
			},
			{
				"$group": bson.M{
					"_id": bson.M{
						"metric": "$m",
					},
					"avg": bson.M{"$avg": "$v"},
					"min": bson.M{"$min": "$v"},
					"max": bson.M{"$max": "$v"},
				},
			},
		},
	)
	summaries := []map[string]interface{}{}
	err := pipe.All(&summaries)
	if err != nil {
		log.Fatal(err)
	}
	summary := summaries[0]
	delete(summary, "_id")

	var docs []map[string]interface{}
	err = _collection.Find(bson.M{"m": metric}).Select(bson.M{"v": 1}).All(&docs)
	if err != nil {
		log.Fatal(err)
	}
	values := []float64{}
	for _, doc := range docs {
		values = append(values, doc["v"].(float64))
	}
	for _, percentile := range []float64{0.8, 0.9, 0.95, 0.99} {
		p := fmt.Sprintf("p%v", percentile*100)
		summary[p] = calcPercentile(values, percentile)
	}

	return summary
}
<commit_msg>ensure index on timestamps (for sorting)<commit_after>package main

import (
	"fmt"
	"log"
	"math"
	"sort"
	"strings"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type MongoHandler struct {
	Session *mgo.Session
}

func (mongo *MongoHandler) Init() {
	dialInfo := &mgo.DialInfo{
		Addrs:   []string{"127.0.0.1"},
		Timeout: 10 * time.Minute,
	}

	var err error
	mongo.Session, err = mgo.DialWithInfo(dialInfo)
	if err != nil {
		log.Fatal(err)
	}
	mongo.Session.SetMode(mgo.Monotonic, true)
}

func (mongo *MongoHandler) ListDatabases() []string {
	all_dbs, err := mongo.Session.DatabaseNames()
	if err != nil {
		log.Fatal(err)
	}

	dbs := []string{}
	for _, db := range all_dbs {
		if strings.HasPrefix(db, "perf") {
			dbs = append(dbs, strings.Replace(db, "perf", "", 1))
		}
	}
	return dbs
}

func (mongo *MongoHandler) ListCollections(db string) []string {
	session := mongo.Session.New()
	defer session.Close()
	_db := session.DB(db)

	all_collections, err := _db.CollectionNames()
	if err != nil {
		log.Fatal(err)
	}

	collections := []string{}
	for _, collection := range all_collections {
		if collection != "system.indexes" {
			collections = append(collections, collection)
		}
	}
	return collections
}

func (mongo *MongoHandler) ListMetrics(db, collection string) []string {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	var metrics []string
	err := _collection.Find(bson.M{}).Distinct("m", &metrics)
	if err != nil {
		log.Fatal(err)
	}
	return metrics
}

func (mongo *MongoHandler) FindValues(db, collection, metric string) map[string]float64 {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	var docs []map[string]interface{}
	err := _collection.Find(bson.M{"m": metric}).Sort("ts").All(&docs)
	if err != nil {
		log.Fatal(err)
	}

	values := map[string]float64{}
	for _, doc := range docs {
		values[doc["ts"].(string)] = doc["v"].(float64)
	}

	return values
}

func (mongo *MongoHandler) InsertSample(db, collection string, sample map[string]interface{}) {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	err := _collection.Insert(sample)
	if err != nil {
		log.Fatal(err)
	}

	err = _collection.EnsureIndexKey("m")
	if err != nil {
		log.Fatal(err)
	}
	err = _collection.EnsureIndexKey("ts")
	if err != nil {
		log.Fatal(err)
	}
}

func calcPercentile(data []float64, p float64) float64 {
	sort.Float64s(data)

	k := float64(len(data)-1) * p
	f := math.Floor(k)
	c := math.Ceil(k)
	if f == c {
		return data[int(k)]
	} else {
		return data[int(f)]*(c-k) + data[int(c)]*(k-f)
	}
}

func (mongo *MongoHandler) Aggregate(db, collection, metric string) map[string]interface{} {
	session := mongo.Session.New()
	defer session.Close()
	_collection := session.DB(db).C(collection)

	pipe := _collection.Pipe(
		[]bson.M{
			{
				"$match": bson.M{
					"m": metric,
				},
			},
			{
				"$group": bson.M{
					"_id": bson.M{
						"metric": "$m",
					},
					"avg": bson.M{"$avg": "$v"},
					"min": bson.M{"$min": "$v"},
					"max": bson.M{"$max": "$v"},
				},
			},
		},
	)
	summaries := []map[string]interface{}{}
	err := pipe.All(&summaries)
	if err != nil {
		log.Fatal(err)
	}
	summary := summaries[0]
	delete(summary, "_id")

	var docs []map[string]interface{}
	err = _collection.Find(bson.M{"m": metric}).Select(bson.M{"v": 1}).All(&docs)
	if err != nil {
		log.Fatal(err)
	}
	values := []float64{}
	for _, doc := range docs {
		values = append(values, doc["v"].(float64))
	}
	for _, percentile := range []float64{0.8, 0.9, 0.95, 0.99} {
		p := fmt.Sprintf("p%v", percentile*100)
		summary[p] = calcPercentile(values, percentile)
	}

	return summary
}
<|endoftext|>


<commit_before>package sia

import (
	"errors"

	"github.com/NebulousLabs/Sia/consensus"
	"github.com/NebulousLabs/Sia/network"
)

const (
	MaxCatchUpBlocks = 100
)

var moreBlocksErr = errors.New("more blocks are available")

// SendBlocks takes a list of block ids as input, and sends all blocks from
func (c *Core) SendBlocks(knownBlocks [32]consensus.BlockID) (blocks []consensus.Block, err error) {
	// Find the most recent block from knownBlocks that is in our current path.
	found := false
	var highest consensus.BlockHeight
	for _, id := range knownBlocks {
		height, err := c.state.HeightOfBlock(id)
		if err == nil {
			found = true
			if height > highest {
				highest = height
			}
		}
	}
	if !found {
		// The genesis block should be included in knownBlocks - if no matching
		// blocks are found the caller is probably on a different blockchain
		// altogether.
		err = errors.New("no matching block found")
		return
	}

	// Send blocks, starting with the child of the most recent known block.
	start := highest + 1
	for i := start; i < start+MaxCatchUpBlocks; i++ {
		b, err := c.state.BlockAtHeight(i)
		if err != nil {
			break
		}
		blocks = append(blocks, b)
	}

	// If more blocks are available, send a benign error
	if _, maxErr := c.state.BlockAtHeight(start + MaxCatchUpBlocks); maxErr == nil {
		err = moreBlocksErr
	}

	return
}

// CatchUp synchronizes with a peer to acquire any missing blocks. The
// requester sends 32 blocks, starting with the 12 most recent and then
// progressing exponentially backwards to the genesis block. The receiver uses
// these blocks to find the most recent block seen by both peers, and then
// transmits blocks sequentially until the requester is fully synchronized.
func (c *Core) CatchUp(peer network.Address) {
	knownBlocks := make([]consensus.BlockID, 0, 32)
	for i := consensus.BlockHeight(0); i < 12; i++ {
		block, badBlockErr := c.state.BlockAtHeight(c.state.Height() - i)
		if badBlockErr != nil {
			break
		}
		knownBlocks = append(knownBlocks, block.ID())
	}

	backtrace := consensus.BlockHeight(12)
	for i := 12; i < 31; i++ {
		backtrace *= 2
		block, badBlockErr := c.state.BlockAtHeight(c.state.Height() - backtrace)
		if badBlockErr != nil {
			break
		}
		knownBlocks = append(knownBlocks, block.ID())
	}
	// always include the genesis block
	genesis, _ := c.state.BlockAtHeight(0)
	knownBlocks = append(knownBlocks, genesis.ID())

	// prepare for RPC
	var newBlocks []consensus.Block
	var blockArray [32]consensus.BlockID
	copy(blockArray[:], knownBlocks)

	// unlock state during network I/O
	err := peer.RPC("SendBlocks", blockArray, &newBlocks)
	if err != nil && err.Error() != moreBlocksErr.Error() {
		// log error
		// TODO: try a different peer?
		return
	}
	for _, block := range newBlocks {
		c.AcceptBlock(block)
	}

	// TODO: There is probably a better approach than to call CatchUp
	// recursively. Furthermore, if there is a reorg that's greater than 100
	// blocks, CatchUp is going to fail outright.
	if err != nil && err.Error() == moreBlocksErr.Error() {
		go c.CatchUp(peer)
	}
}
<commit_msg>fix catch up overlapping<commit_after>package sia

import (
	"errors"
	"time"

	"github.com/NebulousLabs/Sia/consensus"
	"github.com/NebulousLabs/Sia/network"
)

const (
	MaxCatchUpBlocks = 100
)

var moreBlocksErr = errors.New("more blocks are available")

// SendBlocks takes a list of block ids as input, and sends all blocks from
func (c *Core) SendBlocks(knownBlocks [32]consensus.BlockID) (blocks []consensus.Block, err error) {
	// Find the most recent block from knownBlocks that is in our current path.
	found := false
	var highest consensus.BlockHeight
	for _, id := range knownBlocks {
		height, err := c.state.HeightOfBlock(id)
		if err == nil {
			found = true
			if height > highest {
				highest = height
			}
		}
	}
	if !found {
		// The genesis block should be included in knownBlocks - if no matching
		// blocks are found the caller is probably on a different blockchain
		// altogether.
		err = errors.New("no matching block found")
		return
	}

	// Send blocks, starting with the child of the most recent known block.
	start := highest + 1
	for i := start; i < start+MaxCatchUpBlocks; i++ {
		b, err := c.state.BlockAtHeight(i)
		if err != nil {
			break
		}
		blocks = append(blocks, b)
	}

	// If more blocks are available, send a benign error
	if _, maxErr := c.state.BlockAtHeight(start + MaxCatchUpBlocks); maxErr == nil {
		err = moreBlocksErr
	}

	return
}

// CatchUp synchronizes with a peer to acquire any missing blocks. The
// requester sends 32 blocks, starting with the 12 most recent and then
// progressing exponentially backwards to the genesis block. The receiver uses
// these blocks to find the most recent block seen by both peers, and then
// transmits blocks sequentially until the requester is fully synchronized.
func (c *Core) CatchUp(peer network.Address) {
	knownBlocks := make([]consensus.BlockID, 0, 32)
	for i := consensus.BlockHeight(0); i < 12; i++ {
		block, badBlockErr := c.state.BlockAtHeight(c.state.Height() - i)
		if badBlockErr != nil {
			break
		}
		knownBlocks = append(knownBlocks, block.ID())
	}

	backtrace := consensus.BlockHeight(12)
	for i := 12; i < 31; i++ {
		backtrace *= 2
		block, badBlockErr := c.state.BlockAtHeight(c.state.Height() - backtrace)
		if badBlockErr != nil {
			break
		}
		knownBlocks = append(knownBlocks, block.ID())
	}
	// always include the genesis block
	genesis, _ := c.state.BlockAtHeight(0)
	knownBlocks = append(knownBlocks, genesis.ID())

	// prepare for RPC
	var newBlocks []consensus.Block
	var blockArray [32]consensus.BlockID
	copy(blockArray[:], knownBlocks)

	// unlock state during network I/O
	err := peer.RPC("SendBlocks", blockArray, &newBlocks)
	if err != nil && err.Error() != moreBlocksErr.Error() {
		// log error
		// TODO: try a different peer?
		return
	}
	for _, block := range newBlocks {
		c.AcceptBlock(block)
	}

	// TODO: There is probably a better approach than to call CatchUp
	// recursively. Furthermore, if there is a reorg that's greater than 100
	// blocks, CatchUp is going to fail outright.
	if err != nil && err.Error() == moreBlocksErr.Error() {
		// sleep long enough for state to accept all blocks
		// TODO: this needs to be replaced by a more deterministic wait.
		time.Sleep(time.Second)
		go c.CatchUp(peer)
	}
}
<|endoftext|>


<commit_before>package db

import (
	"io/ioutil"
	"log"
	"math/rand"
	"strings"
)

var links []string

func initLinks() {
	content, err := ioutil.ReadFile("resources/links.txt")
	if err != nil {
		log.Fatal(err)
	}
	links = strings.Split(string(content), "\n")
}

func RandomLinks() []string {
	var r []string
	for i := 0; i < 3; i++ {
		r = append(r, links[rand.Intn(len(links))])
	}
	return r
}
<commit_msg>Avoid returning duplicate random links in query answers<commit_after>package db

import (
	"io/ioutil"
	"log"
	"math/rand"
	"strings"
)

var links []string

func initLinks() {
	content, err := ioutil.ReadFile("resources/links.txt")
	if err != nil {
		log.Fatal(err)
	}
	links = strings.Split(string(content), "\n")
}

func RandomLinks() []string {
	// urls of chosen random links
	var r []string
	// size of this map used to check when 3 unique links have been selected
	m := make(map[int]bool)

	for len(m) < 3 {
		i := rand.Intn(len(links))
		if !m[i] {
			m[i] = true
			r = append(r, links[i])
		}
	}
	return r
}
<|endoftext|>


<commit_before>package sitegen

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/russross/blackfriday"
	"gopkg.in/yaml.v1"
)

func Start() {
	templates = template.Must(template.ParseGlob("templates/*.html"))

	// Crawl the filesystem tree.
	log.Println("==> Crawling")
	content, err := crawlContent()
	if err != nil {
		log.Fatal(err)
	}

	// Wait for parsing
	log.Println("==> Parsing")
	if parseError != nil {
		log.Fatal(parseError)
	}

	// Allow processing metadata
	if processor != nil {
		log.Println("==> Processing")
		content.Process()
		if processError != nil {
			log.Fatal(processError)
		}
	}

	// Generate the output
	log.Println("==> Generating")
	err = os.MkdirAll("static", 0755)
	if err != nil {
		log.Fatal(err)
	}

	content.Write("static")
	if generateError != nil {
		log.Fatal(generateError)
	}
}

var (
	parseError    error = nil
	processError  error = nil
	generateError error = nil
	templates     *template.Template

	processor MetadataProcessor
)

type ContentItem struct {
	Filename string
	FullPath string
	Url      string
	Type     ContentType
	Content  template.HTML
	Children []*ContentItem
	Metadata Metadata
	Extra    interface{}
}

type Metadata struct {
	Title    string
	Template string
}

type ContentType int

const (
	Content ContentType = iota
	Directory
	Asset
)

func crawlContent() (*ContentItem, error) {
	return readDir(".", "content")
}

func readDir(name, path string) (*ContentItem, error) {
	fullPath := path + "/" + name
	files, err := ioutil.ReadDir(fullPath)
	if err != nil {
		return nil, err
	}

	c := &ContentItem{
		Filename: name,
		FullPath: fullPath,
		Type:     Directory,
		Children: make([]*ContentItem, 0),
	}

	for _, v := range files {
		var child *ContentItem

		filename := v.Name()
		if isContentFile(filename) {
			parts := strings.Split(filename, ".")
			outname := strings.Join(parts[0:len(parts)-1], ".") + ".html"
			child = &ContentItem{
				Filename: outname,
				FullPath: fullPath + "/" + filename,
				Type:     Content,
			}
			child.Parse(fullPath + "/" + filename)
		} else if v.IsDir() {
			child, err = readDir(filename, fullPath)
			if err != nil {
				return nil, err
			}
		} else {
			child = &ContentItem{
				Filename: filename,
				FullPath: fullPath + "/" + filename,
				Type:     Asset,
			}
		}
		c.Children = append(c.Children, child)
	}

	return c, nil
}

func isContentFile(filename string) bool {
	return strings.HasSuffix(filename, ".html") || strings.HasSuffix(filename, ".md")
}

func splitContent(content []byte) (frontMatter, body []byte, err error) {
	startDelim := []byte("---\n")
	endDelim := []byte("\n---\n\n")
	if bytes.HasPrefix(content, startDelim) {
		endIndex := bytes.Index(content, endDelim)
		if endIndex == -1 {
			err = errors.New("No end delimiter found for metadata!")
			return
		}

		frontMatter = content[len(startDelim):endIndex]
		body = content[endIndex+len(endDelim) : len(content)]
	} else {
		frontMatter = nil
		body = content
	}
	return
}

func (c *ContentItem) parseContent(filename string) error {
	printName := strings.TrimPrefix(filename, "content/.")
	log.Printf(" -> %s\n", printName)

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	frontMatter, body, err := splitContent(data)
	if err != nil {
		return err
	}

	if frontMatter != nil {
		yaml.Unmarshal(frontMatter, &c.Metadata)
	}

	if c.Metadata.Template == "" {
		c.Metadata.Template = "page"
	}

	var content []byte
	if strings.HasSuffix(filename, ".md") {
		content = RenderMarkdown(body)
	} else {
		content = body
	}
	c.Content = template.HTML(content)
	return nil
}

func RenderMarkdown(input []byte) []byte {
	// set up the HTML renderer
	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_USE_XHTML
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	htmlFlags |= blackfriday.HTML_FOOTNOTE_RETURN_LINKS
	renderer := blackfriday.HtmlRendererWithParameters(htmlFlags, "", "", blackfriday.HtmlRendererParameters{
		FootnoteReturnLinkContents: "↩",
	})

	// set up the parser
	extensions := 0
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_HEADER_IDS
	extensions |= blackfriday.EXTENSION_FOOTNOTES

	return blackfriday.Markdown(input, renderer, extensions)
}

func (c *ContentItem) Parse(filename string) {
	err := c.parseContent(filename)
	if err != nil {
		parseError = err
	}
}

func (c *ContentItem) Process() {
	c.Url = strings.TrimPrefix(c.FullPath, "content/.")
	extra, err := processor(c)
	if err != nil {
		processError = err
		return
	}
	c.Extra = extra

	for _, v := range c.Children {
		v.Process()
	}
}

func (c *ContentItem) Write(path string) {
	fullPath := path + "/" + c.Filename
	printName := strings.TrimPrefix(fullPath, "static/.")
	if printName != "" {
		log.Printf(" -> %s\n", printName)
	}

	if c.Type == Directory {
		err := os.MkdirAll(fullPath, 0755)
		if err != nil {
			generateError = err
			return
		}
	} else if c.Type == Content {
		err := c.WriteContent(fullPath)
		if err != nil {
			generateError = err
			return
		}
	} else if c.Type == Asset {
		out := strings.Replace(c.FullPath, "content/.", "static", 1)
		err := copyFile(c.FullPath, out)
		if err != nil {
			generateError = err
			return
		}
	}

	for _, v := range c.Children {
		v.Write(fullPath)
	}
}

func (c *ContentItem) WriteContent(path string) error {
	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer out.Close()
	return templates.ExecuteTemplate(out, c.Metadata.Template, c)
}

// Metadata processing
type MetadataProcessor func(item *ContentItem) (interface{}, error)

func SetMetadataProcessor(f MetadataProcessor) {
	processor = f
}

// Utilities

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

// copyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func copyFile(src, dst string) (err error) {
	sfi, err := os.Stat(src)
	if err != nil {
		return
	}
	if !sfi.Mode().IsRegular() {
		// cannot copy non-regular files (e.g., directories,
		// symlinks, devices, etc.)
		return fmt.Errorf("copyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
	}
	dfi, err := os.Stat(dst)
	if err != nil {
		if !os.IsNotExist(err) {
			return
		}
	} else {
		if !(dfi.Mode().IsRegular()) {
			return fmt.Errorf("copyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
		}
		if os.SameFile(sfi, dfi) {
			return
		}
	}
	if err = os.Link(src, dst); err == nil {
		return
	}
	return copyFileContents(src, dst)
}

// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}
	err = out.Sync()
	return
}
<commit_msg>Add ugly hack to parse date/time.<commit_after>package sitegen

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"

	"github.com/russross/blackfriday"
	"gopkg.in/yaml.v2"
)

func Start() {
	templates = template.Must(template.ParseGlob("templates/*.html"))

	// Crawl the filesystem tree.
	log.Println("==> Crawling")
	content, err := crawlContent()
	if err != nil {
		log.Fatal(err)
	}

	// Wait for parsing
	log.Println("==> Parsing")
	if parseError != nil {
		log.Fatal(parseError)
	}

	// Allow processing metadata
	if processor != nil {
		log.Println("==> Processing")
		content.Process()
		if processError != nil {
			log.Fatal(processError)
		}
	}

	// Generate the output
	log.Println("==> Generating")
	err = os.MkdirAll("static", 0755)
	if err != nil {
		log.Fatal(err)
	}

	content.Write("static")
	if generateError != nil {
		log.Fatal(generateError)
	}
}

var (
	parseError    error = nil
	processError  error = nil
	generateError error = nil
	templates     *template.Template

	processor MetadataProcessor
)

type ContentItem struct {
	Filename string
	FullPath string
	Url      string
	Type     ContentType
	Content  template.HTML
	Children []*ContentItem
	Metadata Metadata
	Extra    interface{}
}

type Metadata struct {
	Title    string
	Template string
	Date     time.Time
}

type metadataTime struct {
	Title    string
	Template string
	Date     string
}

type ContentType int

const (
	Content ContentType = iota
	Directory
	Asset
)

func crawlContent() (*ContentItem, error) {
	return readDir(".", "content")
}

func readDir(name, path string) (*ContentItem, error) {
	fullPath := path + "/" + name
	files, err := ioutil.ReadDir(fullPath)
	if err != nil {
		return nil, err
	}

	c := &ContentItem{
		Filename: name,
		FullPath: fullPath,
		Type:     Directory,
		Children: make([]*ContentItem, 0),
	}

	for _, v := range files {
		var child *ContentItem

		filename := v.Name()
		if isContentFile(filename) {
			parts := strings.Split(filename, ".")
			outname := strings.Join(parts[0:len(parts)-1], ".") + ".html"
			child = &ContentItem{
				Filename: outname,
				FullPath: fullPath + "/" + filename,
				Type:     Content,
			}
			child.Parse(fullPath + "/" + filename)
		} else if v.IsDir() {
			child, err = readDir(filename, fullPath)
			if err != nil {
				return nil, err
			}
		} else {
			child = &ContentItem{
				Filename: filename,
				FullPath: fullPath + "/" + filename,
				Type:     Asset,
			}
		}
		c.Children = append(c.Children, child)
	}

	return c, nil
}

func isContentFile(filename string) bool {
	return strings.HasSuffix(filename, ".html") || strings.HasSuffix(filename, ".md")
}

func splitContent(content []byte) (frontMatter, body []byte, err error) {
	startDelim := []byte("---\n")
	endDelim := []byte("\n---\n\n")
	if bytes.HasPrefix(content, startDelim) {
		endIndex := bytes.Index(content, endDelim)
		if endIndex == -1 {
			err = errors.New("No end delimiter found for metadata!")
			return
		}

		frontMatter = content[len(startDelim):endIndex]
		body = content[endIndex+len(endDelim) : len(content)]
	} else {
		frontMatter = nil
		body = content
	}
	return
}

func (c *ContentItem) parseContent(filename string) error {
	printName := strings.TrimPrefix(filename, "content/.")
	log.Printf(" -> %s\n", printName)

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	frontMatter, body, err := splitContent(data)
	if err != nil {
		return err
	}

	if frontMatter != nil {
		yaml.Unmarshal(frontMatter, &c.Metadata)
	}

	if c.Metadata.Template == "" {
		c.Metadata.Template = "page"
	}

	var content []byte
	if strings.HasSuffix(filename, ".md") {
		content = RenderMarkdown(body)
	} else {
		content = body
	}
	c.Content = template.HTML(content)
	return nil
}

func RenderMarkdown(input []byte) []byte {
	// set up the HTML renderer
	htmlFlags := 0
	htmlFlags |= blackfriday.HTML_USE_XHTML
	htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
	htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
	htmlFlags |= blackfriday.HTML_FOOTNOTE_RETURN_LINKS
	renderer := blackfriday.HtmlRendererWithParameters(htmlFlags, "", "", blackfriday.HtmlRendererParameters{
		FootnoteReturnLinkContents: "↩",
	})

	// set up the parser
	extensions := 0
	extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
	extensions |= blackfriday.EXTENSION_TABLES
	extensions |= blackfriday.EXTENSION_FENCED_CODE
	extensions |= blackfriday.EXTENSION_AUTOLINK
	extensions |= blackfriday.EXTENSION_STRIKETHROUGH
	extensions |= blackfriday.EXTENSION_SPACE_HEADERS
	extensions |= blackfriday.EXTENSION_HEADER_IDS
	extensions |= blackfriday.EXTENSION_FOOTNOTES

	return blackfriday.Markdown(input, renderer, extensions)
}

func (c *ContentItem) Parse(filename string) {
	err := c.parseContent(filename)
	if err != nil {
		parseError = err
	}
}

func (c *ContentItem) Process() {
	c.Url = strings.TrimPrefix(c.FullPath, "content/.")
	extra, err := processor(c)
	if err != nil {
		processError = err
		return
	}
	c.Extra = extra

	for _, v := range c.Children {
		v.Process()
	}
}

func (c *ContentItem) Write(path string) {
	fullPath := path + "/" + c.Filename
	printName := strings.TrimPrefix(fullPath, "static/.")
	if printName != "" {
		log.Printf(" -> %s\n", printName)
	}

	if c.Type == Directory {
		err := os.MkdirAll(fullPath, 0755)
		if err != nil {
			generateError = err
			return
		}
	} else if c.Type == Content {
		err := c.WriteContent(fullPath)
		if err != nil {
			generateError = err
			return
		}
	} else if c.Type == Asset {
		out := strings.Replace(c.FullPath, "content/.", "static", 1)
		err := copyFile(c.FullPath, out)
		if err != nil {
			generateError = err
			return
		}
	}

	for _, v := range c.Children {
		v.Write(fullPath)
	}
}

func (c *ContentItem) WriteContent(path string) error {
	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer out.Close()
	return templates.ExecuteTemplate(out, c.Metadata.Template, c)
}

// Metadata processing
type MetadataProcessor func(item *ContentItem) (interface{}, error)

func SetMetadataProcessor(f MetadataProcessor) {
	processor = f
}

// Time handling
func (m *Metadata) UnmarshalYAML(unmarshal func(interface{}) error) error {
	md := &metadataTime{}
	if err := unmarshal(md); err != nil {
		return err
	}

	loc, _ := time.LoadLocation("Europe/Brussels")
	t, err := time.ParseInLocation("2006-01-02 15:04:05", md.Date, loc)
	if err != nil {
		return err
	}

	m.Title = md.Title
	m.Template = md.Template
	m.Date = t
	return nil
}

// Utilities

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

// copyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func copyFile(src, dst string) (err error) {
	sfi, err := os.Stat(src)
	if err != nil {
		return
	}
	if !sfi.Mode().IsRegular() {
		// cannot copy non-regular files (e.g., directories,
		// symlinks, devices, etc.)
		return fmt.Errorf("copyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
	}
	dfi, err := os.Stat(dst)
	if err != nil {
		if !os.IsNotExist(err) {
			return
		}
	} else {
		if !(dfi.Mode().IsRegular()) {
			return fmt.Errorf("copyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
		}
		if os.SameFile(sfi, dfi) {
			return
		}
	}
	if err = os.Link(src, dst); err == nil {
		return
	}
	return copyFileContents(src, dst)
}

// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}
	err = out.Sync()
	return
}
<|endoftext|>


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

package siv

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"strconv"
	"testing"
)

func TestXorend(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func fromBinary(s string) byte {
	AssertEq(8, len(s), "%s", s)

	u, err := strconv.ParseUint(s, 2, 8)
	AssertEq(nil, err, "%s", s)

	return byte(u)
}

type XorendTest struct{}

func init() { RegisterTestSuite(&XorendTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *XorendTest) AIsShorterThanB() {
	a := []byte{0xde}
	b := []byte{0xde, 0xad}

	f := func() { xorend(a, b) }
	ExpectThat(f, Panics(HasSubstr("length")))
}

func (t *XorendTest) BothAreNil() {
	a := []byte(nil)
	b := []byte(nil)

	expected := []byte(nil)
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsNil() {
	a := []byte{fromBinary("10101010"), fromBinary("00000000")}
	b := []byte(nil)

	expected := a
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BothAreEmpty() {
	a := []byte{}
	b := []byte{}

	expected := []byte{}
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsEmpty() {
	a := []byte{fromBinary("10101010"), fromBinary("00000000")}
	b := []byte{}

	expected := a
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsNonEmpty() {
	a := []byte{
		fromBinary("11110000"),
		fromBinary("10101010"),
		fromBinary("00000000"),
	}

	b := []byte{
		fromBinary("11110000"),
		fromBinary("00001111"),
	}

	expected := []byte{
		fromBinary("11110000"),
		fromBinary("01011010"),
		fromBinary("00001111"),
	}

	ExpectThat(xorend(a, b), DeepEquals(expected))
}
<commit_msg>XorendTest.DoesntClobberInputData<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package siv

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"strconv"
	"testing"
)

func TestXorend(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func fromBinary(s string) byte {
	AssertEq(8, len(s), "%s", s)

	u, err := strconv.ParseUint(s, 2, 8)
	AssertEq(nil, err, "%s", s)

	return byte(u)
}

type XorendTest struct{}

func init() { RegisterTestSuite(&XorendTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *XorendTest) AIsShorterThanB() {
	a := []byte{0xde}
	b := []byte{0xde, 0xad}

	f := func() { xorend(a, b) }
	ExpectThat(f, Panics(HasSubstr("length")))
}

func (t *XorendTest) BothAreNil() {
	a := []byte(nil)
	b := []byte(nil)

	expected := []byte(nil)
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsNil() {
	a := []byte{fromBinary("10101010"), fromBinary("00000000")}
	b := []byte(nil)

	expected := a
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BothAreEmpty() {
	a := []byte{}
	b := []byte{}

	expected := []byte{}
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsEmpty() {
	a := []byte{fromBinary("10101010"), fromBinary("00000000")}
	b := []byte{}

	expected := a
	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) BIsNonEmpty() {
	a := []byte{
		fromBinary("11110000"),
		fromBinary("10101010"),
		fromBinary("00000000"),
	}

	b := []byte{
		fromBinary("11110000"),
		fromBinary("00001111"),
	}

	expected := []byte{
		fromBinary("11110000"),
		fromBinary("01011010"),
		fromBinary("00001111"),
	}

	ExpectThat(xorend(a, b), DeepEquals(expected))
}

func (t *XorendTest) DoesntClobberInputData() {
	a := []byte{
		fromBinary("11110000"),
		fromBinary("10101010"),
		fromBinary("00000000"),
	}
	aCopy := dup(a)

	b := []byte{
		fromBinary("11110000"),
		fromBinary("00001111"),
	}
	bCopy := dup(b)

	xorend(a, b)
	ExpectThat(a, DeepEquals(aCopy))
	ExpectThat(b, DeepEquals(bCopy))
}
<|endoftext|>


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

// Package build gathers information about Go packages.
//
// Go Path
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
// Go tree.  The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
// on Plan 9, a list).
//
// Each directory listed in the Go path must have a prescribed structure:
//
// The src/ directory holds source code.  The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
// As in the Go tree, each target operating system and
// architecture pair has its own subdirectory of pkg
// (pkg/GOOS_GOARCH).
//
// If DIR is a directory listed in the Go path, a package with
// source in DIR/src/foo/bar can be imported as "foo/bar" and
// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
// using the final element, not the entire path.  That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
// Here's an example directory layout:
//
//	GOPATH=/home/user/gocode
//
//	/home/user/gocode/
//	    src/
//	        foo/
//	            bar/               (go code in package bar)
//	                x.go
//	            quux/              (go code in package main)
//	                y.go
//	    bin/
//	        quux                   (installed command)
//	    pkg/
//	        linux_amd64/
//	            foo/
//	                bar.a          (installed package object)
//
// Build Constraints
//
// A build constraint is a line comment beginning with the directive +build
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments.
//
// A build constraint is evaluated as the OR of space-separated options;
// each option evaluates as the AND of its comma-separated terms;
// and each term is an alphanumeric word or, preceded by !, its negation.
// That is, the build constraint:
//
//	// +build linux,386 darwin,!cgo
//
// corresponds to the boolean formula:
//
//	(linux AND 386) OR (darwin AND (NOT cgo))
//
// During a particular build, the following words are satisfied:
//
//	- the target operating system, as spelled by runtime.GOOS
//	- the target architecture, as spelled by runtime.GOARCH
//	- "cgo", if ctxt.CgoEnabled is true
//	- any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
// system and architecture values, then the file is considered to have an implicit
// build constraint requiring those terms.
//
// To keep a file from being considered for the build:
//
//	// +build ignore
//
// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
//	// +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
//	// +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
package build
<commit_msg>go/build: document the behavior of multiple build constraints.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build gathers information about Go packages.
//
// Go Path
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
// Go tree.  The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
// on Plan 9, a list).
//
// Each directory listed in the Go path must have a prescribed structure:
//
// The src/ directory holds source code.  The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
// As in the Go tree, each target operating system and
// architecture pair has its own subdirectory of pkg
// (pkg/GOOS_GOARCH).
//
// If DIR is a directory listed in the Go path, a package with
// source in DIR/src/foo/bar can be imported as "foo/bar" and
// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
// using the final element, not the entire path.  That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
// Here's an example directory layout:
//
//	GOPATH=/home/user/gocode
//
//	/home/user/gocode/
//	    src/
//	        foo/
//	            bar/               (go code in package bar)
//	                x.go
//	            quux/              (go code in package main)
//	                y.go
//	    bin/
//	        quux                   (installed command)
//	    pkg/
//	        linux_amd64/
//	            foo/
//	                bar.a          (installed package object)
//
// Build Constraints
//
// A build constraint is a line comment beginning with the directive +build
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments.
//
// A build constraint is evaluated as the OR of space-separated options;
// each option evaluates as the AND of its comma-separated terms;
// and each term is an alphanumeric word or, preceded by !, its negation.
// That is, the build constraint:
//
//	// +build linux,386 darwin,!cgo
//
// corresponds to the boolean formula:
//
//	(linux AND 386) OR (darwin AND (NOT cgo))
//
// A file may have multiple build constraints. The overall constraint is the AND
// of the individual constraints. That is, the build constraints:
//
//	// +build linux darwin
//	// +build 386
//
// corresponds to the boolean formula:
//
//	(linux OR darwin) AND 386
//
// During a particular build, the following words are satisfied:
//
//	- the target operating system, as spelled by runtime.GOOS
//	- the target architecture, as spelled by runtime.GOARCH
//	- "cgo", if ctxt.CgoEnabled is true
//	- any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
// system and architecture values, then the file is considered to have an implicit
// build constraint requiring those terms.
//
// To keep a file from being considered for the build:
//
//	// +build ignore
//
// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
//	// +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
//	// +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
package build
<|endoftext|>


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

package http

import (
	"bufio"
	"io"
	"net"
	"net/textproto"
	"os"
	"sync"
)

var (
	ErrPersistEOF = &ProtocolError{"persistent connection closed"}
	ErrPipeline   = &ProtocolError{"pipeline error"}
)

// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// does not close the underlying connection. Instead, the user calls Close
// and regains control over the connection. ServerConn supports pipe-lining,
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
type ServerConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe textproto.Pipeline
}

// NewServerConn returns a new ServerConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ServerConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before Read has signaled the end of the keep-alive logic. The user
// should not call Close while Read or Write is in progress.
func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	c = sc.c
	r = sc.r
	sc.c = nil
	sc.r = nil
	return
}

// Read returns the next request on the wire. An ErrPersistEOF is returned if
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
func (sc *ServerConn) Read() (req *Request, err os.Error) {

	// Ensure ordered execution of Reads and Writes
	id := sc.pipe.Next()
	sc.pipe.StartRequest(id)
	defer func() {
		sc.pipe.EndRequest(id)
		if req == nil {
			sc.pipe.StartResponse(id)
			sc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			sc.lk.Lock()
			sc.pipereq[req] = id
			sc.lk.Unlock()
		}
	}()

	sc.lk.Lock()
	if sc.we != nil { // no point receiving if write-side broken or closed
		defer sc.lk.Unlock()
		return nil, sc.we
	}
	if sc.re != nil {
		defer sc.lk.Unlock()
		return nil, sc.re
	}
	if sc.r == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return nil, os.EBADF
	}
	r := sc.r
	lastbody := sc.lastbody
	sc.lastbody = nil
	sc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			sc.lk.Lock()
			defer sc.lk.Unlock()
			sc.re = err
			return nil, err
		}
	}

	req, err = ReadRequest(r)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			// A close from the opposing client is treated as a
			// graceful close, even if there was some unparse-able
			// data before the close.
			sc.re = ErrPersistEOF
			return nil, sc.re
		} else {
			sc.re = err
			return req, err
		}
	}
	sc.lastbody = req.Body
	sc.nread++
	if req.Close {
		sc.re = ErrPersistEOF
		return req, sc.re
	}
	return req, err
}

// Pending returns the number of unanswered requests
// that have been received on the connection.
func (sc *ServerConn) Pending() int {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	return sc.nread - sc.nwritten
}

// Write writes resp in response to req. To close the connection gracefully, set the
// Response.Close field to true. Write should be considered operational until
// it returns an error, regardless of any errors returned on the Read side.
func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {

	// Retrieve the pipeline ID of this request/response pair
	sc.lk.Lock()
	id, ok := sc.pipereq[req]
	sc.pipereq[req] = 0, false
	if !ok {
		sc.lk.Unlock()
		return ErrPipeline
	}
	sc.lk.Unlock()

	// Ensure pipeline order
	sc.pipe.StartResponse(id)
	defer sc.pipe.EndResponse(id)

	sc.lk.Lock()
	if sc.we != nil {
		defer sc.lk.Unlock()
		return sc.we
	}
	if sc.c == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return os.EBADF
	}
	c := sc.c
	if sc.nread <= sc.nwritten {
		defer sc.lk.Unlock()
		return os.NewError("persist server pipe count")
	}
	if resp.Close {
		// After signaling a keep-alive close, any pipelined unread
		// requests will be lost. It is up to the user to drain them
		// before signaling.
		sc.re = ErrPersistEOF
	}
	sc.lk.Unlock()

	err := resp.Write(c)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		sc.we = err
		return err
	}
	sc.nwritten++

	return nil
}

// A ClientConn sends request and receives headers over an underlying
// connection, while respecting the HTTP keepalive logic. ClientConn is not
// responsible for closing the underlying connection. One must call Close to
// regain control of that connection and deal with it as desired.
type ClientConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe textproto.Pipeline
}

// NewClientConn returns a new ClientConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ClientConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ClientConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before the user or Read have signaled the end of the keep-alive
// logic. The user should not call Close while Read or Write is in progress.
func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	c = cc.c
	r = cc.r
	cc.c = nil
	cc.r = nil
	return
}

// Write writes a request. An ErrPersistEOF error is returned if the connection
// has been closed in an HTTP keepalive sense. If req.Close equals true, the
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
func (cc *ClientConn) Write(req *Request) (err os.Error) {

	// Ensure ordered execution of Writes
	id := cc.pipe.Next()
	cc.pipe.StartRequest(id)
	defer func() {
		cc.pipe.EndRequest(id)
		if err != nil {
			cc.pipe.StartResponse(id)
			cc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			cc.lk.Lock()
			cc.pipereq[req] = id
			cc.lk.Unlock()
		}
	}()

	cc.lk.Lock()
	if cc.re != nil { // no point sending if read-side closed or broken
		defer cc.lk.Unlock()
		return cc.re
	}
	if cc.we != nil {
		defer cc.lk.Unlock()
		return cc.we
	}
	if cc.c == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return os.EBADF
	}
	c := cc.c
	if req.Close {
		// We write the EOF to the write-side error, because there
		// still might be some pipelined reads
		cc.we = ErrPersistEOF
	}
	cc.lk.Unlock()

	err = req.Write(c)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.we = err
		return err
	}
	cc.nwritten++

	return nil
}

// Pending returns the number of unanswered requests
// that have been sent on the connection.
func (cc *ClientConn) Pending() int {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	return cc.nwritten - cc.nread
}

// Read reads the next response from the wire. A valid response might be
// returned together with an ErrPersistEOF, which means that the remote
// requested that this be the last request serviced. Read can be called
// concurrently with Write, but not with another Read.
func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {

	// Retrieve the pipeline ID of this request/response pair
	cc.lk.Lock()
	id, ok := cc.pipereq[req]
	cc.pipereq[req] = 0, false
	if !ok {
		cc.lk.Unlock()
		return nil, ErrPipeline
	}
	cc.lk.Unlock()

	// Ensure pipeline order
	cc.pipe.StartResponse(id)
	defer cc.pipe.EndResponse(id)

	cc.lk.Lock()
	if cc.re != nil {
		defer cc.lk.Unlock()
		return nil, cc.re
	}
	if cc.r == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return nil, os.EBADF
	}
	r := cc.r
	lastbody := cc.lastbody
	cc.lastbody = nil
	cc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			cc.lk.Lock()
			defer cc.lk.Unlock()
			cc.re = err
			return nil, err
		}
	}

	resp, err = ReadResponse(r, req.Method)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.re = err
		return resp, err
	}
	cc.lastbody = resp.Body

	cc.nread++

	if resp.Close {
		cc.re = ErrPersistEOF // don't send any more requests
		return resp, cc.re
	}
	return resp, err
}

// Do is convenience method that writes a request and reads a response.
func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
	err = cc.Write(req)
	if err != nil {
		return
	}
	return cc.Read(req)
}
<commit_msg>http: add NewProxyClientConn<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

import (
	"bufio"
	"io"
	"net"
	"net/textproto"
	"os"
	"sync"
)

var (
	ErrPersistEOF = &ProtocolError{"persistent connection closed"}
	ErrPipeline   = &ProtocolError{"pipeline error"}
)

// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// does not close the underlying connection. Instead, the user calls Close
// and regains control over the connection. ServerConn supports pipe-lining,
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
type ServerConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe textproto.Pipeline
}

// NewServerConn returns a new ServerConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ServerConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before Read has signaled the end of the keep-alive logic. The user
// should not call Close while Read or Write is in progress.
func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	c = sc.c
	r = sc.r
	sc.c = nil
	sc.r = nil
	return
}

// Read returns the next request on the wire. An ErrPersistEOF is returned if
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
func (sc *ServerConn) Read() (req *Request, err os.Error) {

	// Ensure ordered execution of Reads and Writes
	id := sc.pipe.Next()
	sc.pipe.StartRequest(id)
	defer func() {
		sc.pipe.EndRequest(id)
		if req == nil {
			sc.pipe.StartResponse(id)
			sc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			sc.lk.Lock()
			sc.pipereq[req] = id
			sc.lk.Unlock()
		}
	}()

	sc.lk.Lock()
	if sc.we != nil { // no point receiving if write-side broken or closed
		defer sc.lk.Unlock()
		return nil, sc.we
	}
	if sc.re != nil {
		defer sc.lk.Unlock()
		return nil, sc.re
	}
	if sc.r == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return nil, os.EBADF
	}
	r := sc.r
	lastbody := sc.lastbody
	sc.lastbody = nil
	sc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			sc.lk.Lock()
			defer sc.lk.Unlock()
			sc.re = err
			return nil, err
		}
	}

	req, err = ReadRequest(r)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			// A close from the opposing client is treated as a
			// graceful close, even if there was some unparse-able
			// data before the close.
			sc.re = ErrPersistEOF
			return nil, sc.re
		} else {
			sc.re = err
			return req, err
		}
	}
	sc.lastbody = req.Body
	sc.nread++
	if req.Close {
		sc.re = ErrPersistEOF
		return req, sc.re
	}
	return req, err
}

// Pending returns the number of unanswered requests
// that have been received on the connection.
func (sc *ServerConn) Pending() int {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	return sc.nread - sc.nwritten
}

// Write writes resp in response to req. To close the connection gracefully, set the
// Response.Close field to true. Write should be considered operational until
// it returns an error, regardless of any errors returned on the Read side.
func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {

	// Retrieve the pipeline ID of this request/response pair
	sc.lk.Lock()
	id, ok := sc.pipereq[req]
	sc.pipereq[req] = 0, false
	if !ok {
		sc.lk.Unlock()
		return ErrPipeline
	}
	sc.lk.Unlock()

	// Ensure pipeline order
	sc.pipe.StartResponse(id)
	defer sc.pipe.EndResponse(id)

	sc.lk.Lock()
	if sc.we != nil {
		defer sc.lk.Unlock()
		return sc.we
	}
	if sc.c == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return os.EBADF
	}
	c := sc.c
	if sc.nread <= sc.nwritten {
		defer sc.lk.Unlock()
		return os.NewError("persist server pipe count")
	}
	if resp.Close {
		// After signaling a keep-alive close, any pipelined unread
		// requests will be lost. It is up to the user to drain them
		// before signaling.
		sc.re = ErrPersistEOF
	}
	sc.lk.Unlock()

	err := resp.Write(c)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		sc.we = err
		return err
	}
	sc.nwritten++

	return nil
}

// A ClientConn sends request and receives headers over an underlying
// connection, while respecting the HTTP keepalive logic. ClientConn is not
// responsible for closing the underlying connection. One must call Close to
// regain control of that connection and deal with it as desired.
type ClientConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe     textproto.Pipeline
	writeReq func(*Request, io.Writer) os.Error
}

// NewClientConn returns a new ClientConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ClientConn{
		c:        c,
		r:        r,
		pipereq:  make(map[*Request]uint),
		writeReq: (*Request).Write,
	}
}

// NewProxyClientConn works like NewClientConn but writes Requests
// using Request's WriteProxy method.
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	cc := NewClientConn(c, r)
	cc.writeReq = (*Request).WriteProxy
	return cc
}

// Close detaches the ClientConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before the user or Read have signaled the end of the keep-alive
// logic. The user should not call Close while Read or Write is in progress.
func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	c = cc.c
	r = cc.r
	cc.c = nil
	cc.r = nil
	return
}

// Write writes a request. An ErrPersistEOF error is returned if the connection
// has been closed in an HTTP keepalive sense. If req.Close equals true, the
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
func (cc *ClientConn) Write(req *Request) (err os.Error) {

	// Ensure ordered execution of Writes
	id := cc.pipe.Next()
	cc.pipe.StartRequest(id)
	defer func() {
		cc.pipe.EndRequest(id)
		if err != nil {
			cc.pipe.StartResponse(id)
			cc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			cc.lk.Lock()
			cc.pipereq[req] = id
			cc.lk.Unlock()
		}
	}()

	cc.lk.Lock()
	if cc.re != nil { // no point sending if read-side closed or broken
		defer cc.lk.Unlock()
		return cc.re
	}
	if cc.we != nil {
		defer cc.lk.Unlock()
		return cc.we
	}
	if cc.c == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return os.EBADF
	}
	c := cc.c
	if req.Close {
		// We write the EOF to the write-side error, because there
		// still might be some pipelined reads
		cc.we = ErrPersistEOF
	}
	cc.lk.Unlock()

	err = cc.writeReq(req, c)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.we = err
		return err
	}
	cc.nwritten++

	return nil
}

// Pending returns the number of unanswered requests
// that have been sent on the connection.
func (cc *ClientConn) Pending() int {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	return cc.nwritten - cc.nread
}

// Read reads the next response from the wire. A valid response might be
// returned together with an ErrPersistEOF, which means that the remote
// requested that this be the last request serviced. Read can be called
// concurrently with Write, but not with another Read.
func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {

	// Retrieve the pipeline ID of this request/response pair
	cc.lk.Lock()
	id, ok := cc.pipereq[req]
	cc.pipereq[req] = 0, false
	if !ok {
		cc.lk.Unlock()
		return nil, ErrPipeline
	}
	cc.lk.Unlock()

	// Ensure pipeline order
	cc.pipe.StartResponse(id)
	defer cc.pipe.EndResponse(id)

	cc.lk.Lock()
	if cc.re != nil {
		defer cc.lk.Unlock()
		return nil, cc.re
	}
	if cc.r == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return nil, os.EBADF
	}
	r := cc.r
	lastbody := cc.lastbody
	cc.lastbody = nil
	cc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			cc.lk.Lock()
			defer cc.lk.Unlock()
			cc.re = err
			return nil, err
		}
	}

	resp, err = ReadResponse(r, req.Method)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.re = err
		return resp, err
	}
	cc.lastbody = resp.Body

	cc.nread++

	if resp.Close {
		cc.re = ErrPersistEOF // don't send any more requests
		return resp, cc.re
	}
	return resp, err
}

// Do is convenience method that writes a request and reads a response.
func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
	err = cc.Write(req)
	if err != nil {
		return
	}
	return cc.Read(req)
}
<|endoftext|>