<commit_before>package stdlib

import (
	"testing"
	"time"

	"github.com/PuerkitoBio/agora/runtime"
)

func TestTimeSleep(t *testing.T) {
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	n := time.Now()
	tm.time_Sleep(runtime.Number(100))
	if diff := time.Now().Sub(n); diff < 100*time.Millisecond {
		t.Errorf("expected at least 100ms, got %f", diff.Seconds()*1000)
	}
}

func TestTimeNow(t *testing.T) {
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	exp := time.Now()
	ret := tm.time_Now()
	ob := ret.(runtime.Object)
	if yr := ob.Get(runtime.String("Year")); yr.Int() != int64(exp.Year()) {
		t.Errorf("expected year %d, got %d", exp.Year(), yr.Int())
	}
	if mt := ob.Get(runtime.String("Month")); mt.Int() != int64(exp.Month()) {
		t.Errorf("expected month %d, got %d", exp.Month(), mt.Int())
	}
	if dy := ob.Get(runtime.String("Day")); dy.Int() != int64(exp.Day()) {
		t.Errorf("expected day %d, got %d", exp.Day(), dy.Int())
	}
	if hr := ob.Get(runtime.String("Hour")); hr.Int() != int64(exp.Hour()) {
		t.Errorf("expected hour %d, got %d", exp.Hour(), hr.Int())
	}
	if mn := ob.Get(runtime.String("Minute")); mn.Int() != int64(exp.Minute()) {
		t.Errorf("expected minute %d, got %d", exp.Minute(), mn.Int())
	}
	if sc := ob.Get(runtime.String("Second")); sc.Int() != int64(exp.Second()) {
		t.Errorf("expected second %d, got %d", exp.Second(), sc.Int())
	}
	if ns := ob.Get(runtime.String("Nanosecond")); ns.Int() < int64(exp.Nanosecond()) {
		t.Errorf("expected nanosecond %d, got %d", exp.Nanosecond(), ns.Int())
	}
}

func TestTimeDate(t *testing.T) {
	cases := []struct {
		args []runtime.Val
		exp  time.Time
	}{
		0: {
			args: []runtime.Val{
				runtime.Number(1975),
			},
			exp: time.Date(1975, 1, 1, 0, 0, 0, 0, time.Local),
		},
		1: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
			},
			exp: time.Date(1975, 2, 1, 0, 0, 0, 0, time.Local),
		},
		2: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
			},
			exp: time.Date(1975, 2, 3, 0, 0, 0, 0, time.Local),
		},
		3: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
			},
			exp: time.Date(1975, 2, 3, 4, 0, 0, 0, time.Local),
		},
		4: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 0, 0, time.Local),
		},
		5: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
				runtime.Number(6),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 6, 0, time.Local),
		},
		6: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
				runtime.Number(6),
				runtime.Number(7),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 6, 7, time.Local),
		},
	}
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	for i, c := range cases {
		ret := tm.time_Date(c.args...)
		ob := ret.(runtime.Object)
		if yr := ob.Get(runtime.String("Year")); yr.Int() != int64(c.exp.Year()) {
			t.Errorf("[%d] - expected year %d, got %d", i, c.exp.Year(), yr.Int())
		}
		if mt := ob.Get(runtime.String("Month")); mt.Int() != int64(c.exp.Month()) {
			t.Errorf("[%d] - expected month %d, got %d", i, c.exp.Month(), mt.Int())
		}
		if dy := ob.Get(runtime.String("Day")); dy.Int() != int64(c.exp.Day()) {
			t.Errorf("[%d] - expected day %d, got %d", i, c.exp.Day(), dy.Int())
		}
		if hr := ob.Get(runtime.String("Hour")); hr.Int() != int64(c.exp.Hour()) {
			t.Errorf("[%d] - expected hour %d, got %d", i, c.exp.Hour(), hr.Int())
		}
		if mn := ob.Get(runtime.String("Minute")); mn.Int() != int64(c.exp.Minute()) {
			t.Errorf("[%d] - expected minute %d, got %d", i, c.exp.Minute(), mn.Int())
		}
		if sc := ob.Get(runtime.String("Second")); sc.Int() != int64(c.exp.Second()) {
			t.Errorf("[%d] - expected second %d, got %d", i, c.exp.Second(), sc.Int())
		}
		if ns := ob.Get(runtime.String("Nanosecond")); ns.Int() < int64(c.exp.Nanosecond()) {
			t.Errorf("[%d] - expected nanosecond %d, got %d", i, c.exp.Nanosecond(), ns.Int())
		}
	}
}
<commit_msg>add time conversion tests<commit_after>package stdlib

import (
	"testing"
	"time"

	"github.com/PuerkitoBio/agora/runtime"
)

func TestTimeConv(t *testing.T) {
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	nw := time.Now().UTC()
	n := tm.time_Date(runtime.Number(nw.Year()),
		runtime.Number(nw.Month()),
		runtime.Number(nw.Day()),
		runtime.Number(nw.Hour()),
		runtime.Number(nw.Minute()),
		runtime.Number(nw.Second()),
		runtime.Number(nw.Nanosecond()))
	ob := n.(runtime.Object)
	cnv := ob.Get(runtime.String("__toString"))
	f := cnv.(runtime.Func)
	ret := f.Call(nil)
	exp := nw.Format(time.RFC3339)
	if ret.String() != exp {
		t.Errorf("expected string to return '%s', got '%s'", exp, ret)
	}
	cnv = ob.Get(runtime.String("__toInt"))
	f = cnv.(runtime.Func)
	ret = f.Call(nil)
	{
		exp := nw.Unix()
		if ret.Int() != int64(exp) {
			t.Errorf("expected int to return %d, got %d", exp, ret.Int())
		}
	}
}

func TestTimeSleep(t *testing.T) {
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	n := time.Now()
	tm.time_Sleep(runtime.Number(100))
	if diff := time.Now().Sub(n); diff < 100*time.Millisecond {
		t.Errorf("expected at least 100ms, got %f", diff.Seconds()*1000)
	}
}

func TestTimeNow(t *testing.T) {
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	exp := time.Now()
	ret := tm.time_Now()
	ob := ret.(runtime.Object)
	if yr := ob.Get(runtime.String("Year")); yr.Int() != int64(exp.Year()) {
		t.Errorf("expected year %d, got %d", exp.Year(), yr.Int())
	}
	if mt := ob.Get(runtime.String("Month")); mt.Int() != int64(exp.Month()) {
		t.Errorf("expected month %d, got %d", exp.Month(), mt.Int())
	}
	if dy := ob.Get(runtime.String("Day")); dy.Int() != int64(exp.Day()) {
		t.Errorf("expected day %d, got %d", exp.Day(), dy.Int())
	}
	if hr := ob.Get(runtime.String("Hour")); hr.Int() != int64(exp.Hour()) {
		t.Errorf("expected hour %d, got %d", exp.Hour(), hr.Int())
	}
	if mn := ob.Get(runtime.String("Minute")); mn.Int() != int64(exp.Minute()) {
		t.Errorf("expected minute %d, got %d", exp.Minute(), mn.Int())
	}
	if sc := ob.Get(runtime.String("Second")); sc.Int() != int64(exp.Second()) {
		t.Errorf("expected second %d, got %d", exp.Second(), sc.Int())
	}
	if ns := ob.Get(runtime.String("Nanosecond")); ns.Int() < int64(exp.Nanosecond()) {
		t.Errorf("expected nanosecond %d, got %d", exp.Nanosecond(), ns.Int())
	}
}

func TestTimeDate(t *testing.T) {
	cases := []struct {
		args []runtime.Val
		exp  time.Time
	}{
		0: {
			args: []runtime.Val{
				runtime.Number(1975),
			},
			exp: time.Date(1975, 1, 1, 0, 0, 0, 0, time.Local),
		},
		1: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
			},
			exp: time.Date(1975, 2, 1, 0, 0, 0, 0, time.Local),
		},
		2: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
			},
			exp: time.Date(1975, 2, 3, 0, 0, 0, 0, time.Local),
		},
		3: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
			},
			exp: time.Date(1975, 2, 3, 4, 0, 0, 0, time.Local),
		},
		4: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 0, 0, time.Local),
		},
		5: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
				runtime.Number(6),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 6, 0, time.Local),
		},
		6: {
			args: []runtime.Val{
				runtime.Number(1975),
				runtime.Number(2),
				runtime.Number(3),
				runtime.Number(4),
				runtime.Number(5),
				runtime.Number(6),
				runtime.Number(7),
			},
			exp: time.Date(1975, 2, 3, 4, 5, 6, 7, time.Local),
		},
	}
	ctx := runtime.NewCtx(nil, nil)
	tm := new(TimeMod)
	tm.SetCtx(ctx)
	for i, c := range cases {
		ret := tm.time_Date(c.args...)
		ob := ret.(runtime.Object)
		if yr := ob.Get(runtime.String("Year")); yr.Int() != int64(c.exp.Year()) {
			t.Errorf("[%d] - expected year %d, got %d", i, c.exp.Year(), yr.Int())
		}
		if mt := ob.Get(runtime.String("Month")); mt.Int() != int64(c.exp.Month()) {
			t.Errorf("[%d] - expected month %d, got %d", i, c.exp.Month(), mt.Int())
		}
		if dy := ob.Get(runtime.String("Day")); dy.Int() != int64(c.exp.Day()) {
			t.Errorf("[%d] - expected day %d, got %d", i, c.exp.Day(), dy.Int())
		}
		if hr := ob.Get(runtime.String("Hour")); hr.Int() != int64(c.exp.Hour()) {
			t.Errorf("[%d] - expected hour %d, got %d", i, c.exp.Hour(), hr.Int())
		}
		if mn := ob.Get(runtime.String("Minute")); mn.Int() != int64(c.exp.Minute()) {
			t.Errorf("[%d] - expected minute %d, got %d", i, c.exp.Minute(), mn.Int())
		}
		if sc := ob.Get(runtime.String("Second")); sc.Int() != int64(c.exp.Second()) {
			t.Errorf("[%d] - expected second %d, got %d", i, c.exp.Second(), sc.Int())
		}
		if ns := ob.Get(runtime.String("Nanosecond")); ns.Int() < int64(c.exp.Nanosecond()) {
			t.Errorf("[%d] - expected nanosecond %d, got %d", i, c.exp.Nanosecond(), ns.Int())
		}
	}
}
<|endoftext|>


<commit_before>package main // FIXME omapi

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"os"
	"sort"
	"time"
)

type Opcode int32
type State int32

const (
	OpOpen Opcode = 1 + iota
	OpRefresh
	OpUpdate
	OpNotify
	OpStatus
	OpDelete
)

const (
	StateFree = 1 + iota
	StateActive
	StateExpired
	StateReleased
	StateAbandoned
	StateReset
	StateBackup
	StateReserved
	StateBootp
)

var Ethernet = []byte{0, 0, 0, 1}
var TokenRing = []byte{0, 0, 0, 6}
var FDDI = []byte{0, 0, 0, 8}

var True = []byte{0, 0, 0, 1}

func (opcode Opcode) String() (ret string) {
	switch opcode {
	case 1:
		ret = "open"
	case 2:
		ret = "refresh"
	case 3:
		ret = "update"
	case 4:
		ret = "notify"
	case 5:
		ret = "status"
	case 6:
		ret = "delete"
	}

	return
}

func (state State) String() (ret string) {
	switch state {
	case 1:
		ret = "free"
	case 2:
		ret = "active"
	case 3:
		ret = "expired"
	case 4:
		ret = "released"
	case 5:
		ret = "abandoned"
	case 6:
		ret = "reset"
	case 7:
		ret = "backup"
	case 8:
		ret = "reserved"
	case 9:
		ret = "bootp"
	}

	return
}

// TODO add size checks for all operations
type buffer struct {
	buffer *bytes.Buffer
}

func newBuffer() *buffer {
	return &buffer{new(bytes.Buffer)}
}

func (b *buffer) add_bytes(data []byte) {
	b.buffer.Write(data)
}

