<commit_before>// Package mysql_defaults_file provides a way of accessing MySQL via a defaults-file.
package mysql_defaults_file

import (
	"database/sql"
	go_ini "github.com/vaughan0/go-ini" // not sure what to do with dashes in names
	"log"
	"os"
	"strings"
)

// There must be a better way of doing this. Fix me...
// Return the environment value of a given name.
func getEnviron(name string) string {
	for i := range os.Environ() {
		s := os.Environ()[i]
		kV := strings.Split(s, "=")

		if kV[0] == name {
			return kV[1]
		}
	}
	return ""
}

// convert ~ to $HOME
func convertFilename(filename string) string {
	for i := range filename {
		if filename[i] == '~' {
			//			fmt.Println("Filename before", filename )
			filename = filename[:i] + getEnviron("HOME") + filename[i+1:]
			//			fmt.Println("Filename after", filename )
			break
		}
	}

	return filename
}

// Read the given defaults file and return the different parameter values as a map.
func defaultsFileComponents(defaultsFile string) map[string]string {
	defaultsFile = convertFilename(defaultsFile)

	components := make(map[string]string)

	i, err := go_ini.LoadFile(defaultsFile)
	if err != nil {
		log.Fatal("Could not load ini file", err)
	}
	section := i.Section("client")

	user, ok := section["user"]
	if ok {
		components["user"] = user
	}
	password, ok := section["password"]
	if ok {
		components["password"] = password
	}
	socket, ok := section["socket"]
	if ok {
		components["socket"] = socket
	}
	host, ok := section["host"]
	if ok {
		components["host"] = host
	}
	port, ok := section["port"]
	if ok {
		components["port"] = port
	}
	database, ok := section["database"]
	if ok {
		components["database"] = database
	}

	return components
}

// BuildDSN builds the dsn we're going to use to connect with based on a
// parameter / value string map and return the dsn as a string.
func BuildDSN(components map[string]string, database string) string {
	dsn := ""

	// USER
	_, ok := components["user"]
	if ok {
		dsn = components["user"]
	} else {
		dsn = getEnviron("USER")
	}
	// PASSWORD
	_, ok = components["password"]
	if ok {
		dsn += ":" + components["password"]
	}

	// SOCKET or HOST? SOCKET TAKES PRECEDENCE if both defined.
	_, okSocket := components["socket"]
	_, okHost := components["host"]
	if okSocket || okHost {
		if okSocket {
			dsn += "@unix(" + components["socket"] + ")/"
		} else {
			hostPort := components["host"]
			_, ok := components["port"]
			if ok {
				hostPort += ":" + components["port"] // stored as string so no need to convert
			} else {
				hostPort += ":3306" // we always need _some_ port so if we don't provide one assume MySQL's default port
			}

			dsn += "@tcp(" + hostPort + ")/"
		}
	} else {
		dsn += "@/" // but I'm guessing here.
	}

	if len(database) > 0 {
		dsn += database
	} else {
		_, ok := components["database"]
		if ok {
			dsn += components["database"]
		}
	}

	//	fmt.Println("final dsn from defaults file:", dsn )
	return dsn
}

// OpenUsingDefaultsFile opens a connection only using a defaults file
func OpenUsingDefaultsFile(sqlDriver string, defaultsFile string, database string) (*sql.DB, error) {
	if defaultsFile == "" {
		defaultsFile = "~/.my.cnf"
	}

	newDSN := BuildDSN(defaultsFileComponents(defaultsFile), database)

	return sql.Open(sqlDriver, newDSN)
}
<commit_msg>mysql_defaults_file: simplify by using os.Getenv()<commit_after>// Package mysql_defaults_file provides a way of accessing MySQL via a defaults-file.
package mysql_defaults_file

import (
	"database/sql"
	go_ini "github.com/vaughan0/go-ini" // not sure what to do with dashes in names
	"log"
	"os"
)

// convert ~ to $HOME
func convertFilename(filename string) string {
	for i := range filename {
		if filename[i] == '~' {
			filename = filename[:i] + os.Getenv("HOME") + filename[i+1:]
			break
		}
	}

	return filename
}

// Read the given defaults file and return the different parameter values as a map.
func defaultsFileComponents(defaultsFile string) map[string]string {
	defaultsFile = convertFilename(defaultsFile)

	components := make(map[string]string)

	i, err := go_ini.LoadFile(defaultsFile)
	if err != nil {
		log.Fatal("Could not load ini file", err)
	}
	section := i.Section("client")

	user, ok := section["user"]
	if ok {
		components["user"] = user
	}
	password, ok := section["password"]
	if ok {
		components["password"] = password
	}
	socket, ok := section["socket"]
	if ok {
		components["socket"] = socket
	}
	host, ok := section["host"]
	if ok {
		components["host"] = host
	}
	port, ok := section["port"]
	if ok {
		components["port"] = port
	}
	database, ok := section["database"]
	if ok {
		components["database"] = database
	}

	return components
}

// BuildDSN builds the dsn we're going to use to connect with based on a
// parameter / value string map and return the dsn as a string.
func BuildDSN(components map[string]string, database string) string {
	dsn := ""

	// USER
	_, ok := components["user"]
	if ok {
		dsn = components["user"]
	} else {
		dsn = os.Getenv("USER")
	}
	// PASSWORD
	_, ok = components["password"]
	if ok {
		dsn += ":" + components["password"]
	}

	// SOCKET or HOST? SOCKET TAKES PRECEDENCE if both defined.
	_, okSocket := components["socket"]
	_, okHost := components["host"]
	if okSocket || okHost {
		if okSocket {
			dsn += "@unix(" + components["socket"] + ")/"
		} else {
			hostPort := components["host"]
			_, ok := components["port"]
			if ok {
				hostPort += ":" + components["port"] // stored as string so no need to convert
			} else {
				hostPort += ":3306" // we always need _some_ port so if we don't provide one assume MySQL's default port
			}

			dsn += "@tcp(" + hostPort + ")/"
		}
	} else {
		dsn += "@/" // but I'm guessing here.
	}

	if len(database) > 0 {
		dsn += database
	} else {
		_, ok := components["database"]
		if ok {
			dsn += components["database"]
		}
	}

	//	fmt.Println("final dsn from defaults file:", dsn )
	return dsn
}

// OpenUsingDefaultsFile opens a connection only using a defaults file
func OpenUsingDefaultsFile(sqlDriver string, defaultsFile string, database string) (*sql.DB, error) {
	if defaultsFile == "" {
		defaultsFile = "~/.my.cnf"
	}

	newDSN := BuildDSN(defaultsFileComponents(defaultsFile), database)

	return sql.Open(sqlDriver, newDSN)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const VERSION = "v1.1.0"

var logger = log.New(os.Stderr, "", 0)

type OriginConfig struct {
	Addr   string
	Direct bool
}

func main() {
	port := flag.String("p", "443", "")
	ip := flag.String("i", "127.0.0.1", "")
	direct := flag.Bool("d", false, "")
	originPort := flag.String("P", "", "")
	originHost := flag.String("H", "", "")
	originDirect := flag.Bool("D", false, "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	outputLogFormat := flag.String("o", "default", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port (Default: 443)")
		fmt.Println("  -i:        IP Address (Default: 127.0.0.1)")
		fmt.Println("  -d:        Use HTTP/2 direct mode")
		fmt.Println("  -P:        Origin port")
		fmt.Println("  -H:        Origin host")
		fmt.Println("  -D:        Use HTTP/2 direct mode to connect origin")
		fmt.Println("  -c:        Certificate file")
		fmt.Println("  -k:        Certificate key file")
		fmt.Println("  -o:        Output log format (default or json, Default: default)")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		logger.Printf("h2a %s\n", VERSION)
		os.Exit(0)
	}

	addr := net.JoinHostPort(*ip, *port)

	if *originPort == "" {
		logger.Fatalln("Origin port is not specified")
	}
	if *originHost == "" {
		logger.Fatalln("Origin host is not specified")
	}
	originConfig := OriginConfig{
		Addr:   net.JoinHostPort(*originHost, *originPort),
		Direct: *originDirect,
	}

	var formatter Formatter
	if *outputLogFormat == "json" {
		formatter = JSONFormatter
	} else {
		formatter = DefaultFormatter
	}

	var server net.Listener
	var err error
	if *direct {
		server, err = net.Listen("tcp", addr)
	} else {
		cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
		if err != nil {
			logger.Fatalln("Invalid certificate file")
		}

		config := &tls.Config{}
		config.Certificates = []tls.Certificate{cert}
		config.NextProtos = append(config.NextProtos, "h2", "h2-16", "h2-15", "h2-14", "http/1.1")

		server, err = tls.Listen("tcp", addr, config)
	}

	if err != nil {
		logger.Fatalf("Could not bind address - %s\n", addr)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			logger.Printf("Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, originConfig, formatter)
	}
}

func handlePeer(remoteConn net.Conn, originConfig OriginConfig, formatter Formatter) {
	var originConn net.Conn
	var err error
	h2 := true
	_, useTls := remoteConn.(*tls.Conn)

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr(), formatter)
	defer dumper.Close()

	remoteCh, remoteErrCh := handleConnection(remoteConn)
	dumpDataCh, dumpDoneCh := handleFrameDumper(dumper)
	defer func() {
		dumpDoneCh <- true
	}()

	select {
	case chunk := <-remoteCh:
		var connState tls.ConnectionState

		if useTls {
			connState = remoteConn.(*tls.Conn).ConnectionState()

			if connState.NegotiatedProtocol == "" {
				connState.NegotiatedProtocol = "http/1.1"
			}
			if connState.NegotiatedProtocol == "http/1.1" {
				h2 = true
			}

			dumper.DumpConnectionState(connState)
		}

		if originConfig.Direct {
			originConn, err = net.Dial("tcp", originConfig.Addr)
		} else {
			config := &tls.Config{}
			if useTls {
				config.CipherSuites = []uint16{connState.CipherSuite}
				config.ServerName = connState.ServerName
			}
			config.InsecureSkipVerify = true
			config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)

			originConn, err = tls.Dial("tcp", originConfig.Addr, config)
		}
		if err != nil {
			logger.Printf("Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.Printf("Unable to write data to the origin: %s", err)
			return
		}

		if h2 {
			dumpDataCh <- &DumpData{chunk, true}
		}

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.Printf("Connection error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the origin: %s", err)
				return
			}

			if h2 {
				dumpDataCh <- &DumpData{chunk, true}
			}

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.Printf("Connection error: %s", err)
			}

			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the connection: %s", err)
				return
			}

			if h2 {
				dumpDataCh <- &DumpData{chunk, false}
			}

		case err := <-originErrCh:
			if err != io.EOF {
				logger.Printf("Origin error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 262144)

			n, err := conn.Read(buf)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}

func handleFrameDumper(dumper *FrameDumper) (chan *DumpData, chan bool) {
	dataCh := make(chan *DumpData, 1024)
	doneCh := make(chan bool, 1)

	go func() {
		for {
			select {
			case d := <-dataCh:
				dumper.DumpFrame(d.Chunk, d.Remote)
			case <-doneCh:
				break
			}
		}
	}()

	return dataCh, doneCh
}

type DumpData struct {
	Chunk  []byte
	Remote bool
}
<commit_msg>Bump version<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const VERSION = "v1.2.0"

var logger = log.New(os.Stderr, "", 0)

type OriginConfig struct {
	Addr   string
	Direct bool
}

func main() {
	port := flag.String("p", "443", "")
	ip := flag.String("i", "127.0.0.1", "")
	direct := flag.Bool("d", false, "")
	originPort := flag.String("P", "", "")
	originHost := flag.String("H", "", "")
	originDirect := flag.Bool("D", false, "")
	certPath := flag.String("c", "", "")
	keyPath := flag.String("k", "", "")
	outputLogFormat := flag.String("o", "default", "")
	version := flag.Bool("version", false, "")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS]\n\n", os.Args[0])
		fmt.Println("Options:")
		fmt.Println("  -p:        Port (Default: 443)")
		fmt.Println("  -i:        IP Address (Default: 127.0.0.1)")
		fmt.Println("  -d:        Use HTTP/2 direct mode")
		fmt.Println("  -P:        Origin port")
		fmt.Println("  -H:        Origin host")
		fmt.Println("  -D:        Use HTTP/2 direct mode to connect origin")
		fmt.Println("  -c:        Certificate file")
		fmt.Println("  -k:        Certificate key file")
		fmt.Println("  -o:        Output log format (default or json, Default: default)")
		fmt.Println("  --version: Display version information and exit.")
		fmt.Println("  --help:    Display this help and exit.")
		os.Exit(1)
	}

	flag.Parse()

	if *version {
		logger.Printf("h2a %s\n", VERSION)
		os.Exit(0)
	}

	addr := net.JoinHostPort(*ip, *port)

	if *originPort == "" {
		logger.Fatalln("Origin port is not specified")
	}
	if *originHost == "" {
		logger.Fatalln("Origin host is not specified")
	}
	originConfig := OriginConfig{
		Addr:   net.JoinHostPort(*originHost, *originPort),
		Direct: *originDirect,
	}

	var formatter Formatter
	if *outputLogFormat == "json" {
		formatter = JSONFormatter
	} else {
		formatter = DefaultFormatter
	}

	var server net.Listener
	var err error
	if *direct {
		server, err = net.Listen("tcp", addr)
	} else {
		cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
		if err != nil {
			logger.Fatalln("Invalid certificate file")
		}

		config := &tls.Config{}
		config.Certificates = []tls.Certificate{cert}
		config.NextProtos = append(config.NextProtos, "h2", "h2-16", "h2-15", "h2-14", "http/1.1")

		server, err = tls.Listen("tcp", addr, config)
	}

	if err != nil {
		logger.Fatalf("Could not bind address - %s\n", addr)
	}

	defer server.Close()

	for {
		remoteConn, err := server.Accept()
		if err != nil {
			logger.Printf("Unable to accept: %s", err)
			continue
		}

		go handlePeer(remoteConn, originConfig, formatter)
	}
}