func (b *buffer) add(data interface{}) {
	err := binary.Write(b.buffer, binary.BigEndian, data)
	if err != nil {
		panic(err)
	}
}

func (b *buffer) add_map(data map[string][]byte) {
	// We need to add the map in a deterministic order for signing to
	// work, so we first sort the keys in alphabetical order, then use
	// that order to access the map entries.

	keys := make(sort.StringSlice, 0, len(data))

	for key := range data {
		keys = append(keys, key)
	}

	sort.Sort(keys)

	for _, key := range keys {
		value := data[key]

		b.add(int16(len(key)))
		b.add([]byte(key))

		b.add(int32(len(value)))
		b.add(value)
	}

	b.add([]byte("\x00\x00"))
}

func (b *buffer) bytes() []byte {
	return b.buffer.Bytes()
}

type Message struct {
	AuthID    int32
	Opcode    Opcode
	Handle    int32
	Tid       int32
	Rid       int32
	Message   map[string][]byte
	Object    map[string][]byte
	Signature []byte
}

func NewMessage() *Message {
	msg := &Message{
		Tid:     rand.Int31(),
		Message: make(map[string][]byte),
		Object:  make(map[string][]byte),
	}

	return msg
}

func NewOpenMessage(typeName string) *Message {
	message := NewMessage()
	message.Opcode = OpOpen
	message.Message["type"] = []byte(typeName)

	return message
}

func NewCreateMessage(typeName string) *Message {
	message := NewOpenMessage(typeName)
	message.Message["create"] = True
	// TODO Where is "exclusive" coming from? Is that always required
	// for creates, or only for hosts?
	message.Message["exclusive"] = True

	return message
}

func NewDeleteMessage(handle int32) *Message {
	message := NewMessage()
	message.Opcode = OpDelete
	message.Handle = handle

	return message
}

func (m *Message) Bytes(forSigning bool) []byte {
	ret := newBuffer()
	if !forSigning {
		ret.add(m.AuthID)
	}

	ret.add(int32(len(m.Signature)))
	ret.add(m.Opcode)
	ret.add(m.Handle)
	ret.add(m.Tid)
	ret.add(m.Rid)
	ret.add_map(m.Message)
	ret.add_map(m.Object)
	if !forSigning {
		ret.add(m.Signature)
	}

	return ret.buffer.Bytes()
}

func (m *Message) Sign(auth Authenticator) {
	m.AuthID = auth.AuthID()
	m.Signature = auth.Sign(m)
}

func (m *Message) Verify(auth Authenticator) bool {
	return bytes.Equal(auth.Sign(m), m.Signature)
}

func (m *Message) IsResponseTo(other *Message) bool {
	return m.Rid == other.Tid
}

type Connection struct {
	Hostname      string
	Port          int
	Username      string
	Key           string
	Authenticator Authenticator
	connection    *net.TCPConn
	inBuffer      *bytes.Buffer
}

func NewConnection(hostname string, port int, username string, key string) *Connection {
	con := &Connection{
		Hostname:      hostname,
		Port:          port,
		Username:      username,
		Key:           key,
		Authenticator: new(NullAuthenticator),
		inBuffer:      new(bytes.Buffer),
	}

	var newAuth Authenticator = new(NullAuthenticator)

	if len(username) > 0 && len(key) > 0 {
		decodedKey, err := base64.StdEncoding.DecodeString(key)
		if err != nil {
			panic(err)
		}
		newAuth = &HMACMD5Authenticator{username, decodedKey, -1}
	}

	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", hostname, port))
	if err != nil {
		// TODO return the error instead
		panic(err)
	}
	tcpConn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		// TODO return the error instead
		panic(err)
	}

	con.connection = tcpConn

	con.sendProtocolInitialization()
	con.receiveProtocolInitialization()
	con.initializeAuthenticator(newAuth)

	return con
}

func (con *Connection) initializeAuthenticator(auth Authenticator) {
	if _, ok := auth.(*NullAuthenticator); ok {
		return
	}

	message := NewOpenMessage("authenticator")
	for key, value := range auth.AuthObject() {
		message.Object[key] = value
	}

	response := con.queryServer(message)

	if response.Opcode != OpUpdate {
		panic("received non-update response for open")
	}

	if response.Handle == 0 {
		panic("received invalid authid from server")
	}

	auth.SetAuthID(response.Handle)
	con.Authenticator = auth
}

func (con *Connection) queryServer(msg *Message) *Message {
	msg.Sign(con.Authenticator)
	con.send(msg.Bytes(false))
	response := con.parseMessage()
	if !response.IsResponseTo(msg) {
		panic("received message is not the desired response")
	}

	// TODO check authid

	return response
}

func (con *Connection) send(data []byte) (n int, err error) {
	return con.connection.Write(data)
}

func (con *Connection) sendProtocolInitialization() {
	buf := newBuffer()
	buf.add(int32(100)) // Protocol version
	buf.add(int32(24))  // Header size
	con.send(buf.bytes())
}

func (con *Connection) read() {
	buf := make([]byte, 2048)
	n, err := con.connection.Read(buf)
	if err != nil {
		panic(err)
	}

	con.inBuffer.Write(buf[0:n])
}

func (con *Connection) waitForN(n int) {
	for con.inBuffer.Len() < n {
		con.read()
	}
}

func (con *Connection) parseStartupMessage() (version, headerSize int32) {
	con.waitForN(8)

	binary.Read(con.inBuffer, binary.BigEndian, &version)
	binary.Read(con.inBuffer, binary.BigEndian, &headerSize)

	return
}

func (con *Connection) parseMap() map[string][]byte {
	dict := make(map[string][]byte)

	var (
		keyLength   int16
		valueLength int32
		key         []byte
		value       []byte
	)

	for {
		con.waitForN(2)
		binary.Read(con.inBuffer, binary.BigEndian, &keyLength)
		if keyLength == 0 {
			// end of map
			break
		}

		con.waitForN(int(keyLength))
		key = make([]byte, keyLength)
		con.inBuffer.Read(key)

		con.waitForN(4)
		binary.Read(con.inBuffer, binary.BigEndian, &valueLength)
		con.waitForN(int(valueLength))
		value = make([]byte, valueLength)
		con.inBuffer.Read(value)

		dict[string(key)] = value
	}

	return dict
}

func (con *Connection) parseMessage() *Message {
	message := new(Message)
	con.waitForN(24) // authid + authlen + opcode + handle + tid + rid

	var authlen int32

	binary.Read(con.inBuffer, binary.BigEndian, &message.AuthID)
	binary.Read(con.inBuffer, binary.BigEndian, &authlen)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Opcode)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Handle)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Tid)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Rid)

	message.Message = con.parseMap()
	message.Object = con.parseMap()

	con.waitForN(int(authlen))
	message.Signature = make([]byte, authlen)
	con.inBuffer.Read(message.Signature)

	return message
}

func (con *Connection) receiveProtocolInitialization() {
	version, headerSize := con.parseStartupMessage()
	if version != 100 {
		panic("version mismatch")
	}

	if headerSize != 24 {
		panic("header size mismatch")
	}
}

type Authenticator interface {
	Sign(*Message) []byte
	AuthObject() map[string][]byte
	AuthLen() int32
	AuthID() int32
	SetAuthID(int32)
}

type NullAuthenticator struct{}

func (_ *NullAuthenticator) AuthObject() map[string][]byte {
	return make(map[string][]byte)
}

func (_ *NullAuthenticator) Sign(_ *Message) []byte {
	return []byte("")
}

func (_ *NullAuthenticator) AuthLen() int32 {
	return 0
}

func (_ *NullAuthenticator) AuthID() int32 {
	return 0
}

func (_ *NullAuthenticator) SetAuthID(_ int32) {
}

type HMACMD5Authenticator struct {
	Username string
	Key      []byte
	_AuthID  int32
}

func (auth *HMACMD5Authenticator) AuthObject() map[string][]byte {
	ret := make(map[string][]byte)
	ret["name"] = []byte(auth.Username)
	ret["algorithm"] = []byte("hmac-md5.SIG-ALG.REG.INT.")

	return ret
}

func (auth *HMACMD5Authenticator) Sign(m *Message) []byte {
	hmac := hmac.New(md5.New, auth.Key)

	// The signature's length is part of the message that we are
	// signing, so initialize the signature with the correct length.
	m.Signature = bytes.Repeat([]byte("\x00"), int(auth.AuthLen()))
	hmac.Write(m.Bytes(true))

	return hmac.Sum(nil)
}

func (_ *HMACMD5Authenticator) AuthLen() int32 {
	return 16
}

func (auth *HMACMD5Authenticator) AuthID() int32 {
	return auth._AuthID
}

func (auth *HMACMD5Authenticator) SetAuthID(val int32) {
	auth._AuthID = val
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	key := os.Getenv("OMAPI_KEY")
	connection := NewConnection("192.168.1.1", 7911, "omapi_key", key)

	// message := NewOpenMessage("lease")
	// mac, _ := net.ParseMAC("bc:ae:c5:76:1d:5a")
	// message.Object["hardware-address"] = []byte(mac)
	// response := connection.queryServer(message)
	// fmt.Println(response)

	// message := NewOpenMessage("host")
	// // message.Message["create"] = Ethernet
	// mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	// message.Object["hardware-address"] = []byte(mac)

	// // buf := new(bytes.Buffer)
	// // binary.Write(buf, binary.BigEndian, int32(1))

	// message.Object["hardware-type"] = Ethernet

	// response := connection.queryServer(message)
	// fmt.Println(response)
	// response = connection.queryServer(NewDeleteMessage(response.Handle))
	// fmt.Println(response)

	mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	ip := net.ParseIP("192.168.1.33")
	message := NewCreateMessage("host")

	message.Object["hardware-address"] = []byte(mac)
	message.Object["hardware-type"] = Ethernet
	message.Object["ip-address"] = []byte(ip[12:])
	message.Object["statements"] = []byte("ddns-hostname=\"win7.vm\";")
	message.Object["name"] = []byte("win7.vm")

	response := connection.queryServer(message)
	if response.Opcode != OpUpdate {
		fmt.Println("add failed:", string(response.Message["message"]))
	}
	// fmt.Println(response)
}
<commit_msg>rename queryServer to Query<commit_after>package main // FIXME omapi

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"os"
	"sort"
	"time"
)

type Opcode int32
type State int32

const (
	OpOpen Opcode = 1 + iota
	OpRefresh
	OpUpdate
	OpNotify
	OpStatus
	OpDelete
)

const (
	StateFree = 1 + iota
	StateActive
	StateExpired
	StateReleased
	StateAbandoned
	StateReset
	StateBackup
	StateReserved
	StateBootp
)

var Ethernet = []byte{0, 0, 0, 1}
var TokenRing = []byte{0, 0, 0, 6}
var FDDI = []byte{0, 0, 0, 8}

var True = []byte{0, 0, 0, 1}

func (opcode Opcode) String() (ret string) {
	switch opcode {
	case 1:
		ret = "open"
	case 2:
		ret = "refresh"
	case 3:
		ret = "update"
	case 4:
		ret = "notify"
	case 5:
		ret = "status"
	case 6:
		ret = "delete"
	}

	return
}

func (state State) String() (ret string) {
	switch state {
	case 1:
		ret = "free"
	case 2:
		ret = "active"
	case 3:
		ret = "expired"
	case 4:
		ret = "released"
	case 5:
		ret = "abandoned"
	case 6:
		ret = "reset"
	case 7:
		ret = "backup"
	case 8:
		ret = "reserved"
	case 9:
		ret = "bootp"
	}

	return
}

// TODO add size checks for all operations
type buffer struct {
	buffer *bytes.Buffer
}

func newBuffer() *buffer {
	return &buffer{new(bytes.Buffer)}
}

func (b *buffer) add_bytes(data []byte) {
	b.buffer.Write(data)
}

func (b *buffer) add(data interface{}) {
	err := binary.Write(b.buffer, binary.BigEndian, data)
	if err != nil {
		panic(err)
	}
}