func handlePeer(remoteConn net.Conn, originConfig OriginConfig, formatter Formatter) {
	var originConn net.Conn
	var err error
	h2 := true
	_, useTls := remoteConn.(*tls.Conn)

	defer remoteConn.Close()

	dumper := NewFrameDumper(remoteConn.RemoteAddr(), formatter)
	defer dumper.Close()

	remoteCh, remoteErrCh := handleConnection(remoteConn)
	dumpDataCh, dumpDoneCh := handleFrameDumper(dumper)
	defer func() {
		dumpDoneCh <- true
	}()

	select {
	case chunk := <-remoteCh:
		var connState tls.ConnectionState

		if useTls {
			connState = remoteConn.(*tls.Conn).ConnectionState()

			if connState.NegotiatedProtocol == "" {
				connState.NegotiatedProtocol = "http/1.1"
			}
			if connState.NegotiatedProtocol == "http/1.1" {
				h2 = true
			}

			dumper.DumpConnectionState(connState)
		}

		if originConfig.Direct {
			originConn, err = net.Dial("tcp", originConfig.Addr)
		} else {
			config := &tls.Config{}
			if useTls {
				config.CipherSuites = []uint16{connState.CipherSuite}
				config.ServerName = connState.ServerName
			}
			config.InsecureSkipVerify = true
			config.NextProtos = append(config.NextProtos, connState.NegotiatedProtocol)

			originConn, err = tls.Dial("tcp", originConfig.Addr, config)
		}
		if err != nil {
			logger.Printf("Unable to connect to the origin: %s", err)
			return
		}

		defer originConn.Close()

		_, err = originConn.Write(chunk)
		if err != nil {
			logger.Printf("Unable to write data to the origin: %s", err)
			return
		}

		if h2 {
			dumpDataCh <- &DumpData{chunk, true}
		}

	case err := <-remoteErrCh:
		if err != io.EOF {
			logger.Printf("Connection error: %s", err)
		}
		return
	}

	originCh, originErrCh := handleConnection(originConn)

	for {
		select {
		case chunk := <-remoteCh:
			_, err := originConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the origin: %s", err)
				return
			}

			if h2 {
				dumpDataCh <- &DumpData{chunk, true}
			}

		case err := <-remoteErrCh:
			if err != io.EOF {
				logger.Printf("Connection error: %s", err)
			}

			return

		case chunk := <-originCh:
			_, err := remoteConn.Write(chunk)
			if err != nil {
				logger.Printf("Unable to write data to the connection: %s", err)
				return
			}

			if h2 {
				dumpDataCh <- &DumpData{chunk, false}
			}

		case err := <-originErrCh:
			if err != io.EOF {
				logger.Printf("Origin error: %s", err)
			}
			return
		}
	}
}

func handleConnection(conn net.Conn) (<-chan []byte, <-chan error) {
	dataCh := make(chan []byte)
	errCh := make(chan error, 1)

	go func() {
		for {
			buf := make([]byte, 262144)

			n, err := conn.Read(buf)
			if err != nil {
				errCh <- err
				break
			}

			dataCh <- buf[:n]
		}
	}()

	return dataCh, errCh
}

func handleFrameDumper(dumper *FrameDumper) (chan *DumpData, chan bool) {
	dataCh := make(chan *DumpData, 1024)
	doneCh := make(chan bool, 1)

	go func() {
		for {
			select {
			case d := <-dataCh:
				dumper.DumpFrame(d.Chunk, d.Remote)
			case <-doneCh:
				break
			}
		}
	}()

	return dataCh, doneCh
}

type DumpData struct {
	Chunk  []byte
	Remote bool
}
<|endoftext|>


<commit_before>package hdf5

// #include "hdf5.h"
// #include <stdlib.h>
// #include <string.h>
import "C"

import (
	"fmt"

	"reflect"
	"runtime"
	"unsafe"
)

type Dataset struct {
	Location
}

func newDataset(id C.hid_t) *Dataset {
	d := &Dataset{Location{Identifier{id}}}
	runtime.SetFinalizer(d, (*Dataset).finalizer)
	return d
}

func createDataset(id C.hid_t, name string, dtype *Datatype, dspace *Dataspace, dcpl *PropList) (*Dataset, error) {
	dtype, err := dtype.Copy() // For safety
	if err != nil {
		return nil, err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	hid := C.H5Dcreate2(id, c_name, dtype.id, dspace.id, P_DEFAULT.id, dcpl.id, P_DEFAULT.id)
	if err := checkID(hid); err != nil {
		return nil, err
	}
	return newDataset(hid), nil
}

func (s *Dataset) finalizer() {
	if err := s.Close(); err != nil {
		panic(fmt.Errorf("error closing dset: %s", err))
	}
}

// Close releases and terminates access to a dataset.
func (s *Dataset) Close() error {
	if s.id == 0 {
		return nil
	}
	err := h5err(C.H5Dclose(s.id))
	s.id = 0
	return err
}

// Space returns an identifier for a copy of the dataspace for a dataset.
func (s *Dataset) Space() *Dataspace {
	hid := C.H5Dget_space(s.id)
	if int(hid) > 0 {
		return newDataspace(hid)
	}
	return nil
}

// ReadSubset reads a subset of raw data from a dataset into a buffer.
func (s *Dataset) ReadSubset(data interface{}, memspace, filespace *Dataspace) error {
	dtype, err := s.Datatype()
	if err != nil {
		return err
	}

	var addr unsafe.Pointer
	v := reflect.Indirect(reflect.ValueOf(data))

	switch v.Kind() {

	case reflect.Array:
		addr = unsafe.Pointer(v.UnsafeAddr())

	case reflect.Slice:
		slice := (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(slice.Data)

	case reflect.String:
		str := (*reflect.StringHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(str.Data)

	case reflect.Ptr:
		addr = unsafe.Pointer(v.Pointer())

	default:
		addr = unsafe.Pointer(v.UnsafeAddr())
	}

	var filespace_id, memspace_id C.hid_t = 0, 0
	if memspace != nil {
		memspace_id = memspace.id
	}
	if filespace != nil {
		filespace_id = filespace.id
	}
	rc := C.H5Dread(s.id, dtype.id, memspace_id, filespace_id, 0, addr)
	err = h5err(rc)
	return err
}

// Read reads raw data from a dataset into a buffer.
func (s *Dataset) Read(data interface{}) error {
	return s.ReadSubset(data, nil, nil)
}

// WriteSubset writes a subset of raw data from a buffer to a dataset.
func (s *Dataset) WriteSubset(data interface{}, memspace, filespace *Dataspace) error {
	dtype, err := s.Datatype()
	if err != nil {
		return err
	}

	addr := unsafe.Pointer(nil)
	v := reflect.Indirect(reflect.ValueOf(data))

	switch v.Kind() {

	case reflect.Array:
		addr = unsafe.Pointer(v.UnsafeAddr())

	case reflect.Slice:
		slice := (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(slice.Data)

	case reflect.String:
		str := (*reflect.StringHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(str.Data)

	case reflect.Ptr:
		addr = unsafe.Pointer(v.Pointer())

	default:
		addr = unsafe.Pointer(v.UnsafeAddr())
	}

	var filespace_id, memspace_id C.hid_t = 0, 0
	if memspace != nil {
		memspace_id = memspace.id
	}
	if filespace != nil {
		filespace_id = filespace.id
	}
	rc := C.H5Dwrite(s.id, dtype.id, memspace_id, filespace_id, 0, addr)
	err = h5err(rc)
	return err
}

// Write writes raw data from a buffer to a dataset.
func (s *Dataset) Write(data interface{}) error {
	return s.WriteSubset(data, nil, nil)
}

// Creates a new attribute at this location.
func (s *Dataset) CreateAttribute(name string, dtype *Datatype, dspace *Dataspace) (*Attribute, error) {
	return createAttribute(s.id, name, dtype, dspace, P_DEFAULT)
}

// Creates a new attribute at this location.
func (s *Dataset) CreateAttributeWith(name string, dtype *Datatype, dspace *Dataspace, acpl *PropList) (*Attribute, error) {
	return createAttribute(s.id, name, dtype, dspace, acpl)
}

// Opens an existing attribute.
func (s *Dataset) OpenAttribute(name string) (*Attribute, error) {
	return openAttribute(s.id, name)
}

// Datatype returns the HDF5 Datatype of the Dataset
func (s *Dataset) Datatype() (*Datatype, error) {
	dtype_id := C.H5Dget_type(s.id)
	if dtype_id < 0 {
		return nil, fmt.Errorf("couldn't open Datatype from Dataset %q", s.Name())
	}
	return NewDatatype(dtype_id), nil
}
<commit_msg>Close datatypes explicitely<commit_after>package hdf5

// #include "hdf5.h"
// #include <stdlib.h>
// #include <string.h>
import "C"

import (
	"fmt"

	"reflect"
	"runtime"
	"unsafe"
)

type Dataset struct {
	Location
}

func newDataset(id C.hid_t) *Dataset {
	d := &Dataset{Location{Identifier{id}}}
	runtime.SetFinalizer(d, (*Dataset).finalizer)
	return d
}

func createDataset(id C.hid_t, name string, dtype *Datatype, dspace *Dataspace, dcpl *PropList) (*Dataset, error) {
	dtype, err := dtype.Copy() // For safety
	if err != nil {
		return nil, err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	hid := C.H5Dcreate2(id, c_name, dtype.id, dspace.id, P_DEFAULT.id, dcpl.id, P_DEFAULT.id)
	if err := checkID(hid); err != nil {
		return nil, err
	}
	return newDataset(hid), nil
}

func (s *Dataset) finalizer() {
	if err := s.Close(); err != nil {
		panic(fmt.Errorf("error closing dset: %s", err))
	}
}

// Close releases and terminates access to a dataset.
func (s *Dataset) Close() error {
	if s.id == 0 {
		return nil
	}
	err := h5err(C.H5Dclose(s.id))
	s.id = 0
	return err
}

// Space returns an identifier for a copy of the dataspace for a dataset.
func (s *Dataset) Space() *Dataspace {
	hid := C.H5Dget_space(s.id)
	if int(hid) > 0 {
		return newDataspace(hid)
	}
	return nil
}

// ReadSubset reads a subset of raw data from a dataset into a buffer.
func (s *Dataset) ReadSubset(data interface{}, memspace, filespace *Dataspace) error {
	dtype, err := s.Datatype()
	defer dtype.Close()
	if err != nil {
		return err
	}

	var addr unsafe.Pointer
	v := reflect.Indirect(reflect.ValueOf(data))

	switch v.Kind() {

	case reflect.Array:
		addr = unsafe.Pointer(v.UnsafeAddr())

	case reflect.Slice:
		slice := (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(slice.Data)

	case reflect.String:
		str := (*reflect.StringHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(str.Data)

	case reflect.Ptr:
		addr = unsafe.Pointer(v.Pointer())

	default:
		addr = unsafe.Pointer(v.UnsafeAddr())
	}

	var filespace_id, memspace_id C.hid_t = 0, 0
	if memspace != nil {
		memspace_id = memspace.id
	}
	if filespace != nil {
		filespace_id = filespace.id
	}
	rc := C.H5Dread(s.id, dtype.id, memspace_id, filespace_id, 0, addr)
	err = h5err(rc)
	return err
}

// Read reads raw data from a dataset into a buffer.
func (s *Dataset) Read(data interface{}) error {
	return s.ReadSubset(data, nil, nil)
}

// WriteSubset writes a subset of raw data from a buffer to a dataset.
func (s *Dataset) WriteSubset(data interface{}, memspace, filespace *Dataspace) error {
	dtype, err := s.Datatype()
	defer dtype.Close()
	if err != nil {
		return err
	}

	addr := unsafe.Pointer(nil)
	v := reflect.Indirect(reflect.ValueOf(data))

	switch v.Kind() {

	case reflect.Array:
		addr = unsafe.Pointer(v.UnsafeAddr())

	case reflect.Slice:
		slice := (*reflect.SliceHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(slice.Data)

	case reflect.String:
		str := (*reflect.StringHeader)(unsafe.Pointer(v.UnsafeAddr()))
		addr = unsafe.Pointer(str.Data)

	case reflect.Ptr:
		addr = unsafe.Pointer(v.Pointer())

	default:
		addr = unsafe.Pointer(v.UnsafeAddr())
	}

	var filespace_id, memspace_id C.hid_t = 0, 0
	if memspace != nil {
		memspace_id = memspace.id
	}
	if filespace != nil {
		filespace_id = filespace.id
	}
	rc := C.H5Dwrite(s.id, dtype.id, memspace_id, filespace_id, 0, addr)
	err = h5err(rc)
	return err
}

// Write writes raw data from a buffer to a dataset.
func (s *Dataset) Write(data interface{}) error {
	return s.WriteSubset(data, nil, nil)
}

// Creates a new attribute at this location.
func (s *Dataset) CreateAttribute(name string, dtype *Datatype, dspace *Dataspace) (*Attribute, error) {
	return createAttribute(s.id, name, dtype, dspace, P_DEFAULT)
}

// Creates a new attribute at this location.
func (s *Dataset) CreateAttributeWith(name string, dtype *Datatype, dspace *Dataspace, acpl *PropList) (*Attribute, error) {
	return createAttribute(s.id, name, dtype, dspace, acpl)
}

// Opens an existing attribute.
func (s *Dataset) OpenAttribute(name string) (*Attribute, error) {
	return openAttribute(s.id, name)
}

// Datatype returns the HDF5 Datatype of the Dataset
func (s *Dataset) Datatype() (*Datatype, error) {
	dtype_id := C.H5Dget_type(s.id)
	if dtype_id < 0 {
		return nil, fmt.Errorf("couldn't open Datatype from Dataset %q", s.Name())
	}
	return NewDatatype(dtype_id), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"strings"
)

var cmdCreate = &Command{
	UsageLine: "create [appname]",
	Short:     "create an application base on beego framework",
	Long: `
create an application base on beego framework

In the current path, will create a folder named [appname]

In the appname folder has the follow struct:

	|- main.go
	|- conf
	    |-  app.conf
	|- controllers
	     |- default.go
	|- models
	|- static
	     |- js
		 |- css
	     |- img
	|- views
	    index.tpl

`,
}

func init() {
	cmdCreate.Run = createapp
}

func createapp(cmd *Command, args []string) {
	crupath, _ := os.Getwd()
	if len(args) != 1 {
		fmt.Println("error args")
		os.Exit(2)
	}
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		fmt.Println("you should set GOPATH in the env")
		os.Exit(2)
	}
	haspath := false
	if crupath != path.Join(gopath, "src") {
		wgopath := strings.Split(gopath, ";")
		if len(wgopath) >= 1 {
			for _, wg := range wgopath {
				wg = wg + `\src`
				if crupath == wg {
					haspath = true
					break
				}
			}
		}
		if !haspath {
			lgopath := strings.Split(gopath, ":")
			if len(lgopath) >= 1 {
				for _, wg := range lgopath {
					if crupath == path.Join(wg, "src") {
						haspath = true
						break
					}
				}
			}
		}

	} else {
		haspath = true
	}
	if !haspath {
		fmt.Println("can't create application outside of GOPATH")
		fmt.Println("you first should `cd $GOPATH/src` then use create")
		os.Exit(2)
	}
	apppath := path.Join(crupath, args[0])
	os.Mkdir(apppath, 0755)
	fmt.Println("create app folder:", apppath)
	os.Mkdir(path.Join(apppath, "conf"), 0755)
	fmt.Println("create conf:", path.Join(apppath, "conf"))
	os.Mkdir(path.Join(apppath, "controllers"), 0755)
	fmt.Println("create controllers:", path.Join(apppath, "controllers"))
	os.Mkdir(path.Join(apppath, "conf"), 0755)
	fmt.Println("create models:", path.Join(apppath, "models"))
	os.Mkdir(path.Join(apppath, "models"), 0755)
	fmt.Println("create static:", path.Join(apppath, "static"))
	os.Mkdir(path.Join(apppath, "static", "js"), 0755)
	fmt.Println("create static js:", path.Join(apppath, "static", "js"))
	os.Mkdir(path.Join(apppath, "static", "css"), 0755)
	fmt.Println("create static css:", path.Join(apppath, "static", "css"))
	os.Mkdir(path.Join(apppath, "static", "img"), 0755)
	fmt.Println("create static img:", path.Join(apppath, "static", "img"))
	fmt.Println("create views:", path.Join(apppath, "views"))
	os.Mkdir(path.Join(apppath, "views"), 0755)
	fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf"))
	writetofile(path.Join(apppath, "conf", "app.conf"), "appname = "+args[0])

	fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go"))
	writetofile(path.Join(apppath, "controllers", "default.go"), controllers)

	fmt.Println("create views index.tpl:", path.Join(apppath, "views", "index.tpl"))
	writetofile(path.Join(apppath, "views", "index.tpl"), indextpl)

	fmt.Println("create main.go:", path.Join(apppath, "main.go"))
	writetofile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", args[0], -1))
}

var maingo = `package main

import (
	"{{.Appname}}/controllers"
	"github.com/astaxie/beego"
)

func main() {
	beego.RegisterController("/", &controllers.MainController{})
	beego.Run()
}

`
var controllers = `package controllers

import (
	"github.com/astaxie/beego"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	this.Data["Username"] = "astaxie"
	this.Data["Email"] = "astaxie@gmail.com"
	this.TplNames = "index.tpl"
}
`

var indextpl = `<!DOCTYPE html>

    <title>beego welcome template</title>

Hello, world!{{.Username}},{{.Email}}

`

func writetofile(filename, content string) {
	f, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	f.WriteString(content)
}
<commit_msg>#1 fix create conf<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"strings"
)

var cmdCreate = &Command{
	UsageLine: "create [appname]",
	Short:     "create an application base on beego framework",
	Long: `
create an application base on beego framework

In the current path, will create a folder named [appname]

In the appname folder has the follow struct:

	|- main.go
	|- conf
	    |-  app.conf
	|- controllers
	     |- default.go
	|- models
	|- static
	     |- js
		 |- css
	     |- img
	|- views
	    index.tpl

`,
}

func init() {
	cmdCreate.Run = createapp
}

func createapp(cmd *Command, args []string) {
	crupath, _ := os.Getwd()
	if len(args) != 1 {
		fmt.Println("error args")
		os.Exit(2)
	}
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		fmt.Println("you should set GOPATH in the env")
		os.Exit(2)
	}
	haspath := false
	if crupath != path.Join(gopath, "src") {
		wgopath := strings.Split(gopath, ";")
		if len(wgopath) >= 1 {
			for _, wg := range wgopath {
				wg = wg + `\src`
				if crupath == wg {
					haspath = true
					break
				}
			}
		}
		if !haspath {
			lgopath := strings.Split(gopath, ":")
			if len(lgopath) >= 1 {
				for _, wg := range lgopath {
					if crupath == path.Join(wg, "src") {
						haspath = true
						break
					}
				}
			}
		}

	} else {
		haspath = true
	}
	if !haspath {
		fmt.Println("can't create application outside of GOPATH")
		fmt.Println("you first should `cd $GOPATH/src` then use create")
		os.Exit(2)
	}
	apppath := path.Join(crupath, args[0])
	os.Mkdir(apppath, 0755)
	fmt.Println("create app folder:", apppath)
	os.Mkdir(path.Join(apppath, "conf"), 0755)
	fmt.Println("create conf:", path.Join(apppath, "conf"))
	os.Mkdir(path.Join(apppath, "controllers"), 0755)
	fmt.Println("create controllers:", path.Join(apppath, "controllers"))
	os.Mkdir(path.Join(apppath, "models"), 0755)
	fmt.Println("create models:", path.Join(apppath, "models"))
	os.Mkdir(path.Join(apppath, "static"), 0755)
	fmt.Println("create static:", path.Join(apppath, "static"))
	os.Mkdir(path.Join(apppath, "static", "js"), 0755)
	fmt.Println("create static js:", path.Join(apppath, "static", "js"))
	os.Mkdir(path.Join(apppath, "static", "css"), 0755)
	fmt.Println("create static css:", path.Join(apppath, "static", "css"))
	os.Mkdir(path.Join(apppath, "static", "img"), 0755)
	fmt.Println("create static img:", path.Join(apppath, "static", "img"))
	fmt.Println("create views:", path.Join(apppath, "views"))
	os.Mkdir(path.Join(apppath, "views"), 0755)
	fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf"))
	writetofile(path.Join(apppath, "conf", "app.conf"), "appname = "+args[0])

	fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go"))
	writetofile(path.Join(apppath, "controllers", "default.go"), controllers)

	fmt.Println("create views index.tpl:", path.Join(apppath, "views", "index.tpl"))
	writetofile(path.Join(apppath, "views", "index.tpl"), indextpl)

	fmt.Println("create main.go:", path.Join(apppath, "main.go"))
	writetofile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", args[0], -1))
}

var maingo = `package main

import (
	"{{.Appname}}/controllers"
	"github.com/astaxie/beego"
)

func main() {
	beego.RegisterController("/", &controllers.MainController{})
	beego.Run()
}

`
var controllers = `package controllers

import (
	"github.com/astaxie/beego"
)

type MainController struct {
	beego.Controller
}

func (this *MainController) Get() {
	this.Data["Username"] = "astaxie"
	this.Data["Email"] = "astaxie@gmail.com"
	this.TplNames = "index.tpl"
}
`

var indextpl = `<!DOCTYPE html>

    <title>beego welcome template</title>

Hello, world!{{.Username}},{{.Email}}

`

func writetofile(filename, content string) {
	f, err := os.Create(filename)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	f.WriteString(content)
}
<|endoftext|>


<commit_before>// Copyright 2015 Andrew E. Bruno. All rights reserved.
// Use of this source code is governed by a BSD style
// license that can be found in the LICENSE file.

// Package ipa is a Go client library for FreeIPA
package ipa

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/go-ini/ini"
	"gopkg.in/jcmturner/gokrb5.v5/client"
	"gopkg.in/jcmturner/gokrb5.v5/config"
	"gopkg.in/jcmturner/gokrb5.v5/keytab"
)

const (
	IpaClientVersion  = "2.156"
	IpaDatetimeFormat = "20060102150405Z"
)

var (
	ipaDefaultHost    string
	ipaDefaultRealm   string
	ipaCertPool       *x509.CertPool
	ipaSessionPattern = regexp.MustCompile(`^ipa_session=([^;]+);`)
)

// FreeIPA Client
type Client struct {
	host       string
	realm      string
	keyTab     string
	sessionID  string
	sticky     bool
	httpClient *http.Client
	krbClient  *client.Client
}

// FreeIPA Password Policy Error
type ErrPasswordPolicy struct {
}

func (e *ErrPasswordPolicy) Error() string {
	return "ipa: password does not conform to policy"
}

// FreeIPA Invalid Password Error
type ErrInvalidPassword struct {
}

func (e *ErrInvalidPassword) Error() string {
	return "ipa: invalid current password"
}

// FreeIPA error
type IpaError struct {
	Message string
	Code    int
}

// Custom FreeIPA string type
type IpaString string

// Custom FreeIPA datetime type
type IpaDateTime time.Time

// Result returned from a FreeIPA JSON rpc call
type Result struct {
	Summary string          `json:"summary"`
	Value   interface{}     `json:"value"`
	Data    json.RawMessage `json:"result"`
}

// Response returned from a FreeIPA JSON rpc call
type Response struct {
	Error     *IpaError `json:"error"`
	Id        string    `json:"id"`
	Principal string    `json:"principal"`
	Version   string    `json:"version"`
	Result    *Result   `json:"result"`
}

func init() {
	// If ca.crt for ipa exists, use it as the cert pool
	// otherwise default to system root ca.
	pem, err := ioutil.ReadFile("/etc/ipa/ca.crt")
	if err == nil {
		ipaCertPool = x509.NewCertPool()
		if !ipaCertPool.AppendCertsFromPEM(pem) {
			ipaCertPool = nil
		}
	}

	// Load default IPA host
	cfg, err := ini.Load("/etc/ipa/default.conf")
	if err == nil {
		ipaDefaultHost = cfg.Section("global").Key("server").MustString("localhost")
		ipaDefaultRealm = cfg.Section("global").Key("realm").MustString("LOCAL")
	}
}

func newHTTPClient() *http.Client {
	return &http.Client{
		Timeout: 1 * time.Minute,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{RootCAs: ipaCertPool},
		},
	}
}

// New default IPA Client using host and realm from /etc/ipa/default.conf
func NewDefaultClient() *Client {
	return &Client{
		host:       ipaDefaultHost,
		realm:      ipaDefaultRealm,
		sticky:     true,
		httpClient: newHTTPClient(),
	}
}

// New default IPA Client with existing sessionID using host and realm from /etc/ipa/default.conf
func NewDefaultClientWithSession(sessionID string) *Client {
	return &Client{
		host:       ipaDefaultHost,
		realm:      ipaDefaultRealm,
		httpClient: newHTTPClient(),
		sticky:     true,
		sessionID:  sessionID,
	}
}

// New IPA Client with host and realm
func NewClient(host, realm string) *Client {
	return &Client{
		host:       host,
		realm:      realm,
		sticky:     true,
		httpClient: newHTTPClient(),
	}
}

// Unmarshal a FreeIPA datetime. Datetimes in FreeIPA are returned using a
// class-hint system. Values are stored as an array with a single element
// indicating the type and value, for example, '[{"__datetime__": "YYYY-MM-DDTHH:MM:SSZ"]}'
func (dt *IpaDateTime) UnmarshalJSON(b []byte) error {
	var a []map[string]string
	err := json.Unmarshal(b, &a)
	if err != nil {
		return err
	}

	if len(a) == 0 {
		return nil
	}

	if str, ok := a[0]["__datetime__"]; ok {
		t, err := time.Parse(IpaDatetimeFormat, str)
		if err != nil {
			return err
		}
		*dt = IpaDateTime(t)
	}

	return nil
}

func (dt *IpaDateTime) UnmarshalBinary(data []byte) error {
	t := time.Time(*dt)
	err := t.UnmarshalBinary(data)
	if err != nil {
		return err
	}

	*dt = IpaDateTime(t)
	return nil
}

func (dt *IpaDateTime) MarshalBinary() (data []byte, err error) {
	return time.Time(*dt).MarshalBinary()
}

func (dt *IpaDateTime) String() string {
	return time.Time(*dt).String()
}

func (dt *IpaDateTime) Format(layout string) string {
	return time.Time(*dt).Format(layout)
}

// Unmarshal a FreeIPA string from an array of strings. Uses the first value
// in the array as the value of the string.
func (s *IpaString) UnmarshalJSON(b []byte) error {
	var a []string
	err := json.Unmarshal(b, &a)
	if err != nil {
		return err
	}

	if len(a) > 0 {
		*s = IpaString(a[0])
	}

	return nil
}

func (s *IpaString) String() string {
	return string(*s)
}

func (e *IpaError) Error() string {
	return fmt.Sprintf("ipa: error %d - %s", e.Code, e.Message)
}

// Call FreeIPA API with method, params and options
func (c *Client) rpc(method string, params []string, options map[string]interface{}) (*Response, error) {
	if options == nil {
		options = map[string]interface{}{}
	}

	options["version"] = IpaClientVersion

	var data []interface{} = make([]interface{}, 2)
	data[0] = params
	data[1] = options
	payload := map[string]interface{}{
		"method": method,
		"params": data}

	b, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	ipaUrl := fmt.Sprintf("https://%s/ipa/json", c.host)
	if len(c.sessionID) > 0 {
		ipaUrl = fmt.Sprintf("https://%s/ipa/session/json", c.host)
	}

	req, err := http.NewRequest("POST", ipaUrl, bytes.NewBuffer(b))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Referer", fmt.Sprintf("https://%s/ipa", c.host))

	if len(c.sessionID) > 0 {
		// If session is set, use the session id
		req.Header.Set("Cookie", fmt.Sprintf("ipa_session=%s", c.sessionID))
	} else if c.krbClient != nil {
		// use Kerberos auth (SPNEGO)
		c.krbClient.SetSPNEGOHeader(req, "")
	}

	res, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return nil, fmt.Errorf("IPA RPC called failed with HTTP status code: %d", res.StatusCode)
	}

	if err = c.setSessionID(res); err != nil {
		return nil, err
	}

	// XXX use the stream decoder here instead of reading entire body?
	//decoder := json.NewDecoder(res.Body)
	rawJson, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var ipaRes Response
	err = json.Unmarshal(rawJson, &ipaRes)
	if err != nil {
		return nil, err
	}

	if ipaRes.Error != nil {
		return nil, ipaRes.Error
	}

	return &ipaRes, nil
}

// Ping FreeIPA server to check connection
func (c *Client) Ping() (*Response, error) {
	options := map[string]interface{}{}

	res, err := c.rpc("ping", []string{}, options)

	if err != nil {
		return nil, err
	}

	return res, nil
}

// Return current FreeIPA sessionID
func (c *Client) SessionID() string {
	return c.sessionID
}

// Clears out FreeIPA session id
func (c *Client) ClearSession() {
	c.sessionID = ""
}

// Set stick sessions.
func (c *Client) StickySession(enable bool) {
	c.sticky = enable
}

// Set FreeIPA sessionID from http response cookie
func (c *Client) setSessionID(res *http.Response) error {
	if !c.sticky {
		return nil
	}

	cookie := res.Header.Get("Set-Cookie")
	if len(cookie) == 0 {
		return errors.New("empty set-cookie header")
	}

	ipaSession := ""
	matches := ipaSessionPattern.FindStringSubmatch(cookie)
	if len(matches) == 2 {
		ipaSession = matches[1]
	}

	if len(ipaSession) == 32 || strings.HasPrefix(ipaSession, "MagBearerToken") {
		c.sessionID = ipaSession
	} else {
		return errors.New("invalid set-cookie header")
	}

	return nil
}

// Login to FreeIPA using web API with uid/passwd and set the FreeIPA session
// id on the client for subsequent requests.
func (c *Client) RemoteLogin(uid, passwd string) error {
	ipaUrl := fmt.Sprintf("https://%s/ipa/session/login_password", c.host)

	form := url.Values{"user": {uid}, "password": {passwd}}
	req, err := http.NewRequest("POST", ipaUrl, strings.NewReader(form.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Referer", fmt.Sprintf("https://%s/ipa", c.host))

	res, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return fmt.Errorf("IPA login failed with HTTP status code: %d", res.StatusCode)
	}

	if err = c.setSessionID(res); err != nil {
		return err
	}

	return nil
}

// Login to FreeIPA using local kerberos login username and password
func (c *Client) Login(username, password string) error {
	cfg, err := config.Load("/etc/krb5.conf")
	if err != nil {
		return err
	}

	cl := client.NewClientWithPassword(username, c.realm, password)
	cl.WithConfig(cfg)

	err = cl.Login()
	if err != nil {
		return err
	}

	c.krbClient = &cl

	return nil
}

// Login to FreeIPA using local kerberos login with keytab and username
func (c *Client) LoginWithKeytab(ktab, username string) error {
	cfg, err := config.Load("/etc/krb5.conf")
	if err != nil {
		return err
	}

	kt, err := keytab.Load(ktab)
	if err != nil {
		return err
	}

	cl := client.NewClientWithKeytab(username, c.realm, kt)
	cl.WithConfig(cfg)

	err = cl.Login()
	if err != nil {
		return err
	}

	c.krbClient = &cl

	return nil
}
<commit_msg>added custom http client<commit_after>// Copyright 2015 Andrew E. Bruno. All rights reserved.
// Use of this source code is governed by a BSD style
// license that can be found in the LICENSE file.

// Package ipa is a Go client library for FreeIPA
package ipa

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/go-ini/ini"
	"gopkg.in/jcmturner/gokrb5.v5/client"
	"gopkg.in/jcmturner/gokrb5.v5/config"
	"gopkg.in/jcmturner/gokrb5.v5/keytab"
)

const (
	IpaClientVersion  = "2.156"
	IpaDatetimeFormat = "20060102150405Z"
)

var (
	ipaDefaultHost    string
	ipaDefaultRealm   string
	ipaCertPool       *x509.CertPool
	ipaSessionPattern = regexp.MustCompile(`^ipa_session=([^;]+);`)
)

// FreeIPA Client
type Client struct {
	host       string
	realm      string
	keyTab     string
	sessionID  string
	sticky     bool
	httpClient *http.Client
	krbClient  *client.Client
}

// FreeIPA Password Policy Error
type ErrPasswordPolicy struct {
}

func (e *ErrPasswordPolicy) Error() string {
	return "ipa: password does not conform to policy"
}

// FreeIPA Invalid Password Error
type ErrInvalidPassword struct {
}

func (e *ErrInvalidPassword) Error() string {
	return "ipa: invalid current password"
}

// FreeIPA error
type IpaError struct {
	Message string
	Code    int
}

// Custom FreeIPA string type
type IpaString string

// Custom FreeIPA datetime type
type IpaDateTime time.Time

// Result returned from a FreeIPA JSON rpc call
type Result struct {
	Summary string          `json:"summary"`
	Value   interface{}     `json:"value"`
	Data    json.RawMessage `json:"result"`
}

// Response returned from a FreeIPA JSON rpc call
type Response struct {
	Error     *IpaError `json:"error"`
	Id        string    `json:"id"`
	Principal string    `json:"principal"`
	Version   string    `json:"version"`
	Result    *Result   `json:"result"`
}

func init() {
	// If ca.crt for ipa exists, use it as the cert pool
	// otherwise default to system root ca.
	pem, err := ioutil.ReadFile("/etc/ipa/ca.crt")
	if err == nil {
		ipaCertPool = x509.NewCertPool()
		if !ipaCertPool.AppendCertsFromPEM(pem) {
			ipaCertPool = nil
		}
	}

	// Load default IPA host
	cfg, err := ini.Load("/etc/ipa/default.conf")
	if err == nil {
		ipaDefaultHost = cfg.Section("global").Key("server").MustString("localhost")
		ipaDefaultRealm = cfg.Section("global").Key("realm").MustString("LOCAL")
	}
}

func newHTTPClient() *http.Client {
	return &http.Client{
		Timeout: 1 * time.Minute,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{RootCAs: ipaCertPool},
		},
	}
}

// New default IPA Client using host and realm from /etc/ipa/default.conf
func NewDefaultClient() *Client {
	return &Client{
		host:       ipaDefaultHost,
		realm:      ipaDefaultRealm,
		sticky:     true,
		httpClient: newHTTPClient(),
	}
}

// New default IPA Client with existing sessionID using host and realm from /etc/ipa/default.conf
func NewDefaultClientWithSession(sessionID string) *Client {
	return &Client{
		host:       ipaDefaultHost,
		realm:      ipaDefaultRealm,
		httpClient: newHTTPClient(),
		sticky:     true,
		sessionID:  sessionID,
	}
}

// New IPA Client with host and realm
func NewClient(host, realm string) *Client {
	return &Client{
		host:       host,
		realm:      realm,
		sticky:     true,
		httpClient: newHTTPClient(),
	}
}

// New IPA Client with host, realm and custom http client
func NewClientCustomHttp(host, realm string, httpClient *http.Client) *Client {
	return &Client{
		host:       host,
		realm:      realm,
		sticky:     true,
		httpClient: httpClient,
	}
}

// Unmarshal a FreeIPA datetime. Datetimes in FreeIPA are returned using a
// class-hint system. Values are stored as an array with a single element
// indicating the type and value, for example, '[{"__datetime__": "YYYY-MM-DDTHH:MM:SSZ"]}'
func (dt *IpaDateTime) UnmarshalJSON(b []byte) error {
	var a []map[string]string
	err := json.Unmarshal(b, &a)
	if err != nil {
		return err
	}

	if len(a) == 0 {
		return nil
	}

	if str, ok := a[0]["__datetime__"]; ok {
		t, err := time.Parse(IpaDatetimeFormat, str)
		if err != nil {
			return err
		}
		*dt = IpaDateTime(t)
	}

	return nil
}

func (dt *IpaDateTime) UnmarshalBinary(data []byte) error {
	t := time.Time(*dt)
	err := t.UnmarshalBinary(data)
	if err != nil {
		return err
	}

	*dt = IpaDateTime(t)
	return nil
}

func (dt *IpaDateTime) MarshalBinary() (data []byte, err error) {
	return time.Time(*dt).MarshalBinary()
}

func (dt *IpaDateTime) String() string {
	return time.Time(*dt).String()
}

func (dt *IpaDateTime) Format(layout string) string {
	return time.Time(*dt).Format(layout)
}

// Unmarshal a FreeIPA string from an array of strings. Uses the first value
// in the array as the value of the string.
func (s *IpaString) UnmarshalJSON(b []byte) error {
	var a []string
	err := json.Unmarshal(b, &a)
	if err != nil {
		return err
	}

	if len(a) > 0 {
		*s = IpaString(a[0])
	}

	return nil
}

func (s *IpaString) String() string {
	return string(*s)
}

func (e *IpaError) Error() string {
	return fmt.Sprintf("ipa: error %d - %s", e.Code, e.Message)
}

// Call FreeIPA API with method, params and options
func (c *Client) rpc(method string, params []string, options map[string]interface{}) (*Response, error) {
	if options == nil {
		options = map[string]interface{}{}
	}

	options["version"] = IpaClientVersion

	var data []interface{} = make([]interface{}, 2)
	data[0] = params
	data[1] = options
	payload := map[string]interface{}{
		"method": method,
		"params": data}

	b, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	ipaUrl := fmt.Sprintf("https://%s/ipa/json", c.host)
	if len(c.sessionID) > 0 {
		ipaUrl = fmt.Sprintf("https://%s/ipa/session/json", c.host)
	}

	req, err := http.NewRequest("POST", ipaUrl, bytes.NewBuffer(b))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Referer", fmt.Sprintf("https://%s/ipa", c.host))

	if len(c.sessionID) > 0 {
		// If session is set, use the session id
		req.Header.Set("Cookie", fmt.Sprintf("ipa_session=%s", c.sessionID))
	} else if c.krbClient != nil {
		// use Kerberos auth (SPNEGO)
		c.krbClient.SetSPNEGOHeader(req, "")
	}

	res, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return nil, fmt.Errorf("IPA RPC called failed with HTTP status code: %d", res.StatusCode)
	}

	if err = c.setSessionID(res); err != nil {
		return nil, err
	}

	// XXX use the stream decoder here instead of reading entire body?
	//decoder := json.NewDecoder(res.Body)
	rawJson, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var ipaRes Response
	err = json.Unmarshal(rawJson, &ipaRes)
	if err != nil {
		return nil, err
	}

	if ipaRes.Error != nil {
		return nil, ipaRes.Error
	}

	return &ipaRes, nil
}

// Ping FreeIPA server to check connection
func (c *Client) Ping() (*Response, error) {
	options := map[string]interface{}{}

	res, err := c.rpc("ping", []string{}, options)

	if err != nil {
		return nil, err
	}

	return res, nil
}

// Return current FreeIPA sessionID
func (c *Client) SessionID() string {
	return c.sessionID
}

// Clears out FreeIPA session id
func (c *Client) ClearSession() {
	c.sessionID = ""
}

// Set stick sessions.
func (c *Client) StickySession(enable bool) {
	c.sticky = enable
}

// Set FreeIPA sessionID from http response cookie
func (c *Client) setSessionID(res *http.Response) error {
	if !c.sticky {
		return nil
	}

	cookie := res.Header.Get("Set-Cookie")
	if len(cookie) == 0 {
		return errors.New("empty set-cookie header")
	}

	ipaSession := ""
	matches := ipaSessionPattern.FindStringSubmatch(cookie)
	if len(matches) == 2 {
		ipaSession = matches[1]
	}

	if len(ipaSession) == 32 || strings.HasPrefix(ipaSession, "MagBearerToken") {
		c.sessionID = ipaSession
	} else {
		return errors.New("invalid set-cookie header")
	}

	return nil
}

// Login to FreeIPA using web API with uid/passwd and set the FreeIPA session
// id on the client for subsequent requests.
func (c *Client) RemoteLogin(uid, passwd string) error {
	ipaUrl := fmt.Sprintf("https://%s/ipa/session/login_password", c.host)

	form := url.Values{"user": {uid}, "password": {passwd}}
	req, err := http.NewRequest("POST", ipaUrl, strings.NewReader(form.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Referer", fmt.Sprintf("https://%s/ipa", c.host))

	res, err := c.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return fmt.Errorf("IPA login failed with HTTP status code: %d", res.StatusCode)
	}

	if err = c.setSessionID(res); err != nil {
		return err
	}

	return nil
}

// Login to FreeIPA using local kerberos login username and password
func (c *Client) Login(username, password string) error {
	cfg, err := config.Load("/etc/krb5.conf")
	if err != nil {
		return err
	}

	cl := client.NewClientWithPassword(username, c.realm, password)
	cl.WithConfig(cfg)

	err = cl.Login()
	if err != nil {
		return err
	}

	c.krbClient = &cl

	return nil
}

// Login to FreeIPA using local kerberos login with keytab and username
func (c *Client) LoginWithKeytab(ktab, username string) error {
	cfg, err := config.Load("/etc/krb5.conf")
	if err != nil {
		return err
	}

	kt, err := keytab.Load(ktab)
	if err != nil {
		return err
	}

	cl := client.NewClientWithKeytab(username, c.realm, kt)
	cl.WithConfig(cfg)

	err = cl.Login()
	if err != nil {
		return err
	}

	c.krbClient = &cl

	return nil
}
<|endoftext|>


<commit_before>/*
 * Provide IRC functionality
 */

package irc

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"strings"
)

type Conn struct {
	Nick  string
	Name  string
	Ident string
	Host  string
	Port  int
	SSL   bool

	connected  bool
	conn       net.Conn
	rw         *bufio.ReadWriter
	actualNick string
}

// Connect attempts to initialize a connection to a server.
func (c *Conn) Connect() error {
	if c.SSL {
		conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port),
			&tls.Config{
				// Typically IRC servers won't have valid certs.
				InsecureSkipVerify: true,
			})
		if err != nil {
			return err
		}
		c.conn = conn
		c.connected = true
	} else {
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port))
		if err != nil {
			return err
		}
		c.conn = conn
		c.connected = true
	}

	c.rw = bufio.NewReadWriter(bufio.NewReader(c.conn), bufio.NewWriter(c.conn))

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

	return nil
}