func (b *buffer) add_map(data map[string][]byte) {
	// We need to add the map in a deterministic order for signing to
	// work, so we first sort the keys in alphabetical order, then use
	// that order to access the map entries.

	keys := make(sort.StringSlice, 0, len(data))

	for key := range data {
		keys = append(keys, key)
	}

	sort.Sort(keys)

	for _, key := range keys {
		value := data[key]

		b.add(int16(len(key)))
		b.add([]byte(key))

		b.add(int32(len(value)))
		b.add(value)
	}

	b.add([]byte("\x00\x00"))
}

func (b *buffer) bytes() []byte {
	return b.buffer.Bytes()
}

type Message struct {
	AuthID    int32
	Opcode    Opcode
	Handle    int32
	Tid       int32
	Rid       int32
	Message   map[string][]byte
	Object    map[string][]byte
	Signature []byte
}

func NewMessage() *Message {
	msg := &Message{
		Tid:     rand.Int31(),
		Message: make(map[string][]byte),
		Object:  make(map[string][]byte),
	}

	return msg
}

func NewOpenMessage(typeName string) *Message {
	message := NewMessage()
	message.Opcode = OpOpen
	message.Message["type"] = []byte(typeName)

	return message
}

func NewCreateMessage(typeName string) *Message {
	message := NewOpenMessage(typeName)
	message.Message["create"] = True
	// TODO Where is "exclusive" coming from? Is that always required
	// for creates, or only for hosts?
	message.Message["exclusive"] = True

	return message
}

func NewDeleteMessage(handle int32) *Message {
	message := NewMessage()
	message.Opcode = OpDelete
	message.Handle = handle

	return message
}

func (m *Message) Bytes(forSigning bool) []byte {
	ret := newBuffer()
	if !forSigning {
		ret.add(m.AuthID)
	}

	ret.add(int32(len(m.Signature)))
	ret.add(m.Opcode)
	ret.add(m.Handle)
	ret.add(m.Tid)
	ret.add(m.Rid)
	ret.add_map(m.Message)
	ret.add_map(m.Object)
	if !forSigning {
		ret.add(m.Signature)
	}

	return ret.buffer.Bytes()
}

func (m *Message) Sign(auth Authenticator) {
	m.AuthID = auth.AuthID()
	m.Signature = auth.Sign(m)
}

func (m *Message) Verify(auth Authenticator) bool {
	return bytes.Equal(auth.Sign(m), m.Signature)
}

func (m *Message) IsResponseTo(other *Message) bool {
	return m.Rid == other.Tid
}

type Connection struct {
	Hostname      string
	Port          int
	Username      string
	Key           string
	Authenticator Authenticator
	connection    *net.TCPConn
	inBuffer      *bytes.Buffer
}

func NewConnection(hostname string, port int, username string, key string) *Connection {
	con := &Connection{
		Hostname:      hostname,
		Port:          port,
		Username:      username,
		Key:           key,
		Authenticator: new(NullAuthenticator),
		inBuffer:      new(bytes.Buffer),
	}

	var newAuth Authenticator = new(NullAuthenticator)

	if len(username) > 0 && len(key) > 0 {
		decodedKey, err := base64.StdEncoding.DecodeString(key)
		if err != nil {
			panic(err)
		}
		newAuth = &HMACMD5Authenticator{username, decodedKey, -1}
	}

	raddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", hostname, port))
	if err != nil {
		// TODO return the error instead
		panic(err)
	}
	tcpConn, err := net.DialTCP("tcp", nil, raddr)
	if err != nil {
		// TODO return the error instead
		panic(err)
	}

	con.connection = tcpConn

	con.sendProtocolInitialization()
	con.receiveProtocolInitialization()
	con.initializeAuthenticator(newAuth)

	return con
}

func (con *Connection) initializeAuthenticator(auth Authenticator) {
	if _, ok := auth.(*NullAuthenticator); ok {
		return
	}

	message := NewOpenMessage("authenticator")
	for key, value := range auth.AuthObject() {
		message.Object[key] = value
	}

	response := con.Query(message)

	if response.Opcode != OpUpdate {
		panic("received non-update response for open")
	}

	if response.Handle == 0 {
		panic("received invalid authid from server")
	}

	auth.SetAuthID(response.Handle)
	con.Authenticator = auth
}

func (con *Connection) Query(msg *Message) *Message {
	msg.Sign(con.Authenticator)
	con.send(msg.Bytes(false))
	response := con.parseMessage()
	if !response.IsResponseTo(msg) {
		panic("received message is not the desired response")
	}

	// TODO check authid

	return response
}

func (con *Connection) send(data []byte) (n int, err error) {
	return con.connection.Write(data)
}

func (con *Connection) sendProtocolInitialization() {
	buf := newBuffer()
	buf.add(int32(100)) // Protocol version
	buf.add(int32(24))  // Header size
	con.send(buf.bytes())
}

func (con *Connection) read() {
	buf := make([]byte, 2048)
	n, err := con.connection.Read(buf)
	if err != nil {
		panic(err)
	}

	con.inBuffer.Write(buf[0:n])
}

func (con *Connection) waitForN(n int) {
	for con.inBuffer.Len() < n {
		con.read()
	}
}

func (con *Connection) parseStartupMessage() (version, headerSize int32) {
	con.waitForN(8)

	binary.Read(con.inBuffer, binary.BigEndian, &version)
	binary.Read(con.inBuffer, binary.BigEndian, &headerSize)

	return
}

func (con *Connection) parseMap() map[string][]byte {
	dict := make(map[string][]byte)

	var (
		keyLength   int16
		valueLength int32
		key         []byte
		value       []byte
	)

	for {
		con.waitForN(2)
		binary.Read(con.inBuffer, binary.BigEndian, &keyLength)
		if keyLength == 0 {
			// end of map
			break
		}

		con.waitForN(int(keyLength))
		key = make([]byte, keyLength)
		con.inBuffer.Read(key)

		con.waitForN(4)
		binary.Read(con.inBuffer, binary.BigEndian, &valueLength)
		con.waitForN(int(valueLength))
		value = make([]byte, valueLength)
		con.inBuffer.Read(value)

		dict[string(key)] = value
	}

	return dict
}

func (con *Connection) parseMessage() *Message {
	message := new(Message)
	con.waitForN(24) // authid + authlen + opcode + handle + tid + rid

	var authlen int32

	binary.Read(con.inBuffer, binary.BigEndian, &message.AuthID)
	binary.Read(con.inBuffer, binary.BigEndian, &authlen)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Opcode)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Handle)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Tid)
	binary.Read(con.inBuffer, binary.BigEndian, &message.Rid)

	message.Message = con.parseMap()
	message.Object = con.parseMap()

	con.waitForN(int(authlen))
	message.Signature = make([]byte, authlen)
	con.inBuffer.Read(message.Signature)

	return message
}

func (con *Connection) receiveProtocolInitialization() {
	version, headerSize := con.parseStartupMessage()
	if version != 100 {
		panic("version mismatch")
	}

	if headerSize != 24 {
		panic("header size mismatch")
	}
}

type Authenticator interface {
	Sign(*Message) []byte
	AuthObject() map[string][]byte
	AuthLen() int32
	AuthID() int32
	SetAuthID(int32)
}

type NullAuthenticator struct{}

func (_ *NullAuthenticator) AuthObject() map[string][]byte {
	return make(map[string][]byte)
}

func (_ *NullAuthenticator) Sign(_ *Message) []byte {
	return []byte("")
}

func (_ *NullAuthenticator) AuthLen() int32 {
	return 0
}

func (_ *NullAuthenticator) AuthID() int32 {
	return 0
}

func (_ *NullAuthenticator) SetAuthID(_ int32) {
}

type HMACMD5Authenticator struct {
	Username string
	Key      []byte
	_AuthID  int32
}

func (auth *HMACMD5Authenticator) AuthObject() map[string][]byte {
	ret := make(map[string][]byte)
	ret["name"] = []byte(auth.Username)
	ret["algorithm"] = []byte("hmac-md5.SIG-ALG.REG.INT.")

	return ret
}

func (auth *HMACMD5Authenticator) Sign(m *Message) []byte {
	hmac := hmac.New(md5.New, auth.Key)

	// The signature's length is part of the message that we are
	// signing, so initialize the signature with the correct length.
	m.Signature = bytes.Repeat([]byte("\x00"), int(auth.AuthLen()))
	hmac.Write(m.Bytes(true))

	return hmac.Sum(nil)
}

func (_ *HMACMD5Authenticator) AuthLen() int32 {
	return 16
}

func (auth *HMACMD5Authenticator) AuthID() int32 {
	return auth._AuthID
}

func (auth *HMACMD5Authenticator) SetAuthID(val int32) {
	auth._AuthID = val
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	key := os.Getenv("OMAPI_KEY")
	connection := NewConnection("192.168.1.1", 7911, "omapi_key", key)

	// message := NewOpenMessage("lease")
	// mac, _ := net.ParseMAC("bc:ae:c5:76:1d:5a")
	// message.Object["hardware-address"] = []byte(mac)
	// response := connection.queryServer(message)
	// fmt.Println(response)

	// message := NewOpenMessage("host")
	// // message.Message["create"] = Ethernet
	// mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	// message.Object["hardware-address"] = []byte(mac)

	// // buf := new(bytes.Buffer)
	// // binary.Write(buf, binary.BigEndian, int32(1))

	// message.Object["hardware-type"] = Ethernet

	// response := connection.queryServer(message)
	// fmt.Println(response)
	// response = connection.queryServer(NewDeleteMessage(response.Handle))
	// fmt.Println(response)

	mac, _ := net.ParseMAC("08:00:27:4f:72:21")
	ip := net.ParseIP("192.168.1.33")
	message := NewCreateMessage("host")

	message.Object["hardware-address"] = []byte(mac)
	message.Object["hardware-type"] = Ethernet
	message.Object["ip-address"] = []byte(ip[12:])
	message.Object["statements"] = []byte("ddns-hostname=\"win7.vm\";")
	message.Object["name"] = []byte("win7.vm")

	response := connection.queryServer(message)
	if response.Opcode != OpUpdate {
		fmt.Println("add failed:", string(response.Message["message"]))
	}
	// fmt.Println(response)
}
<|endoftext|>


<commit_before>package coinbase

import (
	"fmt"
)

type Order struct {
	Type      string  `json:"type"`
	Size      float64 `json:"size,string"`
	Side      string  `json:"side"`
	ProductId string  `json:"product_id"`
	ClientOID string  `json:"client_oid,omitempty"`
	Stp       string  `json:"stp,omitempty"`
	// Limit Order
	Price       float64 `json:"price,string,omitempty"`
	TimeInForce string  `json:"time_in_force,omitempty"`
	PostOnly    bool    `json:"post_only,omitempty"`
	// Market Order
	Funds float64 `json:"funds,string,omitempty"`
	// Response Fields
	Id         string `json:"id"`
	Status     string `json:"status,omitempty"`
	Settled    bool   `json:"settled,omitempty"`
	DoneReason string `json:"done_reason,omitempty"`
	CreatedAt  Time   `json:"created_at,string,omitempty"`
}

type ListOrdersParams struct {
	Status     string
	Pagination PaginationParams
}

func (c *Client) CreateOrder(newOrder *Order) (Order, error) {
	var savedOrder Order

	if len(newOrder.Type) == 0 {
		newOrder.Type = "limit"
	}

	url := fmt.Sprintf("/orders")
	_, err := c.Request("POST", url, newOrder, &savedOrder)
	return savedOrder, err
}

func (c *Client) CancelOrder(id string) error {
	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("DELETE", url, nil, nil)
	return err
}

func (c *Client) GetOrder(id string) (Order, error) {
	var savedOrder Order

	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("GET", url, nil, &savedOrder)
	return savedOrder, err
}

func (c *Client) ListOrders(p ...ListOrdersParams) *Cursor {
	paginationParams := PaginationParams{}
	if len(p) > 0 {
		paginationParams = p[0].Pagination
		if p[0].Status != "" {
			paginationParams.AddExtraParam("status", p[0].Status)
		}
	}

	return NewCursor(c, "GET", fmt.Sprintf("/orders"),
		&paginationParams)
}
<commit_msg>Add cancel_after to Order<commit_after>package coinbase