// init runs connection initiation (nick, etc)
func (c *Conn) init() error {
	err := c.write(fmt.Sprintf("NICK %s\r\n", c.Nick))
	if err != nil {
		return fmt.Errorf("Failed to send NICK: %s", err.Error())
	}

	err = c.write(fmt.Sprintf("USER %s 0 * :%s\r\n", c.Ident, c.Name))
	if err != nil {
		return fmt.Errorf("Failed to send NICK: %s", err.Error())
	}

	for {
		line, err := c.rw.ReadString('\n')
		if err != nil {
			return err
		}

		log.Printf("Read line [%s]", strings.TrimSpace(line))

		if !strings.HasPrefix(line, ":") {
			continue
		}

		var server string
		var code int
		_, err = fmt.Sscanf(line, ":%s %d ", &server, &code)
		if err == nil {
			if code == 1 {
				return nil
			}
			return fmt.Errorf("No welcome found")
		}
	}
}

// Loop enters a loop. We maintain the IRC connection. Hook events
// will fire.
func (c *Conn) Loop() error {
	for {
		line, err := c.rw.ReadString('\n')
		if err != nil {
			return err
		}

		log.Printf("Read line [%s]", line)

		if strings.HasPrefix(line, "PING ") {
			var server string
			_, err = fmt.Sscanf(line, "PING :%s", &server)
			if err != nil {
				return fmt.Errorf("Unable to parse PING")
			}

			err = c.write(fmt.Sprintf("PONG %s\r\n", server))
			if err != nil {
				return fmt.Errorf("Failed to send PONG: %s", err.Error())
			}
			log.Printf("Sent PONG.")
			continue
		}

		pieces := strings.Split(line, " ")

		if len(pieces) > 1 {
			if pieces[1] == "PRIVMSG" {
				err = c.privmsg(line, pieces)
				if err != nil {
					return err
				}
				continue
			}
		}
	}
}