import (
	"fmt"
)

type Order struct {
	Type      string  `json:"type"`
	Size      float64 `json:"size,string"`
	Side      string  `json:"side"`
	ProductId string  `json:"product_id"`
	ClientOID string  `json:"client_oid,omitempty"`
	Stp       string  `json:"stp,omitempty"`
	// Limit Order
	Price       float64 `json:"price,string,omitempty"`
	TimeInForce string  `json:"time_in_force,omitempty"`
	PostOnly    bool    `json:"post_only,omitempty"`
	CancelAfter string  `json:"cancel_after,omitempty"`
	// Market Order
	Funds float64 `json:"funds,string,omitempty"`
	// Response Fields
	Id         string `json:"id"`
	Status     string `json:"status,omitempty"`
	Settled    bool   `json:"settled,omitempty"`
	DoneReason string `json:"done_reason,omitempty"`
	CreatedAt  Time   `json:"created_at,string,omitempty"`
}

type ListOrdersParams struct {
	Status     string
	Pagination PaginationParams
}

func (c *Client) CreateOrder(newOrder *Order) (Order, error) {
	var savedOrder Order

	if len(newOrder.Type) == 0 {
		newOrder.Type = "limit"
	}

	url := fmt.Sprintf("/orders")
	_, err := c.Request("POST", url, newOrder, &savedOrder)
	return savedOrder, err
}

func (c *Client) CancelOrder(id string) error {
	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("DELETE", url, nil, nil)
	return err
}

func (c *Client) GetOrder(id string) (Order, error) {
	var savedOrder Order

	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("GET", url, nil, &savedOrder)
	return savedOrder, err
}

func (c *Client) ListOrders(p ...ListOrdersParams) *Cursor {
	paginationParams := PaginationParams{}
	if len(p) > 0 {
		paginationParams = p[0].Pagination
		if p[0].Status != "" {
			paginationParams.AddExtraParam("status", p[0].Status)
		}
	}

	return NewCursor(c, "GET", fmt.Sprintf("/orders"),
		&paginationParams)
}
<|endoftext|>


<commit_before>package aspect

// Both ColumnElem and OrderedColumns will implement the Orderable interface
type Orderable interface {
	Orderable() OrderedColumn
}

// OrderedColumn represents a ColumnElem that will be used in an ORDER BY
// clause within SELECT statements. It provides additional sorting
// features, such as ASC, DESC, NULLS FIRST, and NULLS LAST.
// If not specified, ASC is assumed by default.
// In Postgres: the default behavior is NULLS LAST when ASC is specified or
// implied, and NULLS FIRST when DESC is specified
// http://www.postgresql.org/docs/9.2/static/sql-select.html#SQL-ORDERBY
type OrderedColumn struct {
	inner                       ColumnElem
	desc, nullsFirst, nullsLast bool
}

// OrderedColumn should implement the Orderable interface
var _ Orderable = OrderedColumn{}

func (o OrderedColumn) String() string {
	compiled, _ := o.Compile(&defaultDialect{}, Params())
	return compiled
}

func (o OrderedColumn) Compile(d Dialect, params *Parameters) (string, error) {
	// Call the compilation method of the embeded column
	compiled, err := o.inner.Compile(d, params)
	if err != nil {
		return "", err
	}

	if o.desc {
		compiled += " DESC"
	}
	if o.nullsFirst || o.nullsLast {
		if o.nullsFirst {
			compiled += " NULLS FIRST"
		} else {
			compiled += " NULLS LAST"
		}
	}
	return compiled, nil
}

func (o OrderedColumn) Orderable() OrderedColumn {
	return o
}

func (o OrderedColumn) Asc() OrderedColumn {
	o.desc = false
	return o
}

func (o OrderedColumn) Desc() OrderedColumn {
	o.desc = true
	return o
}

func (o OrderedColumn) NullsFirst() OrderedColumn {
	o.nullsFirst = true
	o.nullsLast = false
	return o
}

func (o OrderedColumn) NullsLast() OrderedColumn {
	o.nullsFirst = false
	o.nullsLast = true
	return o
}
<commit_msg>Added a Column method to OrderedColumn, which returns the inner ColumnElem<commit_after>package aspect

// Both ColumnElem and OrderedColumns will implement the Orderable interface
type Orderable interface {
	Orderable() OrderedColumn
}

// OrderedColumn represents a ColumnElem that will be used in an ORDER BY
// clause within SELECT statements. It provides additional sorting
// features, such as ASC, DESC, NULLS FIRST, and NULLS LAST.
// If not specified, ASC is assumed by default.
// In Postgres: the default behavior is NULLS LAST when ASC is specified or
// implied, and NULLS FIRST when DESC is specified
// http://www.postgresql.org/docs/9.2/static/sql-select.html#SQL-ORDERBY
type OrderedColumn struct {
	inner                       ColumnElem
	desc, nullsFirst, nullsLast bool
}

// OrderedColumn should implement the Orderable interface
var _ Orderable = OrderedColumn{}

func (o OrderedColumn) String() string {
	compiled, _ := o.Compile(&defaultDialect{}, Params())
	return compiled
}

// Column returns the OrderedColumn's inner ColumnElem
func (o OrderedColumn) Column() ColumnElem {
	return o.inner
}

func (o OrderedColumn) Compile(d Dialect, params *Parameters) (string, error) {
	// Call the compilation method of the embeded column
	compiled, err := o.inner.Compile(d, params)
	if err != nil {
		return "", err
	}

	if o.desc {
		compiled += " DESC"
	}
	if o.nullsFirst || o.nullsLast {
		if o.nullsFirst {
			compiled += " NULLS FIRST"
		} else {
			compiled += " NULLS LAST"
		}
	}
	return compiled, nil
}

func (o OrderedColumn) Orderable() OrderedColumn {
	return o
}

func (o OrderedColumn) Asc() OrderedColumn {
	o.desc = false
	return o
}

func (o OrderedColumn) Desc() OrderedColumn {
	o.desc = true
	return o
}

func (o OrderedColumn) NullsFirst() OrderedColumn {
	o.nullsFirst = true
	o.nullsLast = false
	return o
}

func (o OrderedColumn) NullsLast() OrderedColumn {
	o.nullsFirst = false
	o.nullsLast = true
	return o
}
<|endoftext|>


<commit_before>package coinbase

import (
	"fmt"
)

type Order struct {
	Type      string  `json:"type"`
	Size      float64 `json:"size,string"`
	Side      string  `json:"side"`
	ProductId string  `json:"product_id"`
	ClientOID string  `json:"client_oid,omitempty"`
	Stp       string  `json:"stp,omitempty"`
	// Limit Order
	Price       float64 `json:"price,string,omitempty"`
	TimeInForce string  `json:"time_in_force,omitempty"`
	PostOnly    bool    `json:"post_only,omitempty"`
	CancelAfter string  `json:"cancel_after,omitempty"`
	// Market Order
	Funds float64 `json:"funds,string,omitempty"`
	// Response Fields
	Id         string `json:"id"`
	Status     string `json:"status,omitempty"`
	Settled    bool   `json:"settled,omitempty"`
	DoneReason string `json:"done_reason,omitempty"`
	CreatedAt  Time   `json:"created_at,string,omitempty"`
}

type ListOrdersParams struct {
	Status     string
	Pagination PaginationParams
}

func (c *Client) CreateOrder(newOrder *Order) (Order, error) {
	var savedOrder Order

	if len(newOrder.Type) == 0 {
		newOrder.Type = "limit"
	}

	url := fmt.Sprintf("/orders")
	_, err := c.Request("POST", url, newOrder, &savedOrder)
	return savedOrder, err
}

func (c *Client) CancelOrder(id string) error {
	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("DELETE", url, nil, nil)
	return err
}

func (c *Client) GetOrder(id string) (Order, error) {
	var savedOrder Order

	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("GET", url, nil, &savedOrder)
	return savedOrder, err
}

func (c *Client) ListOrders(p ...ListOrdersParams) *Cursor {
	paginationParams := PaginationParams{}
	if len(p) > 0 {
		paginationParams = p[0].Pagination
		if p[0].Status != "" {
			paginationParams.AddExtraParam("status", p[0].Status)
		}
	}

	return NewCursor(c, "GET", fmt.Sprintf("/orders"),
		&paginationParams)
}
<commit_msg>Add missing fields<commit_after>package coinbase

import (
	"fmt"
)

type Order struct {
	Type      string  `json:"type"`
	Size      float64 `json:"size,string,omitempty"`
	Side      string  `json:"side"`
	ProductId string  `json:"product_id"`
	ClientOID string  `json:"client_oid,omitempty"`
	Stp       string  `json:"stp,omitempty"`
	// Limit Order
	Price       float64 `json:"price,string,omitempty"`
	TimeInForce string  `json:"time_in_force,omitempty"`
	PostOnly    bool    `json:"post_only,omitempty"`
	CancelAfter string  `json:"cancel_after,omitempty"`
	// Market Order
	Funds float64 `json:"funds,string,omitempty"`
	// Response Fields
	Id            string  `json:"id"`
	Status        string  `json:"status,omitempty"`
	Settled       bool    `json:"settled,omitempty"`
	DoneReason    string  `json:"done_reason,omitempty"`
	CreatedAt     Time    `json:"created_at,string,omitempty"`
	FillFees      float64 `json:"fill_fees,string,omitempty"`
	FilledSize    float64 `json:"filled_size,string,omitempty"`
	ExecutedValue float64 `json:"executed_value,string,omitempty"`
}

type ListOrdersParams struct {
	Status     string
	Pagination PaginationParams
}

func (c *Client) CreateOrder(newOrder *Order) (Order, error) {
	var savedOrder Order

	if len(newOrder.Type) == 0 {
		newOrder.Type = "limit"
	}

	url := fmt.Sprintf("/orders")
	_, err := c.Request("POST", url, newOrder, &savedOrder)
	return savedOrder, err
}

func (c *Client) CancelOrder(id string) error {
	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("DELETE", url, nil, nil)
	return err
}

func (c *Client) GetOrder(id string) (Order, error) {
	var savedOrder Order

	url := fmt.Sprintf("/orders/%s", id)
	_, err := c.Request("GET", url, nil, &savedOrder)
	return savedOrder, err
}

func (c *Client) ListOrders(p ...ListOrdersParams) *Cursor {
	paginationParams := PaginationParams{}
	if len(p) > 0 {
		paginationParams = p[0].Pagination
		if p[0].Status != "" {
			paginationParams.AddExtraParam("status", p[0].Status)
		}
	}

	return NewCursor(c, "GET", fmt.Sprintf("/orders"),
		&paginationParams)
}
<|endoftext|>


<commit_before>package os

import (
	reg "github.com/hiromaily/golibs/regexp"
	"os"
)

// GetArgs is to get args
func GetArgs(i int) string {
	return os.Args[i]
}

// AddParam is to add value as arguments
func AddParam(val string) {
	os.Args = append(os.Args, val)
}

// FindParam is to find specific args
func FindParam(key string) (bRet bool) {
	//fmt.Println(os.Args)
	bRet = false
	for _, v := range os.Args {
		if reg.CheckRegexp(`^`+key, v) {
			bRet = true
			break
		}
	}
	return
}
<commit_msg>added IsFileExisted func<commit_after>package os

import (
	"os"

	reg "github.com/hiromaily/golibs/regexp"
)

// GetArgs is to get args
func GetArgs(i int) string {
	return os.Args[i]
}

// AddParam is to add value as arguments
func AddParam(val string) {
	os.Args = append(os.Args, val)
}

// FindParam is to find specific args
func FindParam(key string) (bRet bool) {
	//fmt.Println(os.Args)
	bRet = false
	for _, v := range os.Args {
		if reg.CheckRegexp(`^`+key, v) {
			bRet = true
			break
		}
	}
	return
}