// Join joins a channel
func (c *Conn) Join(name string) error {
	return c.write(fmt.Sprintf("JOIN %s\r\n", name))
}

// Message sends a message.
func (c *Conn) Message(target string, message string) error {
	return c.write(fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message))
}

// Quit sends a quit.
func (c *Conn) Quit(message string) error {
	return c.write(fmt.Sprintf("QUIT :%s\r\n", message))
}

// privmsg fires when a PRIVMSG is seen.
//
// It triggers any hook functions registered for privmsg.
func (c *Conn) privmsg(line string, pieces []string) error {
	log.Printf("privmsg: todo")
	return nil
}

// write writes a string to the connection
func (c *Conn) write(s string) error {
	sz, err := c.rw.WriteString(s)
	if err != nil {
		return err
	}

	if sz != len(s) {
		return fmt.Errorf("Short write")
	}

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

	log.Printf("Sent: [%s]", s)

	return nil
}
<commit_msg>irc: Commenting and name improvements<commit_after>/*
 * Provide IRC client functionality.
 *
 * I would like to be able to write bots using this package.
 */

package irc

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"strings"
)

// Conn holds an IRC connection.
type Conn struct {
	// Nick is the desired nickname.
	Nick string

	// Name is the realname to use.
	Name string

	// Ident is the ident portion to use.
	Ident string

	// Host is the IP/hostname of the IRC server to connect to.
	Host string

	// Port is the port of the host of the IRC server to connect to.
	Port int

	// TLS toggles whether we connect with TLS/SSL or not.
	TLS bool

	// connected: Whether currently connected or not
	connected bool

	// conn: The connection if we are actively connected.
	conn net.Conn

	// rw: Read/write handle to the connection
	rw *bufio.ReadWriter

	// actualNick: The nick we have if we are currently connected. The requested
	// nick may not always be available.
	actualNick string
}

// Connect attempts to initialize a connection to a server.
func (c *Conn) Connect() error {
	if c.TLS {
		conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port),
			&tls.Config{
				// Typically IRC servers won't have valid certs.
				InsecureSkipVerify: true,
			})
		if err != nil {
			return err
		}
		c.conn = conn
		c.connected = true
	} else {
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.Host, c.Port))
		if err != nil {
			return err
		}
		c.conn = conn
		c.connected = true
	}

	c.rw = bufio.NewReadWriter(bufio.NewReader(c.conn), bufio.NewWriter(c.conn))

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

	return nil
}

// init runs connection initiation (nick, etc)
func (c *Conn) init() error {
	err := c.write(fmt.Sprintf("NICK %s\r\n", c.Nick))
	if err != nil {
		return fmt.Errorf("Failed to send NICK: %s", err.Error())
	}

	err = c.write(fmt.Sprintf("USER %s 0 * :%s\r\n", c.Ident, c.Name))
	if err != nil {
		return fmt.Errorf("Failed to send NICK: %s", err.Error())
	}

	for {
		line, err := c.rw.ReadString('\n')
		if err != nil {
			return err
		}

		log.Printf("Read line [%s]", strings.TrimSpace(line))

		if !strings.HasPrefix(line, ":") {
			continue
		}

		var server string
		var code int
		_, err = fmt.Sscanf(line, ":%s %d ", &server, &code)
		if err == nil {
			if code == 1 {
				return nil
			}
			return fmt.Errorf("No welcome found")
		}
	}
}

// Loop enters a loop reading from the server.
// We maintain the IRC connection.
// Hook events will fire.
func (c *Conn) Loop() error {
	for {
		line, err := c.rw.ReadString('\n')
		if err != nil {
			return err
		}

		log.Printf("Read line [%s]", line)

		// Respond to PING.
		if strings.HasPrefix(line, "PING ") {
			var server string
			_, err = fmt.Sscanf(line, "PING :%s", &server)
			if err != nil {
				return fmt.Errorf("Unable to parse PING")
			}

			err = c.write(fmt.Sprintf("PONG %s\r\n", server))
			if err != nil {
				return fmt.Errorf("Failed to send PONG: %s", err.Error())
			}
			log.Printf("Sent PONG.")
			continue
		}

		pieces := strings.Split(line, " ")

		if len(pieces) > 1 {
			// PRIVMSG: Fire hook
			if pieces[1] == "PRIVMSG" {
				err = c.privmsg(line, pieces)
				if err != nil {
					return err
				}
				continue
			}
		}
	}
}

// Join joins a channel.
func (c *Conn) Join(name string) error {
	return c.write(fmt.Sprintf("JOIN %s\r\n", name))
}

// Message sends a message.
func (c *Conn) Message(target string, message string) error {
	return c.write(fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message))
}

// Quit sends a quit.
func (c *Conn) Quit(message string) error {
	return c.write(fmt.Sprintf("QUIT :%s\r\n", message))
}

// privmsg fires when a PRIVMSG is seen.
//
// It triggers any hook functions registered for privmsg.
func (c *Conn) privmsg(line string, pieces []string) error {
	log.Printf("privmsg: todo")
	return nil
}

// write writes a string to the connection
func (c *Conn) write(s string) error {
	sz, err := c.rw.WriteString(s)
	if err != nil {
		return err
	}

	if sz != len(s) {
		return fmt.Errorf("Short write")
	}

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

	log.Printf("Sent: [%s]", s)

	return nil
}
<|endoftext|>


<commit_before>// dulbecco is a IRC bot.
//
// Plugin support through external commands (bash, python, ...).
//
//   most of the code was copied from:
//   - https://github.com/fluffle/goirc
//   - https://github.com/thoj/go-ircevent
package dulbecco

import (
	"bufio"
	"crypto/tls"
	"errors"
	"github.com/piger/dulbecco/markov"
	"log"
	"net"
	"strings"
	"sync"
	"time"
)

var (
	pingFrequency = 3 * time.Minute
)

// the number of *Loop() methods on Connection; it's used for synchronization
// and must be updated accordingly.
const (
	numLoops = 4

	NickservName = "nickserv"

	// IRC defines a maximum "line" length of 512 characters, including \r\n,
	// the command and all parameters. On Azzurra the limit seems to be lower...
	MaximumCommandLength = 460
)

type Channel struct {
	name, topic string
	names       []string
}

type User struct {
	nickname, username, hostname, realname string

	channels map[string]bool
}

func NewUser(nickname string) *User {
	user := &User{
		nickname: nickname,
		channels: make(map[string]bool),
	}
	return user
}

// A connection to the IRC server, also the main data structure of the IRC bot.
type Connection struct {
	config ServerConfiguration

	// current nickname
	nickname string

	chanmap map[string]*Channel
	usermap map[string]*User

	// enable anti-flood protection
	floodProtection bool
	// anti-flood internal counters
	badness  time.Duration
	lastSent time.Time

	// IO
	sock         net.Conn
	io           *bufio.ReadWriter
	out          chan string
	connected    bool
	tryReconnect bool

	// lock shutdown calls
	mutex sync.Mutex

	// SSL
	useTLS bool

	// Internal channels
	inerr  chan error
	outerr chan bool
	wg     sync.WaitGroup

	// markov database
	mdb *markov.MarkovDB

	// callbacks
	events map[string]map[string]func(*Message)
}