// IsFileExisted check if file exists
func IsFileExisted(filePath string) bool {
	_, err := os.Stat(filePath)
	if err == os.ErrNotExist {
		return false
	} else if err != nil {
		// error may be better to return
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs_test

import (
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"
	"strconv"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples/memfs"
	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

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

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

func currentUid() uint32 {
	user, err := user.Current()
	if err != nil {
		panic(err)
	}

	uid, err := strconv.ParseUint(user.Uid, 10, 32)
	if err != nil {
		panic(err)
	}

	return uint32(uid)
}

func currentGid() uint32 {
	user, err := user.Current()
	if err != nil {
		panic(err)
	}

	gid, err := strconv.ParseUint(user.Gid, 10, 32)
	if err != nil {
		panic(err)
	}

	return uint32(gid)
}

func timespecToTime(ts syscall.Timespec) time.Time {
	return time.Unix(ts.Sec, ts.Nsec)
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type MemFSTest struct {
	clock timeutil.SimulatedClock
	mfs   *fuse.MountedFileSystem
}

var _ SetUpInterface = &MemFSTest{}
var _ TearDownInterface = &MemFSTest{}

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

func (t *MemFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Now())

	// Set up a temporary directory for mounting.
	mountPoint, err := ioutil.TempDir("", "memfs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Mount a file system.
	fs := memfs.NewMemFS(&t.clock)
	if t.mfs, err = fuse.Mount(mountPoint, fs); err != nil {
		panic("Mount: " + err.Error())
	}

	if err = t.mfs.WaitForReady(context.Background()); err != nil {
		panic("MountedFileSystem.WaitForReady: " + err.Error())
	}
}

func (t *MemFSTest) TearDown() {
	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := t.mfs.Unmount()
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(context.Background()); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *MemFSTest) ContentsOfEmptyFileSystem() {
	entries, err := ioutil.ReadDir(t.mfs.Dir())

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_OneLevel() {
	var err error
	var fi os.FileInfo
	var stat *syscall.Stat_t

	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create a directory within the root.
	createTime := t.clock.Now()
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Simulate time proceeding.
	t.clock.AdvanceTime(time.Second)

	// Stat the directory.
	fi, err = os.Stat(dirName)
	stat = fi.Sys().(*syscall.Stat_t)

	AssertEq(nil, err)
	ExpectEq("dir", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(os.ModeDir|0754, fi.Mode())
	ExpectEq(0, fi.ModTime().Sub(createTime))
	ExpectTrue(fi.IsDir())

	ExpectEq(1, stat.Nlink)
	ExpectEq(currentUid(), stat.Uid)
	ExpectEq(currentGid(), stat.Gid)
	ExpectEq(0, stat.Size)
	ExpectEq(createTime, timespecToTime(stat.Atimespec))
	ExpectEq(createTime, timespecToTime(stat.Mtimespec))
	ExpectEq(createTime, timespecToTime(stat.Ctimespec))

	// Read the directory.
	entries, err := ioutil.ReadDir(dirName)

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_TwoLevels() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Mkdir_AlreadyExists() {
	var err error
	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create the directory once.
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Attempt to create it again.
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("exists")))
}

func (t *MemFSTest) Mkdir_IntermediateIsFile() {
	var err error

	// Create a file.
	fileName := path.Join(t.mfs.Dir(), "foo")
	err = ioutil.WriteFile(fileName, []byte{}, 0700)
	AssertEq(nil, err)

	// Attempt to create a directory within the file.
	dirName := path.Join(fileName, "dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *MemFSTest) Mkdir_IntermediateIsNonExistent() {
	var err error

	// Attempt to create a sub-directory of a non-existent sub-directory.
	dirName := path.Join(t.mfs.Dir(), "foo/dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("no such file or directory")))
}

func (t *MemFSTest) CreateNewFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) CreateNewFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NotAFile() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonEmpty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_Empty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NotADirectory() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonExistent() {
	AssertTrue(false, "TODO")
}
<commit_msg>Fixed some test bugs.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs_test

import (
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"
	"strconv"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/samples/memfs"
	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

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

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

func currentUid() uint32 {
	user, err := user.Current()
	if err != nil {
		panic(err)
	}

	uid, err := strconv.ParseUint(user.Uid, 10, 32)
	if err != nil {
		panic(err)
	}

	return uint32(uid)
}

func currentGid() uint32 {
	user, err := user.Current()
	if err != nil {
		panic(err)
	}

	gid, err := strconv.ParseUint(user.Gid, 10, 32)
	if err != nil {
		panic(err)
	}

	return uint32(gid)
}

func timespecToTime(ts syscall.Timespec) time.Time {
	return time.Unix(ts.Sec, ts.Nsec)
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type MemFSTest struct {
	clock timeutil.SimulatedClock
	mfs   *fuse.MountedFileSystem
}

var _ SetUpInterface = &MemFSTest{}
var _ TearDownInterface = &MemFSTest{}

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

func (t *MemFSTest) SetUp(ti *TestInfo) {
	var err error

	// Set up a fixed, non-zero time.
	t.clock.SetTime(time.Now())

	// Set up a temporary directory for mounting.
	mountPoint, err := ioutil.TempDir("", "memfs_test")
	if err != nil {
		panic("ioutil.TempDir: " + err.Error())
	}

	// Mount a file system.
	fs := memfs.NewMemFS(&t.clock)
	if t.mfs, err = fuse.Mount(mountPoint, fs); err != nil {
		panic("Mount: " + err.Error())
	}

	if err = t.mfs.WaitForReady(context.Background()); err != nil {
		panic("MountedFileSystem.WaitForReady: " + err.Error())
	}
}

func (t *MemFSTest) TearDown() {
	// Unmount the file system. Try again on "resource busy" errors.
	delay := 10 * time.Millisecond
	for {
		err := t.mfs.Unmount()
		if err == nil {
			break
		}

		if strings.Contains(err.Error(), "resource busy") {
			log.Println("Resource busy error while unmounting; trying again")
			time.Sleep(delay)
			delay = time.Duration(1.3 * float64(delay))
			continue
		}

		panic("MountedFileSystem.Unmount: " + err.Error())
	}

	if err := t.mfs.Join(context.Background()); err != nil {
		panic("MountedFileSystem.Join: " + err.Error())
	}
}

////////////////////////////////////////////////////////////////////////
// Test functions
////////////////////////////////////////////////////////////////////////

func (t *MemFSTest) ContentsOfEmptyFileSystem() {
	entries, err := ioutil.ReadDir(t.mfs.Dir())

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_OneLevel() {
	var err error
	var fi os.FileInfo
	var stat *syscall.Stat_t

	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create a directory within the root.
	createTime := t.clock.Now()
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Simulate time proceeding.
	t.clock.AdvanceTime(time.Second)

	// Stat the directory.
	fi, err = os.Stat(dirName)
	stat = fi.Sys().(*syscall.Stat_t)

	AssertEq(nil, err)
	ExpectEq("dir", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(os.ModeDir|0754, fi.Mode())
	ExpectEq(0, fi.ModTime().Sub(createTime))
	ExpectTrue(fi.IsDir())

	ExpectEq(1, stat.Nlink)
	ExpectEq(currentUid(), stat.Uid)
	ExpectEq(currentGid(), stat.Gid)
	ExpectEq(0, stat.Size)
	ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime))
	ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime))
	ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime))

	// Read the directory.
	entries, err := ioutil.ReadDir(dirName)

	AssertEq(nil, err)
	ExpectThat(entries, ElementsAre())
}

func (t *MemFSTest) Mkdir_TwoLevels() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Mkdir_AlreadyExists() {
	var err error
	dirName := path.Join(t.mfs.Dir(), "dir")

	// Create the directory once.
	err = os.Mkdir(dirName, 0754)
	AssertEq(nil, err)

	// Attempt to create it again.
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("exists")))
}

func (t *MemFSTest) Mkdir_IntermediateIsFile() {
	var err error

	// Create a file.
	fileName := path.Join(t.mfs.Dir(), "foo")
	err = ioutil.WriteFile(fileName, []byte{}, 0700)
	AssertEq(nil, err)

	// Attempt to create a directory within the file.
	dirName := path.Join(fileName, "dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("TODO")))
}

func (t *MemFSTest) Mkdir_IntermediateIsNonExistent() {
	var err error

	// Attempt to create a sub-directory of a non-existent sub-directory.
	dirName := path.Join(t.mfs.Dir(), "foo/dir")
	err = os.Mkdir(dirName, 0754)

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("no such file or directory")))
}

func (t *MemFSTest) CreateNewFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) CreateNewFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InRoot() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) ModifyExistingFile_InSubDir() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_Exists() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NotAFile() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) UnlinkFile_NonExistent() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonEmpty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_Empty() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NotADirectory() {
	AssertTrue(false, "TODO")
}

func (t *MemFSTest) Rmdir_NonExistent() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before><commit_msg>Add systemd type of volumes to workaround fuse forking<commit_after><|endoftext|>


<commit_before><commit_msg>gob -> msgpack<commit_after><|endoftext|>


<commit_before>package gin

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"time"
)

type Runner interface {
	Run() (*exec.Cmd, error)
	Info() (os.FileInfo, error)
	SetWriter(io.Writer)
	Kill() error
}

type runner struct {
	bin       string
	args      []string
	writer    io.Writer
	command   *exec.Cmd
	starttime time.Time
	status    string
}

func NewRunner(bin string, args ...string) Runner {
	return &runner{
		bin:       bin,
		args:      args,
		writer:    ioutil.Discard,
		starttime: time.Now(),
		status:    "new",
	}
}

func (r *runner) Run() (*exec.Cmd, error) {
	if r.needsRefresh() {
		r.Kill()
	}

	for r.status == "starting" {
		time.Sleep(250 * time.Millisecond)
	}

	if r.command == nil || r.Exited() {
		err := r.runBin()
		return r.command, err
	} else {
		return r.command, nil
	}

}

func (r *runner) Info() (os.FileInfo, error) {
	return os.Stat(r.bin)
}

func (r *runner) SetWriter(writer io.Writer) {
	r.writer = writer
}

func (r *runner) Kill() error {
	if r.command != nil && r.command.Process != nil {
		done := make(chan error)
		go func() {
			r.command.Wait()
			close(done)
		}()

		//Trying a "soft" kill first
		if runtime.GOOS == "windows" {
			if err := r.command.Process.Kill(); err != nil {
				return err
			}
		} else if err := r.command.Process.Signal(os.Interrupt); err != nil {
			return err
		}

		//Wait for our process to die before we return or hard kill after 3 sec
		select {
		case <-time.After(3 * time.Second):
			if err := r.command.Process.Kill(); err != nil {
				log.Println("failed to kill: ", err)
			}
		case <-done:
		}
		r.command = nil
	}

	return nil
}

func (r *runner) Exited() bool {
	return r.command != nil && r.command.ProcessState != nil && r.command.ProcessState.Exited()
}

func (r *runner) runBin() error {
	r.status = "starting"
	r.command = exec.Command(r.bin, r.args...)
	stdout, err := r.command.StdoutPipe()
	if err != nil {
		r.status = "error"
		return err
	}
	stderr, err := r.command.StderrPipe()
	if err != nil {
		r.status = "error"
		return err
	}

	err = r.command.Start()
	if err != nil {
		r.status = "error"
		return err
	}

	r.starttime = time.Now()

	go io.Copy(r.writer, stdout)
	go io.Copy(r.writer, stderr)
	log.Printf("%+v", r)
	go r.command.Wait()

	time.Sleep(1000 * time.Millisecond)
	r.status = "up"

	return nil
}

func (r *runner) needsRefresh() bool {
	info, err := r.Info()
	if err != nil {
		return false
	} else {
		return info.ModTime().After(r.starttime)
	}
}
<commit_msg>more logging<commit_after>package gin

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"time"
)

type Runner interface {
	Run() (*exec.Cmd, error)
	Info() (os.FileInfo, error)
	SetWriter(io.Writer)
	Kill() error
}

type runner struct {
	bin       string
	args      []string
	writer    io.Writer
	command   *exec.Cmd
	starttime time.Time
	status    string
}

func NewRunner(bin string, args ...string) Runner {
	return &runner{
		bin:       bin,
		args:      args,
		writer:    ioutil.Discard,
		starttime: time.Now(),
		status:    "new",
	}
}

func (r *runner) Run() (*exec.Cmd, error) {
	if r.needsRefresh() {
		r.Kill()
	}

	for r.status == "starting" {
		time.Sleep(250 * time.Millisecond)
	}

	if r.command == nil || r.Exited() {
		err := r.runBin()
		return r.command, err
	} else {
		return r.command, nil
	}

}

func (r *runner) Info() (os.FileInfo, error) {
	return os.Stat(r.bin)
}

func (r *runner) SetWriter(writer io.Writer) {
	r.writer = writer
}

func (r *runner) Kill() error {
	if r.command != nil && r.command.Process != nil {
		done := make(chan error)
		go func() {
			r.command.Wait()
			close(done)
		}()

		//Trying a "soft" kill first
		if runtime.GOOS == "windows" {
			if err := r.command.Process.Kill(); err != nil {
				return err
			}
		} else if err := r.command.Process.Signal(os.Interrupt); err != nil {
			return err
		}

		//Wait for our process to die before we return or hard kill after 3 sec
		select {
		case <-time.After(3 * time.Second):
			if err := r.command.Process.Kill(); err != nil {
				log.Println("failed to kill: ", err)
			}
		case <-done:
		}
		r.command = nil
	}

	return nil
}

func (r *runner) Exited() bool {
	return r.command != nil && r.command.ProcessState != nil && r.command.ProcessState.Exited()
}

func (r *runner) runBin() error {
	r.status = "starting"
	r.command = exec.Command(r.bin, r.args...)
	log.Printf("First: %+v", r)
	stdout, err := r.command.StdoutPipe()
	if err != nil {
		r.status = "error"
		return err
	}
	stderr, err := r.command.StderrPipe()
	if err != nil {
		r.status = "error"
		return err
	}

	err = r.command.Start()
	if err != nil {
		r.status = "error"
		return err
	}

	r.starttime = time.Now()

	go io.Copy(r.writer, stdout)
	go io.Copy(r.writer, stderr)
	log.Printf("Second: %+v", r)
	go r.command.Wait()

	time.Sleep(1000 * time.Millisecond)
	r.status = "up"

	return nil
}

func (r *runner) needsRefresh() bool {
	info, err := r.Info()
	if err != nil {
		return false
	} else {
		return info.ModTime().After(r.starttime)
	}
}
<|endoftext|>


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

package p4

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os/exec"
	"strconv"
	"strings"
)

// Conn is an interface to the Conn command line client.
type Conn struct {
	Address string
	Binary  string
}

func NewConn() *Conn {
	return &Conn{Binary: "p4", Address: "localhost:1666"}
}

type TagLine struct {
	Tag   string
	Value []byte
}

// Output runs p4 and captures stdout.
func (p *Conn) Output(args []string) ([]byte, error) {
	b := p.Binary
	if !strings.Contains(b, "/") {
		b, _ = exec.LookPath(b)
	}
	cmd := exec.Cmd{
		Path: b,
		Args: append([]string{p.Binary, "-p", p.Address}, args...),
	}
	log.Println("running", cmd.Args)
	return cmd.Output()
}

// Runs p4 with -zTAG -s and captures the result lines.
func (p *Conn) RunMarshaled(command string, args []string) (result []Result, err error) {
	out, err := p.Output(append([]string{"-G", command}, args...))
	r := bytes.NewBuffer(out)
	for {
		v, err := Decode(r)
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		asMap, ok := v.(map[interface{}]interface{})
		if !ok {
			return nil, fmt.Errorf("format err: p4 marshaled %v", v)
		}
		result = append(result, interpretResult(asMap, command))
	}

	if len(result) > 0 {
		err = nil
	}

	return result, err
}

func interpretResult(in map[interface{}]interface{}, command string) Result {
	imap := map[string]interface{}{}
	for k, v := range in {
		imap[k.(string)] = v
	}
	code := imap["code"].(string)
	if code == "error" {
		e := Error{}
		e.Severity = int(imap["severity"].(int32))
		e.Generic = int(imap["generic"].(int32))
		e.Data = imap["data"].(string)
		return &e
	}

	switch command {
	case "dirs":
		return &Dir{Dir: imap["dir"].(string)}
	case "fstat":
		r := map[string]string{}
		for k, v := range imap {
			r[k] = v.(string)
		}

		st := Stat{
			DepotFile:  r["depotFile"],
			HeadAction: r["headAction"],
			Digest:     r["digest"],
			HeadType:   r["headType"],
		}

		// Brilliant. We get the integers as decimal strings. Sigh.
		st.HeadTime, _ = strconv.ParseInt(r["headTime"], 10, 64)
		st.HeadRev, _ = strconv.ParseInt(r["headRev"], 10, 64)
		st.HeadChange, _ = strconv.ParseInt(r["headChange"], 10, 64)
		st.HeadModTime, _ = strconv.ParseInt(r["headModTime"], 10, 64)
		st.FileSize, _ = strconv.ParseInt(r["fileSize"], 10, 64)
		return &st

	case "changes":
		r := map[string]string{}
		for k, v := range imap {
			r[k] = v.(string)
		}
		c := Change{
			Desc:       r["desc"],
			User:       r["user"],
			Status:     r["status"],
			Path:       r["path"],
			Code:       r["code"],
			ChangeType: r["changeType"],
			Client:     r["client"],
		}
		cl, _ := strconv.ParseInt(r["change"], 10, 64)
		c.Change = int(cl)
		t, _ := strconv.ParseInt(r["time"], 10, 64)
		c.Time = int(t)
		return &c
	default:
		log.Panicf("unknown code %q", command)
	}
	return nil
}

func (p *Conn) Fstat(paths []string) (results []Result, err error) {
	r, err := p.RunMarshaled("fstat",
		append([]string{"-Ol"}, paths...))
	return r, err
}

func (p *Conn) Dirs(paths []string) ([]Result, error) {
	return p.RunMarshaled("dirs", paths)
}

func (p *Conn) Print(path string) (content []byte, err error) {
	out, err := p.Output([]string{"print", path})
	if err != nil {
		return nil, err
	}
	parts := bytes.SplitN(out, []byte{'\n'}, 2)
	return parts[1], nil
}

func (p *Conn) Changes(paths []string) ([]Result, error) {
	return p.RunMarshaled("changes", append([]string{"-l"}, paths...))
}

////////////////
type Result interface {
	String() string
}

type Error struct {
	Generic  int
	Severity int
	Data     string
}

func (e *Error) String() string {
	return fmt.Sprintf("error %d(%d): %s", e.Generic, e.Severity, e.Data)
}

// Stat has the data for a single file revision.
type Stat struct {
	DepotFile   string
	HeadAction  string
	HeadType    string
	HeadTime    int64
	HeadRev     int64
	HeadChange  int64
	HeadModTime int64
	FileSize    int64
	Digest      string
}

func (f *Stat) String() string {
	return fmt.Sprintf("%s#%d - change %d (%s)",
		f.DepotFile, f.HeadRev, f.HeadChange, f.HeadType)
}

type Dir struct {
	Dir string
}

func (f *Dir) String() string {
	return fmt.Sprintf("%s/", f.Dir)
}

type Change struct {
	Desc   string
	User   string
	Status string
	Change int
	Time   int

	Path       string
	Code       string
	ChangeType string
	Client     string
}

func (c *Change) String() string {
	l := len(c.Desc)
	if l > 250 {
		l = 250
	}
	return fmt.Sprintf("change %d by %s - %s", c.Change, c.User, strings.Trim(c.Desc[:l], " "))
}
<commit_msg>Fix comment.<commit_after>// Copyright 2012 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package p4

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os/exec"
	"strconv"
	"strings"
)

// Conn is an interface to the Conn command line client.
type Conn struct {
	Address string
	Binary  string
}

func NewConn() *Conn {
	return &Conn{Binary: "p4", Address: "localhost:1666"}
}

type TagLine struct {
	Tag   string
	Value []byte
}

// Output runs p4 and captures stdout.
func (p *Conn) Output(args []string) ([]byte, error) {
	b := p.Binary
	if !strings.Contains(b, "/") {
		b, _ = exec.LookPath(b)
	}
	cmd := exec.Cmd{
		Path: b,
		Args: append([]string{p.Binary, "-p", p.Address}, args...),
	}
	log.Println("running", cmd.Args)
	return cmd.Output()
}

// Runs p4 with -G and captures the result lines.
func (p *Conn) RunMarshaled(command string, args []string) (result []Result, err error) {
	out, err := p.Output(append([]string{"-G", command}, args...))
	r := bytes.NewBuffer(out)
	for {
		v, err := Decode(r)
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}
		asMap, ok := v.(map[interface{}]interface{})
		if !ok {
			return nil, fmt.Errorf("format err: p4 marshaled %v", v)
		}
		result = append(result, interpretResult(asMap, command))
	}

	if len(result) > 0 {
		err = nil
	}

	return result, err
}

func interpretResult(in map[interface{}]interface{}, command string) Result {
	imap := map[string]interface{}{}
	for k, v := range in {
		imap[k.(string)] = v
	}
	code := imap["code"].(string)
	if code == "error" {
		e := Error{}
		e.Severity = int(imap["severity"].(int32))
		e.Generic = int(imap["generic"].(int32))
		e.Data = imap["data"].(string)
		return &e
	}

	switch command {
	case "dirs":
		return &Dir{Dir: imap["dir"].(string)}
	case "fstat":
		r := map[string]string{}
		for k, v := range imap {
			r[k] = v.(string)
		}

		st := Stat{
			DepotFile:  r["depotFile"],
			HeadAction: r["headAction"],
			Digest:     r["digest"],
			HeadType:   r["headType"],
		}

		// Brilliant. We get the integers as decimal strings. Sigh.
		st.HeadTime, _ = strconv.ParseInt(r["headTime"], 10, 64)
		st.HeadRev, _ = strconv.ParseInt(r["headRev"], 10, 64)
		st.HeadChange, _ = strconv.ParseInt(r["headChange"], 10, 64)
		st.HeadModTime, _ = strconv.ParseInt(r["headModTime"], 10, 64)
		st.FileSize, _ = strconv.ParseInt(r["fileSize"], 10, 64)
		return &st

	case "changes":
		r := map[string]string{}
		for k, v := range imap {
			r[k] = v.(string)
		}
		c := Change{
			Desc:       r["desc"],
			User:       r["user"],
			Status:     r["status"],
			Path:       r["path"],
			Code:       r["code"],
			ChangeType: r["changeType"],
			Client:     r["client"],
		}
		cl, _ := strconv.ParseInt(r["change"], 10, 64)
		c.Change = int(cl)
		t, _ := strconv.ParseInt(r["time"], 10, 64)
		c.Time = int(t)
		return &c
	default:
		log.Panicf("unknown code %q", command)
	}
	return nil
}

func (p *Conn) Fstat(paths []string) (results []Result, err error) {
	r, err := p.RunMarshaled("fstat",
		append([]string{"-Ol"}, paths...))
	return r, err
}

func (p *Conn) Dirs(paths []string) ([]Result, error) {
	return p.RunMarshaled("dirs", paths)
}

func (p *Conn) Print(path string) (content []byte, err error) {
	out, err := p.Output([]string{"print", path})
	if err != nil {
		return nil, err
	}
	parts := bytes.SplitN(out, []byte{'\n'}, 2)
	return parts[1], nil
}

func (p *Conn) Changes(paths []string) ([]Result, error) {
	return p.RunMarshaled("changes", append([]string{"-l"}, paths...))
}

////////////////
type Result interface {
	String() string
}

type Error struct {
	Generic  int
	Severity int
	Data     string
}

func (e *Error) String() string {
	return fmt.Sprintf("error %d(%d): %s", e.Generic, e.Severity, e.Data)
}