func NewConnection(config ServerConfiguration, botConfig *Configuration, mdb *markov.MarkovDB) *Connection {
	conn := &Connection{
		config:          config,
		nickname:        config.Nickname,
		chanmap:         make(map[string]*Channel),
		usermap:         make(map[string]*User),
		floodProtection: true,
		lastSent:        time.Now(),
		out:             make(chan string, 32),
		inerr:           make(chan error, numLoops),
		outerr:          make(chan bool, numLoops),
		mdb:             mdb,
		tryReconnect:    true,
	}

	// setup internal callbacks
	conn.SetupCallbacks()
	conn.SetupPlugins(botConfig.Plugins)

	return conn
}

func (c *Connection) MainLoop() {
	for {
		err := c.Connect()
		if err != nil {
			log.Printf("Connection error: %s\n", err)
		}
		if !c.tryReconnect {
			return
		}

		c.reinit()
		time.Sleep(time.Second * 5)
	}
}

func (c *Connection) reinit() {
	close(c.out)
	close(c.inerr)
	close(c.outerr)
	c.out = make(chan string, 32)
	c.inerr = make(chan error, numLoops)
	c.outerr = make(chan bool, numLoops)
}

// Connect to the server, launch all internal goroutines.
func (c *Connection) Connect() (err error) {
	if c.config.Ssl {
		// XXX should use a valid tls client configuration insted of nil (default)
		c.sock, err = tls.Dial("tcp", c.config.Address, nil)
	} else {
		c.sock, err = net.Dial("tcp", c.config.Address)
	}
	if err != nil {
		return
	}

	log.Println("Connected to:", c.config.Address)
	c.connected = true

	c.io = bufio.NewReadWriter(
		bufio.NewReader(c.sock),
		bufio.NewWriter(c.sock))

	// remember to update numLoops if you add or remove loop methods!
	c.wg.Add(numLoops)
	go c.writeLoop()
	go c.readLoop()
	go c.pingLoop()
	go c.errLoop()

	c.RunCallbacks(&Message{Cmd: "INIT"})

	c.wg.Wait()

	return nil
}

func (c *Connection) errLoop() {
	defer func() {
		log.Println("exiting errLoop()")
		c.wg.Done()
	}()

	for {
		select {
		case err := <-c.inerr:
			log.Printf("Incoming error: %s\n", err)

			// ensure we have closed the socket
			c.sock.Close()

			// incoming error from a goroutine
			for i := 0; i < numLoops; i++ {
				c.outerr <- true
			}
			return
		case <-c.outerr:
			log.Printf("errLoop: alert received, bye!\n")
			return
		}
	}
}

func (c *Connection) writeLoop() {
	defer func() {
		defer log.Println("exiting writeLoop()")
		defer c.wg.Done()
	}()

	for {
		select {
		case line := <-c.out:
			err := c.write(line)
			if err != nil {
				log.Println("ERROR writing:", err)
				c.inerr <- err
				return
			}
		case <-c.outerr:
			return
		}
	}
}

func (c *Connection) readLoop() {
	defer func() {
		defer log.Println("exiting readLoop()")
		defer c.wg.Done()
	}()

	for {
		// a read() on a closed socket should always fail, so we can skip
		// the check on outerr.
		line, err := c.io.ReadString('\n')
		if err != nil {
			log.Printf("error reading from socket: %s\n", err)
			c.inerr <- err
			return
		}

		line = strings.TrimRight(line, "\r\n")

		if message, err := parseMessage(line); err == nil {
			log.Println("message =", message.Dump())
			c.RunCallbacks(message)
		} else {
			log.Printf("parsing failed (%s) for line: %q\n", err, line)
		}
	}
}

func (c *Connection) pingLoop() {
	defer func() {
		defer log.Println("exiting pingLoop()")
		defer c.wg.Done()
	}()

	tick := time.NewTicker(pingFrequency)
	for {
		select {
		case <-tick.C:
			c.ServerPing()
		case <-c.outerr:
			tick.Stop()
			return
		}
	}
}

func (c *Connection) write(line string) error {
	if !c.floodProtection {
		if t := c.rateLimit(len(line)); t != 0 {
			log.Printf("anti-flood: sleeping for %.2f seconds\n", t.Seconds())
			<-time.After(t)
		}
	}

	if _, err := c.io.WriteString(line); err != nil {
		return err
	}

	if err := c.io.Flush(); err != nil {
		return err
	}
	return nil
}

func (c *Connection) rateLimit(chars int) time.Duration {
	lineTime := 2*time.Second + time.Duration(chars)*time.Second/120
	elapsed := time.Now().Sub(c.lastSent)
	if c.badness += lineTime - elapsed; c.badness < 0 {
		c.badness = 0
	}
	c.lastSent = time.Now()

	if c.badness > 10*time.Second {
		return lineTime
	}

	return 0
}

func (c *Connection) Shutdown() {
	c.tryReconnect = false
	c.inerr <- errors.New("shutdown requested")
}
<commit_msg>use a constant for duration of sleep between reconnection attempts<commit_after>// dulbecco is a IRC bot.
//
// Plugin support through external commands (bash, python, ...).
//
//   most of the code was copied from:
//   - https://github.com/fluffle/goirc
//   - https://github.com/thoj/go-ircevent
package dulbecco

import (
	"bufio"
	"crypto/tls"
	"errors"
	"github.com/piger/dulbecco/markov"
	"log"
	"net"
	"strings"
	"sync"
	"time"
)

var (
	pingFrequency = 3 * time.Minute
)

// the number of *Loop() methods on Connection; it's used for synchronization
// and must be updated accordingly.
const (
	numLoops = 4

	NickservName = "nickserv"

	// IRC defines a maximum "line" length of 512 characters, including \r\n,
	// the command and all parameters. On Azzurra the limit seems to be lower...
	MaximumCommandLength = 460

	SleepBetweenReconnects = time.Minute * 5
)

type Channel struct {
	name, topic string
	names       []string
}

type User struct {
	nickname, username, hostname, realname string

	channels map[string]bool
}

func NewUser(nickname string) *User {
	user := &User{
		nickname: nickname,
		channels: make(map[string]bool),
	}
	return user
}

// A connection to the IRC server, also the main data structure of the IRC bot.
type Connection struct {
	config ServerConfiguration

	// current nickname
	nickname string

	chanmap map[string]*Channel
	usermap map[string]*User

	// enable anti-flood protection
	floodProtection bool
	// anti-flood internal counters
	badness  time.Duration
	lastSent time.Time

	// IO
	sock         net.Conn
	io           *bufio.ReadWriter
	out          chan string
	connected    bool
	tryReconnect bool

	// lock shutdown calls
	mutex sync.Mutex

	// SSL
	useTLS bool

	// Internal channels
	inerr  chan error
	outerr chan bool
	wg     sync.WaitGroup

	// markov database
	mdb *markov.MarkovDB

	// callbacks
	events map[string]map[string]func(*Message)
}

func NewConnection(config ServerConfiguration, botConfig *Configuration, mdb *markov.MarkovDB) *Connection {
	conn := &Connection{
		config:          config,
		nickname:        config.Nickname,
		chanmap:         make(map[string]*Channel),
		usermap:         make(map[string]*User),
		floodProtection: true,
		lastSent:        time.Now(),
		out:             make(chan string, 32),
		inerr:           make(chan error, numLoops),
		outerr:          make(chan bool, numLoops),
		mdb:             mdb,
		tryReconnect:    true,
	}

	// setup internal callbacks
	conn.SetupCallbacks()
	conn.SetupPlugins(botConfig.Plugins)

	return conn
}

func (c *Connection) MainLoop() {
	for {
		err := c.Connect()
		if err != nil {
			log.Printf("Connection error: %s\n", err)
		}
		if !c.tryReconnect {
			return
		}

		c.reinit()
		time.Sleep(SleepBetweenReconnects)
	}
}

func (c *Connection) reinit() {
	close(c.out)
	close(c.inerr)
	close(c.outerr)
	c.out = make(chan string, 32)
	c.inerr = make(chan error, numLoops)
	c.outerr = make(chan bool, numLoops)
}

// Connect to the server, launch all internal goroutines.
func (c *Connection) Connect() (err error) {
	if c.config.Ssl {
		// XXX should use a valid tls client configuration insted of nil (default)
		c.sock, err = tls.Dial("tcp", c.config.Address, nil)
	} else {
		c.sock, err = net.Dial("tcp", c.config.Address)
	}
	if err != nil {
		return
	}

	log.Println("Connected to:", c.config.Address)
	c.connected = true

	c.io = bufio.NewReadWriter(
		bufio.NewReader(c.sock),
		bufio.NewWriter(c.sock))

	// remember to update numLoops if you add or remove loop methods!
	c.wg.Add(numLoops)
	go c.writeLoop()
	go c.readLoop()
	go c.pingLoop()
	go c.errLoop()

	c.RunCallbacks(&Message{Cmd: "INIT"})

	c.wg.Wait()

	return nil
}

func (c *Connection) errLoop() {
	defer func() {
		log.Println("exiting errLoop()")
		c.wg.Done()
	}()

	for {
		select {
		case err := <-c.inerr:
			log.Printf("Incoming error: %s\n", err)

			// ensure we have closed the socket
			c.sock.Close()

			// incoming error from a goroutine
			for i := 0; i < numLoops; i++ {
				c.outerr <- true
			}
			return
		case <-c.outerr:
			log.Printf("errLoop: alert received, bye!\n")
			return
		}
	}
}

func (c *Connection) writeLoop() {
	defer func() {
		defer log.Println("exiting writeLoop()")
		defer c.wg.Done()
	}()

	for {
		select {
		case line := <-c.out:
			err := c.write(line)
			if err != nil {
				log.Println("ERROR writing:", err)
				c.inerr <- err
				return
			}
		case <-c.outerr:
			return
		}
	}
}

func (c *Connection) readLoop() {
	defer func() {
		defer log.Println("exiting readLoop()")
		defer c.wg.Done()
	}()

	for {
		// a read() on a closed socket should always fail, so we can skip
		// the check on outerr.
		line, err := c.io.ReadString('\n')
		if err != nil {
			log.Printf("error reading from socket: %s\n", err)
			c.inerr <- err
			return
		}

		line = strings.TrimRight(line, "\r\n")

		if message, err := parseMessage(line); err == nil {
			log.Println("message =", message.Dump())
			c.RunCallbacks(message)
		} else {
			log.Printf("parsing failed (%s) for line: %q\n", err, line)
		}
	}
}

func (c *Connection) pingLoop() {
	defer func() {
		defer log.Println("exiting pingLoop()")
		defer c.wg.Done()
	}()

	tick := time.NewTicker(pingFrequency)
	for {
		select {
		case <-tick.C:
			c.ServerPing()
		case <-c.outerr:
			tick.Stop()
			return
		}
	}
}

func (c *Connection) write(line string) error {
	if !c.floodProtection {
		if t := c.rateLimit(len(line)); t != 0 {
			log.Printf("anti-flood: sleeping for %.2f seconds\n", t.Seconds())
			<-time.After(t)
		}
	}

	if _, err := c.io.WriteString(line); err != nil {
		return err
	}

	if err := c.io.Flush(); err != nil {
		return err
	}
	return nil
}

func (c *Connection) rateLimit(chars int) time.Duration {
	lineTime := 2*time.Second + time.Duration(chars)*time.Second/120
	elapsed := time.Now().Sub(c.lastSent)
	if c.badness += lineTime - elapsed; c.badness < 0 {
		c.badness = 0
	}
	c.lastSent = time.Now()

	if c.badness > 10*time.Second {
		return lineTime
	}

	return 0
}

func (c *Connection) Shutdown() {
	c.tryReconnect = false
	c.inerr <- errors.New("shutdown requested")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net/textproto"
	"os"
	"regexp"
	"runtime"
	"strings"
	"sync"
)

//output err
func errOut(err error, quit chan bool) {
	fmt.Println("ERROR: ", err.Error())
	var trace []byte
	runtime.Stack(trace, false)
	fmt.Print(trace)
	if err.Error() == "EOF" {
		fmt.Println("EXITING")
		for i := 0; i < 2; i++ {
			quit <- true
		}
		fmt.Println("QUITS SENT")
	}
}

//take input from srvChan and send to server
func writeToServer(socket *textproto.Conn, srvChan chan string, wg *sync.WaitGroup, quit chan bool) {
	defer wg.Done()
	defer fmt.Println("WTS")
	w := socket.Writer
	err := w.PrintfLine(<-srvChan)
	for ; err == nil; {
		select {
		case <- quit:
			return
		case str := <- srvChan:
			err = w.PrintfLine(str)
		}
	}
	if err != nil {
		errOut(err, quit)
		socket.Close()
	}
}

//take input from connection and write out to console, also handle PING/PONG
func writeToConsole(socket *textproto.Conn, srvChan chan string, wg *sync.WaitGroup, quit chan bool) {
	defer wg.Done()
	defer fmt.Println("WTC")
	r := socket.Reader
	pingRegex := regexp.MustCompile("^PING (.*)")
	line, line_err := r.ReadLine()
	for ; line_err == nil; line, line_err = r.ReadLine() {
		select {
		case <- quit:
			return
		default:
		}
		fmt.Println(line)
		if match := pingRegex.FindStringSubmatch(line); match != nil {
			srvChan <- ("PONG " + match[1])
			fmt.Println("PONG", match[1])
		}
	}
	if line_err != nil {
		errOut(line_err, quit)
		socket.Close()
	}
}