// Stat has the data for a single file revision.
type Stat struct {
	DepotFile   string
	HeadAction  string
	HeadType    string
	HeadTime    int64
	HeadRev     int64
	HeadChange  int64
	HeadModTime int64
	FileSize    int64
	Digest      string
}

func (f *Stat) String() string {
	return fmt.Sprintf("%s#%d - change %d (%s)",
		f.DepotFile, f.HeadRev, f.HeadChange, f.HeadType)
}

type Dir struct {
	Dir string
}

func (f *Dir) String() string {
	return fmt.Sprintf("%s/", f.Dir)
}

type Change struct {
	Desc   string
	User   string
	Status string
	Change int
	Time   int

	Path       string
	Code       string
	ChangeType string
	Client     string
}

func (c *Change) String() string {
	l := len(c.Desc)
	if l > 250 {
		l = 250
	}
	return fmt.Sprintf("change %d by %s - %s", c.Change, c.User, strings.Trim(c.Desc[:l], " "))
}
<|endoftext|>


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

package lib

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/venicegeo/pz-gocommon"
	"github.com/venicegeo/pz-gocommon/elasticsearch"
)

type LockedAdminSettings struct {
	sync.Mutex
	LoggerAdminSettings
}

var settings LockedAdminSettings

type LockedAdminStats struct {
	sync.Mutex
	LoggerAdminStats
}

var stats LockedAdminStats

type LogData struct {
	sync.Mutex
	esIndex elasticsearch.IIndex
	id      int
}

var logData LogData

var schema = "LogData"

func initServer(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) {
	var err error

	stats.StartTime = time.Now()

	/***/
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	/***/

	if !esIndex.IndexExists() {
		err = esIndex.Create()
		if err != nil {
			log.Fatal(err)
		}

		mapping :=
			`{
		    "LogData":{
			    "properties":{
				    "service":{
					    "type": "string",
                        "store": true
    			    },
				    "address":{
					    "type": "string",
                        "store": true
    			    },
				    "stamp":{
					    "type": "long",
                        "store": true
    			    },
				    "severity":{
					    "type": "string",
                        "store": true
    			    },
				    "message":{
					    "type": "string",
                        "store": true
    			    }
	    	    }
	        }
        }`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Fatal(err)
		}
	}

	logData.esIndex = esIndex
}

func handleGetRoot(c *gin.Context) {
	//log.Print("got health-check request")
	c.String(http.StatusOK, "Hi. I'm pz-logger.")
}

func handlePostMessages(c *gin.Context) {
	var mssg Message
	err := c.BindJSON(&mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	err = mssg.Validate()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	log.Printf("PZLOG: %s\n", mssg.String())

	logData.Lock()
	idStr := strconv.Itoa(logData.id)
	logData.id++
	logData.Unlock()
	indexResult, err := logData.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}
	if !indexResult.Created {
		c.String(http.StatusBadRequest, "POST of log data failed")
		return
	}

	err = logData.esIndex.Flush()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	stats.LoggerAdminStats.NumMessages++

	c.JSON(http.StatusOK, nil)
}

func handleGetAdminStats(c *gin.Context) {
	logData.Lock()
	t := stats.LoggerAdminStats
	logData.Unlock()
	c.JSON(http.StatusOK, t)
}

func handleGetAdminSettings(c *gin.Context) {
	settings.Lock()
	t := settings.LoggerAdminSettings
	settings.Unlock()
	c.JSON(http.StatusOK, t)
}

func handlePostAdminSettings(c *gin.Context) {
	t := LoggerAdminSettings{}
	err := c.BindJSON(&t)
	if err != nil {
		c.Error(err)
		return
	}
	settings.Lock()
	settings.LoggerAdminSettings = t
	settings.Unlock()
	c.String(http.StatusOK, "")
}

func handlePostAdminShutdown(c *gin.Context) {
	piazza.HandlePostAdminShutdown(c)
}

func handleGetMessages(c *gin.Context) {
	var err error
	count := 128
	key := c.Query("count")
	if key != "" {
		count, err = strconv.Atoi(key)
		if err != nil {
			c.String(http.StatusBadRequest, "query argument invalid: %s", key)
			return
		}
	}

	// copy up to count elements from the end of the log array

	searchResult, err := logData.esIndex.FilterByMatchAll(schema, "stamp")
	if err != nil {
		c.String(http.StatusBadRequest, "query failed: %s", err)
		return
	}

	// TODO: unsafe truncation
	l := int(searchResult.TotalHits())
	if count > l {
		count = l
	}
	lines := make([]Message, count)

	i := 0
	for _, hit := range *searchResult.GetHits() {
		if hit == nil {
			//log.Printf("null source hit")
			continue
		}
		src := *hit.Source
		//log.Printf("source hit: %s", string(src))

		tmp := &Message{}
		err = json.Unmarshal(src, tmp)
		if err != nil {
			log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
			c.String(http.StatusBadRequest, "query unmarshal failed: %s", err)
			return
		}
		err = tmp.Validate()
		if err != nil {
			log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
			//c.String(http.StatusBadRequest, "query unmarshal failed to validate: %s", err)
			//return
			continue
		}
		lines[i] = *tmp
		i++
	}

	c.JSON(http.StatusOK, lines)
}

func CreateHandlers(sys *piazza.SystemConfig, esi elasticsearch.IIndex) http.Handler {
	initServer(sys, esi)

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	//router.Use(gin.Logger())
	//router.Use(gin.Recovery())

	router.GET("/", func(c *gin.Context) { handleGetRoot(c) })

	router.POST("/v1/messages", func(c *gin.Context) { handlePostMessages(c) })
	router.GET("/v1/messages", func(c *gin.Context) { handleGetMessages(c) })

	router.GET("/v1/admin/stats", func(c *gin.Context) { handleGetAdminStats(c) })

	router.GET("/v1/admin/settings", func(c *gin.Context) { handleGetAdminSettings(c) })
	router.POST("/v1/admin/settings", func(c *gin.Context) { handlePostAdminSettings(c) })

	router.POST("/v1/admin/shutdown", func(c *gin.Context) { handlePostAdminShutdown(c) })

	return router
}
<commit_msg>comment out the index deleter<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lib

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/venicegeo/pz-gocommon"
	"github.com/venicegeo/pz-gocommon/elasticsearch"
)

type LockedAdminSettings struct {
	sync.Mutex
	LoggerAdminSettings
}

var settings LockedAdminSettings

type LockedAdminStats struct {
	sync.Mutex
	LoggerAdminStats
}

var stats LockedAdminStats

type LogData struct {
	sync.Mutex
	esIndex elasticsearch.IIndex
	id      int
}

var logData LogData

var schema = "LogData"

func initServer(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) {
	var err error

	stats.StartTime = time.Now()

	/***
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	***/

	if !esIndex.IndexExists() {
		err = esIndex.Create()
		if err != nil {
			log.Fatal(err)
		}

		mapping :=
			`{
		    "LogData":{
			    "properties":{
				    "service":{
					    "type": "string",
                        "store": true
    			    },
				    "address":{
					    "type": "string",
                        "store": true
    			    },
				    "stamp":{
					    "type": "long",
                        "store": true
    			    },
				    "severity":{
					    "type": "string",
                        "store": true
    			    },
				    "message":{
					    "type": "string",
                        "store": true
    			    }
	    	    }
	        }
        }`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Fatal(err)
		}
	}

	logData.esIndex = esIndex
}

func handleGetRoot(c *gin.Context) {
	//log.Print("got health-check request")
	c.String(http.StatusOK, "Hi. I'm pz-logger.")
}

func handlePostMessages(c *gin.Context) {
	var mssg Message
	err := c.BindJSON(&mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	err = mssg.Validate()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	log.Printf("PZLOG: %s\n", mssg.String())

	logData.Lock()
	idStr := strconv.Itoa(logData.id)
	logData.id++
	logData.Unlock()
	indexResult, err := logData.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}
	if !indexResult.Created {
		c.String(http.StatusBadRequest, "POST of log data failed")
		return
	}

	err = logData.esIndex.Flush()
	if err != nil {
		c.String(http.StatusBadRequest, "%v", err)
		return
	}

	stats.LoggerAdminStats.NumMessages++

	c.JSON(http.StatusOK, nil)
}

func handleGetAdminStats(c *gin.Context) {
	logData.Lock()
	t := stats.LoggerAdminStats
	logData.Unlock()
	c.JSON(http.StatusOK, t)
}

func handleGetAdminSettings(c *gin.Context) {
	settings.Lock()
	t := settings.LoggerAdminSettings
	settings.Unlock()
	c.JSON(http.StatusOK, t)
}

func handlePostAdminSettings(c *gin.Context) {
	t := LoggerAdminSettings{}
	err := c.BindJSON(&t)
	if err != nil {
		c.Error(err)
		return
	}
	settings.Lock()
	settings.LoggerAdminSettings = t
	settings.Unlock()
	c.String(http.StatusOK, "")
}

func handlePostAdminShutdown(c *gin.Context) {
	piazza.HandlePostAdminShutdown(c)
}

func handleGetMessages(c *gin.Context) {
	var err error
	count := 128
	key := c.Query("count")
	if key != "" {
		count, err = strconv.Atoi(key)
		if err != nil {
			c.String(http.StatusBadRequest, "query argument invalid: %s", key)
			return
		}
	}

	// copy up to count elements from the end of the log array

	searchResult, err := logData.esIndex.FilterByMatchAll(schema, "stamp")
	if err != nil {
		c.String(http.StatusBadRequest, "query failed: %s", err)
		return
	}

	// TODO: unsafe truncation
	l := int(searchResult.TotalHits())
	if count > l {
		count = l
	}
	lines := make([]Message, count)

	i := 0
	for _, hit := range *searchResult.GetHits() {
		if hit == nil {
			//log.Printf("null source hit")
			continue
		}
		src := *hit.Source
		//log.Printf("source hit: %s", string(src))

		tmp := &Message{}
		err = json.Unmarshal(src, tmp)
		if err != nil {
			log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
			c.String(http.StatusBadRequest, "query unmarshal failed: %s", err)
			return
		}
		err = tmp.Validate()
		if err != nil {
			log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
			//c.String(http.StatusBadRequest, "query unmarshal failed to validate: %s", err)
			//return
			continue
		}
		lines[i] = *tmp
		i++
	}

	c.JSON(http.StatusOK, lines)
}

func CreateHandlers(sys *piazza.SystemConfig, esi elasticsearch.IIndex) http.Handler {
	initServer(sys, esi)

	gin.SetMode(gin.ReleaseMode)
	router := gin.New()
	//router.Use(gin.Logger())
	//router.Use(gin.Recovery())

	router.GET("/", func(c *gin.Context) { handleGetRoot(c) })

	router.POST("/v1/messages", func(c *gin.Context) { handlePostMessages(c) })
	router.GET("/v1/messages", func(c *gin.Context) { handleGetMessages(c) })

	router.GET("/v1/admin/stats", func(c *gin.Context) { handleGetAdminStats(c) })

	router.GET("/v1/admin/settings", func(c *gin.Context) { handleGetAdminSettings(c) })
	router.POST("/v1/admin/settings", func(c *gin.Context) { handlePostAdminSettings(c) })

	router.POST("/v1/admin/shutdown", func(c *gin.Context) { handlePostAdminShutdown(c) })

	return router
}
<|endoftext|>


<commit_before>package gorm

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"

	"time"
)

type Model struct {
	data   interface{}
	driver string
}

type Field struct {
	Name           string
	Value          interface{}
	SqlType        string
	DbName         string
	AutoCreateTime bool
	AutoUpdateTime bool
	IsPrimaryKey   bool
	IsBlank        bool
}

func (m *Model) primaryKeyZero() bool {
	return m.primaryKeyValue() <= 0
}

func (m *Model) primaryKeyValue() int64 {
	if m.data == nil {
		return -1
	}

	data := reflect.ValueOf(m.data).Elem()

	switch data.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
		return 0
	default:
		value := data.FieldByName(m.primaryKey())

		if value.IsValid() {
			switch value.Kind() {
			case reflect.Int, reflect.Int64, reflect.Int32:
				return value.Int()
			default:
				return 0
			}
		} else {
			return 0
		}
	}
}

func (m *Model) primaryKey() string {
	return "Id"
}

func (m *Model) primaryKeyDb() string {
	return toSnake(m.primaryKey())
}

func (m *Model) fields(operation string) (fields []Field) {
	indirect_value := reflect.Indirect(reflect.ValueOf(m.data))
	typ := indirect_value.Type()

	for i := 0; i < typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			var field Field
			field.Name = p.Name
			field.DbName = toSnake(p.Name)
			field.IsPrimaryKey = m.primaryKeyDb() == field.DbName
			field.AutoCreateTime = "created_at" == field.DbName
			field.AutoUpdateTime = "updated_at" == field.DbName
			value := indirect_value.FieldByName(p.Name)

			switch value.Kind() {
			case reflect.Int, reflect.Int64, reflect.Int32:
				field.IsBlank = value.Int() == 0
			case reflect.String:
				field.IsBlank = value.String() == ""
			default:
				if value, ok := value.Interface().(time.Time); ok {
					field.IsBlank = value.IsZero()
				}
			}

			if v, ok := value.Interface().(time.Time); ok {
				switch operation {
				case "create":
					if (field.AutoCreateTime || field.AutoUpdateTime) && v.IsZero() {
						value.Set(reflect.ValueOf(time.Now()))
					}
				case "update":
					if field.AutoUpdateTime {
						value.Set(reflect.ValueOf(time.Now()))
					}
				}
			}

			field.Value = value.Interface()

			if field.IsPrimaryKey {
				field.SqlType = getPrimaryKeySqlType(m.driver, field.Value, 0)
			} else {
				field.SqlType = getSqlType(m.driver, field.Value, 0)
			}
			fields = append(fields, field)
		}
	}
	return

}

func (m *Model) columnsHasValue(operation string) (fields []Field) {
	for _, field := range m.fields(operation) {
		if !field.IsBlank {
			fields = append(fields, field)
		}
	}
	return
}

func (m *Model) updatedColumnsAndValues(values map[string]interface{}) (map[string]interface{}, bool) {
	if m.data == nil {
		return values, true
	}

	data := reflect.Indirect(reflect.ValueOf(m.data))
	results := map[string]interface{}{}

	for key, value := range values {
		field := data.FieldByName(snakeToUpperCamel(key))
		if field.IsValid() {
			if field.Interface() != value {
				switch field.Kind() {
				case reflect.Int, reflect.Int32, reflect.Int64:
					if field.Int() != reflect.ValueOf(value).Int() {
						results[key] = value
					}
					field.SetInt(reflect.ValueOf(value).Int())
				default:
					results[key] = value
					field.Set(reflect.ValueOf(value))
				}
			}
		}
	}

	if values["updated_at"] != nil && len(results) > 0 {
		setFieldValue(data.FieldByName("UpdatedAt"), time.Now())
	}
	result := len(results) > 0
	return map[string]interface{}{}, result
}

func (m *Model) columnsAndValues(operation string) map[string]interface{} {
	if m.data == nil {
		return map[string]interface{}{}
	}

	results := map[string]interface{}{}
	for _, field := range m.fields(operation) {
		if !field.IsPrimaryKey {
			results[field.DbName] = field.Value
		}
	}
	return results
}

func (m *Model) hasColumn(name string) bool {
	if m.data == nil {
		return false
	}

	data := reflect.Indirect(reflect.ValueOf(m.data))
	if data.Kind() == reflect.Slice {
		return reflect.New(data.Type().Elem()).Elem().FieldByName(name).IsValid()
	} else {
		return data.FieldByName(name).IsValid()
	}
}

func (m *Model) tableName() (str string, err error) {
	if m.data == nil {
		err = errors.New("Model haven't been set")
		return
	}

	typ := reflect.Indirect(reflect.ValueOf(m.data)).Type()
	if typ.Kind() == reflect.Slice {
		typ = typ.Elem()
	}

	str = toSnake(typ.Name())
	pluralMap := map[string]string{"ch": "ches", "ss": "sses", "sh": "shes", "day": "days", "y": "ies", "x": "xes", "s?": "s"}
	for key, value := range pluralMap {
		reg := regexp.MustCompile(key + "$")
		if reg.MatchString(str) {
			return reg.ReplaceAllString(str, value), err
		}
	}
	return
}

func (m *Model) callMethod(method string) error {
	if m.data == nil {
		return nil
	}

	fm := reflect.ValueOf(m.data).MethodByName(method)
	if fm.IsValid() {
		v := fm.Call([]reflect.Value{})
		if len(v) > 0 {
			if verr, ok := v[0].Interface().(error); ok {
				return verr
			}
		}
	}
	return nil
}

func (m *Model) returningStr() (str string) {
	if m.driver == "postgres" {
		str = fmt.Sprintf("RETURNING \"%v\"", m.primaryKeyDb())
	}
	return
}

func (m *Model) missingColumns() (results []string) {
	return
}

func (m *Model) setValueByColumn(name string, value interface{}, out interface{}) {
	data := reflect.Indirect(reflect.ValueOf(out))
	setFieldValue(data.FieldByName(snakeToUpperCamel(name)), value)
}

func setFieldValue(field reflect.Value, value interface{}) {
	if field.IsValid() {
		switch field.Kind() {
		case reflect.Int, reflect.Int32, reflect.Int64:
			field.SetInt(reflect.ValueOf(value).Int())
		default:
			field.Set(reflect.ValueOf(value))
		}
	}
}
<commit_msg>Convert str to int if it is when set field<commit_after>package gorm

import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"strconv"

	"time"
)

type Model struct {
	data   interface{}
	driver string
}

type Field struct {
	Name           string
	Value          interface{}
	SqlType        string
	DbName         string
	AutoCreateTime bool
	AutoUpdateTime bool
	IsPrimaryKey   bool
	IsBlank        bool
}

func (m *Model) primaryKeyZero() bool {
	return m.primaryKeyValue() <= 0
}

func (m *Model) primaryKeyValue() int64 {
	if m.data == nil {
		return -1
	}

	data := reflect.ValueOf(m.data).Elem()

	switch data.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
		return 0
	default:
		value := data.FieldByName(m.primaryKey())

		if value.IsValid() {
			switch value.Kind() {
			case reflect.Int, reflect.Int64, reflect.Int32:
				return value.Int()
			default:
				return 0
			}
		} else {
			return 0
		}
	}
}

func (m *Model) primaryKey() string {
	return "Id"
}

func (m *Model) primaryKeyDb() string {
	return toSnake(m.primaryKey())
}

func (m *Model) fields(operation string) (fields []Field) {
	indirect_value := reflect.Indirect(reflect.ValueOf(m.data))
	typ := indirect_value.Type()

	for i := 0; i < typ.NumField(); i++ {
		p := typ.Field(i)
		if !p.Anonymous {
			var field Field
			field.Name = p.Name
			field.DbName = toSnake(p.Name)
			field.IsPrimaryKey = m.primaryKeyDb() == field.DbName
			field.AutoCreateTime = "created_at" == field.DbName
			field.AutoUpdateTime = "updated_at" == field.DbName
			value := indirect_value.FieldByName(p.Name)

			switch value.Kind() {
			case reflect.Int, reflect.Int64, reflect.Int32:
				field.IsBlank = value.Int() == 0
			case reflect.String:
				field.IsBlank = value.String() == ""
			default:
				if value, ok := value.Interface().(time.Time); ok {
					field.IsBlank = value.IsZero()
				}
			}

			if v, ok := value.Interface().(time.Time); ok {
				switch operation {
				case "create":
					if (field.AutoCreateTime || field.AutoUpdateTime) && v.IsZero() {
						value.Set(reflect.ValueOf(time.Now()))
					}
				case "update":
					if field.AutoUpdateTime {
						value.Set(reflect.ValueOf(time.Now()))
					}
				}
			}

			field.Value = value.Interface()

			if field.IsPrimaryKey {
				field.SqlType = getPrimaryKeySqlType(m.driver, field.Value, 0)
			} else {
				field.SqlType = getSqlType(m.driver, field.Value, 0)
			}
			fields = append(fields, field)
		}
	}
	return

}

func (m *Model) columnsHasValue(operation string) (fields []Field) {
	for _, field := range m.fields(operation) {
		if !field.IsBlank {
			fields = append(fields, field)
		}
	}
	return
}

func (m *Model) updatedColumnsAndValues(values map[string]interface{}) (map[string]interface{}, bool) {
	if m.data == nil {
		return values, true
	}

	data := reflect.Indirect(reflect.ValueOf(m.data))
	results := map[string]interface{}{}

	for key, value := range values {
		field := data.FieldByName(snakeToUpperCamel(key))
		if field.IsValid() {
			if field.Interface() != value {
				switch field.Kind() {
				case reflect.Int, reflect.Int32, reflect.Int64:
					if field.Int() != reflect.ValueOf(value).Int() {
						results[key] = value
					}
					field.SetInt(reflect.ValueOf(value).Int())
				default:
					results[key] = value
					field.Set(reflect.ValueOf(value))
				}
			}
		}
	}

	if values["updated_at"] != nil && len(results) > 0 {
		setFieldValue(data.FieldByName("UpdatedAt"), time.Now())
	}
	result := len(results) > 0
	return map[string]interface{}{}, result
}

func (m *Model) columnsAndValues(operation string) map[string]interface{} {
	if m.data == nil {
		return map[string]interface{}{}
	}

	results := map[string]interface{}{}
	for _, field := range m.fields(operation) {
		if !field.IsPrimaryKey {
			results[field.DbName] = field.Value
		}
	}
	return results
}

func (m *Model) hasColumn(name string) bool {
	if m.data == nil {
		return false
	}

	data := reflect.Indirect(reflect.ValueOf(m.data))
	if data.Kind() == reflect.Slice {
		return reflect.New(data.Type().Elem()).Elem().FieldByName(name).IsValid()
	} else {
		return data.FieldByName(name).IsValid()
	}
}

func (m *Model) tableName() (str string, err error) {
	if m.data == nil {
		err = errors.New("Model haven't been set")
		return
	}

	typ := reflect.Indirect(reflect.ValueOf(m.data)).Type()
	if typ.Kind() == reflect.Slice {
		typ = typ.Elem()
	}

	str = toSnake(typ.Name())
	pluralMap := map[string]string{"ch": "ches", "ss": "sses", "sh": "shes", "day": "days", "y": "ies", "x": "xes", "s?": "s"}
	for key, value := range pluralMap {
		reg := regexp.MustCompile(key + "$")
		if reg.MatchString(str) {
			return reg.ReplaceAllString(str, value), err
		}
	}
	return
}

func (m *Model) callMethod(method string) error {
	if m.data == nil {
		return nil
	}

	fm := reflect.ValueOf(m.data).MethodByName(method)
	if fm.IsValid() {
		v := fm.Call([]reflect.Value{})
		if len(v) > 0 {
			if verr, ok := v[0].Interface().(error); ok {
				return verr
			}
		}
	}
	return nil
}

func (m *Model) returningStr() (str string) {
	if m.driver == "postgres" {
		str = fmt.Sprintf("RETURNING \"%v\"", m.primaryKeyDb())
	}
	return
}

func (m *Model) missingColumns() (results []string) {
	return
}

func (m *Model) setValueByColumn(name string, value interface{}, out interface{}) {
	data := reflect.Indirect(reflect.ValueOf(out))
	setFieldValue(data.FieldByName(snakeToUpperCamel(name)), value)
}

func setFieldValue(field reflect.Value, value interface{}) {
	if field.IsValid() {
		switch field.Kind() {
		case reflect.Int, reflect.Int32, reflect.Int64:
			if str, ok := value.(string); ok {
				value, _ = strconv.Atoi(str)
			}
			field.SetInt(reflect.ValueOf(value).Int())
		default:
			field.Set(reflect.ValueOf(value))
		}
	}
}
<|endoftext|>