//read input from console and send to srvChan
func readFromConsole(srvChan chan string, wg *sync.WaitGroup, quit chan bool, error chan bool) {
	defer wg.Done()
	defer fmt.Println("RFC")
	in := bufio.NewScanner(os.Stdin)
	for in.Scan() {
		str := in.Text()
		srvChan <- str
		if strings.TrimSpace(str) == "QUIT" {
			error <- true
			return
		}
	}
	if err := in.Err(); err != nil {
		errOut(err, quit)
	}
}

func main() {
	//funcMap := initMap()
	srvChan := make(chan string)
	var wgSrv, wg sync.WaitGroup
	quit := make(chan bool, 2)
	error := make(chan bool, 1)
	//initiate connection
	wg.Add(1)
	go readFromConsole(srvChan, &wg, quit, error) //doesnt get restarted on connection EOF
connectionLoop:
	for {
		select {
		case <-error: //if readFromConsole got a "QUIT", exit program
			break connectionLoop
		default: //otherwise restart connections
			socket, err := textproto.Dial("tcp", "irc.tamu.edu:6667")
			if err != nil {
				errOut(err, quit)
				return
			}
			//make writer/reader to/from server
			//send initial IRC messages, NICK and USER
			err = socket.Writer.PrintfLine("NICK yaircb")
			if err != nil {
				errOut(err, quit)
			}
			wgSrv.Add(1)
			//launch routine to write server output to console
			go writeToConsole(socket, srvChan, &wgSrv, quit)
			err = socket.Writer.PrintfLine("USER yaircb * * yaircb")
			if err != nil {
				errOut(err, quit)
			}
			//join first channel
			err = socket.Writer.PrintfLine("JOIN #ttestt")
			if err != nil {
				errOut(err, quit)
			}
			wgSrv.Add(1)
			//launch routine to send to server and get input from console
			go writeToServer(socket, srvChan, &wgSrv, quit)
			wgSrv.Wait()
		}
	}
	wg.Wait()
}
<commit_msg>gofmt<commit_after>package main

import (
	"bufio"
	"fmt"
	"net/textproto"
	"os"
	"regexp"
	"runtime"
	"strings"
	"sync"
)

//output err
func errOut(err error, quit chan bool) {
	fmt.Println("ERROR: ", err.Error())
	var trace []byte
	runtime.Stack(trace, false)
	fmt.Print(trace)
	if err.Error() == "EOF" {
		fmt.Println("EXITING")
		for i := 0; i < 2; i++ {
			quit <- true
		}
		fmt.Println("QUITS SENT")
	}
}

//take input from srvChan and send to server
func writeToServer(socket *textproto.Conn, srvChan chan string, wg *sync.WaitGroup, quit chan bool) {
	defer wg.Done()
	defer fmt.Println("WTS")
	w := socket.Writer
	err := w.PrintfLine(<-srvChan)
	for err == nil {
		select {
		case <-quit:
			return
		case str := <-srvChan:
			err = w.PrintfLine(str)
		}
	}
	if err != nil {
		errOut(err, quit)
		socket.Close()
	}
}

//take input from connection and write out to console, also handle PING/PONG
func writeToConsole(socket *textproto.Conn, srvChan chan string, wg *sync.WaitGroup, quit chan bool) {
	defer wg.Done()
	defer fmt.Println("WTC")
	r := socket.Reader
	pingRegex := regexp.MustCompile("^PING (.*)")
	line, line_err := r.ReadLine()
	for ; line_err == nil; line, line_err = r.ReadLine() {
		select {
		case <-quit:
			return
		default:
		}
		fmt.Println(line)
		if match := pingRegex.FindStringSubmatch(line); match != nil {
			srvChan <- ("PONG " + match[1])
			fmt.Println("PONG", match[1])
		}
	}
	if line_err != nil {
		errOut(line_err, quit)
		socket.Close()
	}
}

//read input from console and send to srvChan
func readFromConsole(srvChan chan string, wg *sync.WaitGroup, quit chan bool, error chan bool) {
	defer wg.Done()
	defer fmt.Println("RFC")
	in := bufio.NewScanner(os.Stdin)
	for in.Scan() {
		str := in.Text()
		srvChan <- str
		if strings.TrimSpace(str) == "QUIT" {
			error <- true
			return
		}
	}
	if err := in.Err(); err != nil {
		errOut(err, quit)
	}
}

func main() {
	//funcMap := initMap()
	srvChan := make(chan string)
	var wgSrv, wg sync.WaitGroup
	quit := make(chan bool, 2)
	error := make(chan bool, 1)
	//initiate connection
	wg.Add(1)
	go readFromConsole(srvChan, &wg, quit, error) //doesnt get restarted on connection EOF
connectionLoop:
	for {
		select {
		case <-error: //if readFromConsole got a "QUIT", exit program
			break connectionLoop
		default: //otherwise restart connections
			socket, err := textproto.Dial("tcp", "irc.tamu.edu:6667")
			if err != nil {
				errOut(err, quit)
				return
			}
			//make writer/reader to/from server
			//send initial IRC messages, NICK and USER
			err = socket.Writer.PrintfLine("NICK yaircb")
			if err != nil {
				errOut(err, quit)
			}
			wgSrv.Add(1)
			//launch routine to write server output to console
			go writeToConsole(socket, srvChan, &wgSrv, quit)
			err = socket.Writer.PrintfLine("USER yaircb * * yaircb")
			if err != nil {
				errOut(err, quit)
			}
			//join first channel
			err = socket.Writer.PrintfLine("JOIN #ttestt")
			if err != nil {
				errOut(err, quit)
			}
			wgSrv.Add(1)
			//launch routine to send to server and get input from console
			go writeToServer(socket, srvChan, &wgSrv, quit)
			wgSrv.Wait()
		}
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>package jit
/*
#cgo LDFLAGS: -lm -ljit
#include <stdio.h>
#include <jit/jit.h>
#include <jit/jit-dump.h>

extern int on_demand_compile(jit_function_t);

static void SetOnDemandCompileFunction(jit_function_t f) {
    jit_function_set_on_demand_compiler(f, on_demand_compile);
}

*/
import "C"
import "unsafe"

const CDECL = C.jit_abi_cdecl

type Context struct {
    C C.jit_context_t
}

type Type struct {
    C C.jit_type_t
}

type Signature struct {
    C C.jit_type_t
}

type Function struct {
    C         C.jit_function_t
    retType   Type
    paramType []Type
}

type Value struct {
    C C.jit_value_t
}

type Label struct {
    C C.jit_label_t
}

var intType = Type{ C.jit_type_int }
func Int() Type {
    return intType
}

var uintType = Type{ C.jit_type_uint }
func UInt() Type {
    return uintType
}

func NewContext() *Context {
    return &Context{ C.jit_context_create() }
}

func NewSignature(ret Type, params []Type) *Signature {
    signature := C.jit_type_create_signature(C.jit_abi_cdecl,
        ret.C,
        (*C.jit_type_t)(unsafe.Pointer(&params[0])),
        C.uint(len(params)), 1)
    return &Signature{signature}
}

func NewLabel() *Label {
    return &Label{ C.jit_label_undefined }
}

// ========== Context =============

func (c *Context) NewFunction(ret Type, params []Type) *Function {
    signature := NewSignature(ret, params)
    function := C.jit_function_create(c.C, signature.C)
    C.jit_type_free(signature.C)
    return &Function{C: function, retType: ret, paramType: params}
}

func (c *Context) BuildStart() {
    C.jit_context_build_start(c.C)
}

func (c *Context) BuildEnd() {
    C.jit_context_build_end(c.C)
}

func (c *Context) Destroy() {
    C.jit_context_destroy(c.C)
}

// ========== Context =============

// ========== Function =============

func (f *Function) Param(i int) *Value {
    return &Value{ C.jit_value_get_param(f.C, C.uint(i)) }
}

func (f *Function) Param2() (*Value, *Value) {
    return &Value{ C.jit_value_get_param(f.C, C.uint(0)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(1)) }
}

func (f *Function) Param3() (*Value, *Value, *Value) {
    return &Value{ C.jit_value_get_param(f.C, C.uint(0)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(1)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(2)) }
}

func (f *Function) Mul(a, b *Value) *Value {
    return &Value{ C.jit_insn_mul(f.C, a.C, b.C) }
}

func (f *Function) Add(a, b *Value) *Value {
    return &Value{ C.jit_insn_add(f.C, a.C, b.C) }
}

func (f *Function) Sub(a, b *Value) *Value {
    return &Value{ C.jit_insn_sub(f.C, a.C, b.C) }
}

func (f *Function) Return(ret *Value) {
    C.jit_insn_return(f.C, ret.C)
}

func (f *Function) Eq(a, b *Value) *Value {
    return &Value{ C.jit_insn_eq(f.C, a.C, b.C) }
}

func (f *Function) BranchIfNot(v *Value, label *Label) {
    C.jit_insn_branch_if_not(f.C, v.C, (*C.jit_label_t)(unsafe.Pointer(label)))
}

func (f *Function) Label(label *Label) {
    C.jit_insn_label(f.C, (*C.jit_label_t)(unsafe.Pointer(label)))
}

func (f *Function) LessThan(a, b *Value) *Value {
    return &Value{ C.jit_insn_lt(f.C, a.C, b.C) }
}

func (f *Function) Call(target *Function, values []*Value) *Value {
    args := make([]C.jit_value_t, len(values))
    for i := range values {
        args[i] = values[i].C
    }
    return &Value{ C.jit_insn_call(f.C,
                    C.CString("noname"),
                    target.C, nil, (*C.jit_value_t)(&args[0]), C.uint(len(args)), C.int(0)) }
}

func (f *Function) Compile() {
    C.jit_function_compile(f.C)
}

func (f *Function) Run(values ...interface{}) interface{} {
    args := make([]unsafe.Pointer, len(values))
    for i := range values {
        switch f.paramType[i].C {
            case C.jit_type_int:
                x := C.jit_int(values[i].(int))
                args[i] = (unsafe.Pointer)(&x)

            case C.jit_type_uint:
                x := C.jit_uint(values[i].(uint))
                args[i] = (unsafe.Pointer)(&x)
        }
    }

    switch f.retType.C {
        case C.jit_type_int:
            result := C.jit_int(0)
            C.jit_function_apply(f.C, (*unsafe.Pointer)(&args[0]), unsafe.Pointer(&result))
            return int(result)

        case C.jit_type_uint:
            result := C.jit_uint(0)
            C.jit_function_apply(f.C, (*unsafe.Pointer)(&args[0]), unsafe.Pointer(&result))
            return uint(result)
    }

    return nil
}

func (f *Function) Dump(name string) {
    C.jit_dump_function((*C.FILE)(C.stdout), f.C, C.CString(name))
}

func (f *Function) SetRecompilable() {
    C.jit_function_set_recompilable(f.C)
}

type compileFunction struct {
    F           *Function
    compileFunc func(*Function)bool
}

var registry = make(map[C.jit_function_t]*compileFunction)

func (f *Function) SetOnDemandCompiler(function func(f *Function)bool) {
    registry[f.C] = &compileFunction{f, function}
    C.SetOnDemandCompileFunction(f.C)
}

func (f *Function) GetOnDemandCompiler() func(*Function)bool {
    return registry[f.C].compileFunc
}

// ========== Function =============

//export on_demand_compile
func on_demand_compile(f C.jit_function_t) C.int {
    cf := registry[f]
    result := cf.compileFunc(cf.F)
    if(result) {
        return C.int(1)
    }
    return C.int(0)
}
<commit_msg>add Call0<commit_after>package jit
/*
#cgo LDFLAGS: -lm -ljit
#include <stdio.h>
#include <jit/jit.h>
#include <jit/jit-dump.h>

extern int on_demand_compile(jit_function_t);

static void SetOnDemandCompileFunction(jit_function_t f) {
    jit_function_set_on_demand_compiler(f, on_demand_compile);
}

*/
import "C"
import "unsafe"

const CDECL = C.jit_abi_cdecl

type Context struct {
    C C.jit_context_t
}

type Type struct {
    C C.jit_type_t
}

type Signature struct {
    C C.jit_type_t
}

type Function struct {
    C         C.jit_function_t
    retType   Type
    paramType []Type
}

type Value struct {
    C C.jit_value_t
}

type Label struct {
    C C.jit_label_t
}

var intType = Type{ C.jit_type_int }
func Int() Type {
    return intType
}

var uintType = Type{ C.jit_type_uint }
func UInt() Type {
    return uintType
}

func NewContext() *Context {
    return &Context{ C.jit_context_create() }
}

func NewSignature(ret Type, params []Type) *Signature {
    signature := C.jit_type_create_signature(C.jit_abi_cdecl,
        ret.C,
        (*C.jit_type_t)(unsafe.Pointer(&params[0])),
        C.uint(len(params)), 1)
    return &Signature{signature}
}

func NewLabel() *Label {
    return &Label{ C.jit_label_undefined }
}

// ========== Context =============

func (c *Context) NewFunction(ret Type, params []Type) *Function {
    signature := NewSignature(ret, params)
    function := C.jit_function_create(c.C, signature.C)
    C.jit_type_free(signature.C)
    return &Function{C: function, retType: ret, paramType: params}
}

func (c *Context) BuildStart() {
    C.jit_context_build_start(c.C)
}

func (c *Context) BuildEnd() {
    C.jit_context_build_end(c.C)
}

func (c *Context) Destroy() {
    C.jit_context_destroy(c.C)
}

// ========== Context =============

// ========== Function =============

func (f *Function) Param(i int) *Value {
    return &Value{ C.jit_value_get_param(f.C, C.uint(i)) }
}

func (f *Function) Param2() (*Value, *Value) {
    return &Value{ C.jit_value_get_param(f.C, C.uint(0)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(1)) }
}

func (f *Function) Param3() (*Value, *Value, *Value) {
    return &Value{ C.jit_value_get_param(f.C, C.uint(0)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(1)) },
           &Value{ C.jit_value_get_param(f.C, C.uint(2)) }
}

func (f *Function) Mul(a, b *Value) *Value {
    return &Value{ C.jit_insn_mul(f.C, a.C, b.C) }
}

func (f *Function) Add(a, b *Value) *Value {
    return &Value{ C.jit_insn_add(f.C, a.C, b.C) }
}

func (f *Function) Sub(a, b *Value) *Value {
    return &Value{ C.jit_insn_sub(f.C, a.C, b.C) }
}

func (f *Function) Return(ret *Value) {
    C.jit_insn_return(f.C, ret.C)
}

func (f *Function) Eq(a, b *Value) *Value {
    return &Value{ C.jit_insn_eq(f.C, a.C, b.C) }
}

func (f *Function) BranchIfNot(v *Value, label *Label) {
    C.jit_insn_branch_if_not(f.C, v.C, (*C.jit_label_t)(unsafe.Pointer(label)))
}

func (f *Function) Label(label *Label) {
    C.jit_insn_label(f.C, (*C.jit_label_t)(unsafe.Pointer(label)))
}

func (f *Function) LessThan(a, b *Value) *Value {
    return &Value{ C.jit_insn_lt(f.C, a.C, b.C) }
}

func (f *Function) Call(target *Function, values []*Value) *Value {
    args := make([]C.jit_value_t, len(values))
    for i := range values {
        args[i] = values[i].C
    }
    return &Value{ C.jit_insn_call(f.C,
                    C.CString("noname"),
                    target.C, nil, (*C.jit_value_t)(&args[0]), C.uint(len(args)), C.int(0)) }
}

func (f *Function) Call0(name string, target *Function, values ...*Value) *Value {
    args := make([]C.jit_value_t, len(values))
    for i := range values {
        args[i] = values[i].C
    }
    return &Value{ C.jit_insn_call(f.C,
                    C.CString(name),
                    target.C, nil, (*C.jit_value_t)(&args[0]), C.uint(len(args)), C.int(0)) }
}

func (f *Function) Compile() {
    C.jit_function_compile(f.C)
}

func (f *Function) Run(values ...interface{}) interface{} {
    args := make([]unsafe.Pointer, len(values))
    for i := range values {
        switch f.paramType[i].C {
            case C.jit_type_int:
                x := C.jit_int(values[i].(int))
                args[i] = (unsafe.Pointer)(&x)

            case C.jit_type_uint:
                x := C.jit_uint(values[i].(uint))
                args[i] = (unsafe.Pointer)(&x)
        }
    }

    switch f.retType.C {
        case C.jit_type_int:
            result := C.jit_int(0)
            C.jit_function_apply(f.C, (*unsafe.Pointer)(&args[0]), unsafe.Pointer(&result))
            return int(result)

        case C.jit_type_uint:
            result := C.jit_uint(0)
            C.jit_function_apply(f.C, (*unsafe.Pointer)(&args[0]), unsafe.Pointer(&result))
            return uint(result)
    }

    return nil
}

func (f *Function) Dump(name string) {
    C.jit_dump_function((*C.FILE)(C.stdout), f.C, C.CString(name))
}

func (f *Function) SetRecompilable() {
    C.jit_function_set_recompilable(f.C)
}

type compileFunction struct {
    F           *Function
    compileFunc func(*Function)bool
}

var registry = make(map[C.jit_function_t]*compileFunction)

func (f *Function) SetOnDemandCompiler(function func(f *Function)bool) {
    registry[f.C] = &compileFunction{f, function}
    C.SetOnDemandCompileFunction(f.C)
}

func (f *Function) GetOnDemandCompiler() func(*Function)bool {
    return registry[f.C].compileFunc
}

// ========== Function =============

//export on_demand_compile
func on_demand_compile(f C.jit_function_t) C.int {
    cf := registry[f]
    result := cf.compileFunc(cf.F)
    if(result) {
        return C.int(1)
    }
    return C.int(0)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"
)

type Job struct {
	ID          int               `json:"id"`
	Script      string            `json:"script"`
	Args        []string          `json:"args,omitempty"`
	Files       map[string]string `json:"files,omitempty"`
	CallbackURL string            `json:"callback_url,omitempty"`
	Output      string            `json:"output"`
	ExecLog     string            `json:"exec_log"`
	Status      string            `json:"status"`
	StartTime   time.Time         `json:"start_time"`
	FinishTime  time.Time         `json:"end_time"`
	Duration    string            `json:"duration"`
}

func NewJob(data []byte) (Job, error) {
	var job Job
	job.Status = STATUS_ERR

	err := json.Unmarshal(data, &job)
	if err != nil {
		return job, err
	}
	return job, nil
}

func (j *Job) CleanArgs() ([]string, error) {
	// TODO find a way to clean the arguments
	return j.Args, nil
}

func (j *Job) SaveFiles(dir string) error {
	var err error
	var file string
	for name, data := range j.Files {

		// Clean bad input
		name = strings.Replace(name, "..", "", -1)
		name = strings.Replace(name, "/", "", -1)

		file = path.Join(dir, name)
		log.Debug("Writing %s to disk", file)
		err = ioutil.WriteFile(file, []byte(data), 0644)
		if err != nil {
			return err
		}
	}
	return nil
}

func (j *Job) Log() error {
	conn := redisDB.Get()
	defer conn.Close()

	data, err := json.Marshal(j)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	log.Debug("Adding job %d to log for %s to Redis\n", j.ID, j.Script)
	_, err = conn.Do("ZADD", j.Script, j.ID, data)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	log.Debug("Trimming log for %s to the %d most recent\n", j.Script, LOGLIMIT)
	_, err = conn.Do("ZREMRANGEBYRANK", j.Script, 0, -LOGLIMIT-1)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (j *Job) Callback() error {
	data, err := json.Marshal(j)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	log.Info("Sending response back to %s", j.CallbackURL)
	buf := bytes.NewBuffer(data)
	_, err = http.Post(j.CallbackURL, "application/json", buf)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (j *Job) Execute(ch chan error) {
	j.StartTime = time.Now()

	// Intialize script path and arguments
	s := path.Join(config.Worker.ScriptDir, j.Script)
	args, err := j.CleanArgs()
	if err != nil {
		j.ExecLog = fmt.Sprintf("%s", err)
		ch <- err
		return
	}

	// Set environment variables
	os.Setenv("QMD_STORE", config.Worker.StoreDir)

	tmpPath := path.Join(config.Worker.WorkingDir, strconv.Itoa(j.ID))
	os.MkdirAll(tmpPath, 0775)
	os.Setenv("QMD_TMP", tmpPath)
	defer j.RemoveTmpdir(tmpPath)

	err = j.SaveFiles(tmpPath)
	if err != nil {
		j.ExecLog = fmt.Sprintf("%s", err)
		ch <- err
		return
	}

	outPath := path.Join(tmpPath, "qmd.out")
	os.Setenv("QMD_OUT", outPath)

	// Setup and execute cmd
	cmd := exec.Command(s, args...)
	cmd.Dir = config.Worker.WorkingDir
	cmdOut := bytes.NewBuffer(nil)
	cmd.Stdout = cmdOut
	cmd.Stderr = cmdOut

	log.Info("Executing command: %s %s", s, args)
	err = cmd.Run()

	j.FinishTime = time.Now()
	j.Duration = fmt.Sprintf("%f", j.FinishTime.Sub(j.StartTime).Seconds())
	j.ExecLog = fmt.Sprintf("%s", string(cmdOut.Bytes()))

	if err != nil {
		j.ExecLog = fmt.Sprintf("%s\n%s", j.ExecLog, err)
		ch <- err
		return
	}

	data, err := ioutil.ReadFile(outPath)
	if !os.IsNotExist(err) {
		j.Output = string(data)
		err = nil
	}

	ch <- err
	return
}

func (j *Job) RemoveTmpdir(tmpPath string) {
	if !config.Worker.KeepTemp {
		log.Debug("Deleting all files and dirs in %s", tmpPath)
		err := os.RemoveAll(tmpPath)
		if err != nil {
			log.Error("Failed to delete all files and dirs in %s - %s", tmpPath, err)
		}
	}
}
<commit_msg>Skip callback if no URL given.<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"time"
)

type Job struct {
	ID          int               `json:"id"`
	Script      string            `json:"script"`
	Args        []string          `json:"args,omitempty"`
	Files       map[string]string `json:"files,omitempty"`
	CallbackURL string            `json:"callback_url,omitempty"`
	Output      string            `json:"output"`
	ExecLog     string            `json:"exec_log"`
	Status      string            `json:"status"`
	StartTime   time.Time         `json:"start_time"`
	FinishTime  time.Time         `json:"end_time"`
	Duration    string            `json:"duration"`
}

func NewJob(data []byte) (Job, error) {
	var job Job
	job.Status = STATUS_ERR

	err := json.Unmarshal(data, &job)
	if err != nil {
		return job, err
	}
	return job, nil
}

func (j *Job) CleanArgs() ([]string, error) {
	// TODO find a way to clean the arguments
	return j.Args, nil
}

func (j *Job) SaveFiles(dir string) error {
	var err error
	var file string
	for name, data := range j.Files {

		// Clean bad input
		name = strings.Replace(name, "..", "", -1)
		name = strings.Replace(name, "/", "", -1)

		file = path.Join(dir, name)
		log.Debug("Writing %s to disk", file)
		err = ioutil.WriteFile(file, []byte(data), 0644)
		if err != nil {
			return err
		}
	}
	return nil
}

func (j *Job) Log() error {
	conn := redisDB.Get()
	defer conn.Close()

	data, err := json.Marshal(j)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	log.Debug("Adding job %d to log for %s to Redis\n", j.ID, j.Script)
	_, err = conn.Do("ZADD", j.Script, j.ID, data)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	log.Debug("Trimming log for %s to the %d most recent\n", j.Script, LOGLIMIT)
	_, err = conn.Do("ZREMRANGEBYRANK", j.Script, 0, -LOGLIMIT-1)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (j *Job) Callback() error {
	data, err := json.Marshal(j)
	if err != nil {
		log.Error(err.Error())
		return err
	}

	if j.CallbackURL == "" {
		return fmt.Errorf("No callback url given")
	}

	log.Info("Sending response back to %s", j.CallbackURL)
	buf := bytes.NewBuffer(data)
	_, err = http.Post(j.CallbackURL, "application/json", buf)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (j *Job) Execute(ch chan error) {
	j.StartTime = time.Now()

	// Intialize script path and arguments
	s := path.Join(config.Worker.ScriptDir, j.Script)
	args, err := j.CleanArgs()
	if err != nil {
		j.ExecLog = fmt.Sprintf("%s", err)
		ch <- err
		return
	}

	// Set environment variables
	os.Setenv("QMD_STORE", config.Worker.StoreDir)

	tmpPath := path.Join(config.Worker.WorkingDir, strconv.Itoa(j.ID))
	os.MkdirAll(tmpPath, 0775)
	os.Setenv("QMD_TMP", tmpPath)
	defer j.RemoveTmpdir(tmpPath)

	err = j.SaveFiles(tmpPath)
	if err != nil {
		j.ExecLog = fmt.Sprintf("%s", err)
		ch <- err
		return
	}

	outPath := path.Join(tmpPath, "qmd.out")
	os.Setenv("QMD_OUT", outPath)

	// Setup and execute cmd
	cmd := exec.Command(s, args...)
	cmd.Dir = config.Worker.WorkingDir
	cmdOut := bytes.NewBuffer(nil)
	cmd.Stdout = cmdOut
	cmd.Stderr = cmdOut

	log.Info("Executing command: %s %s", s, args)
	err = cmd.Run()

	j.FinishTime = time.Now()
	j.Duration = fmt.Sprintf("%f", j.FinishTime.Sub(j.StartTime).Seconds())
	j.ExecLog = fmt.Sprintf("%s", string(cmdOut.Bytes()))

	if err != nil {
		j.ExecLog = fmt.Sprintf("%s\n%s", j.ExecLog, err)
		ch <- err
		return
	}

	data, err := ioutil.ReadFile(outPath)
	if !os.IsNotExist(err) {
		j.Output = string(data)
		err = nil
	}

	ch <- err
	return
}

func (j *Job) RemoveTmpdir(tmpPath string) {
	if !config.Worker.KeepTemp {
		log.Debug("Deleting all files and dirs in %s", tmpPath)
		err := os.RemoveAll(tmpPath)
		if err != nil {
			log.Error("Failed to delete all files and dirs in %s - %s", tmpPath, err)
		}
	}
}
<|endoftext|>