<commit_before>package tacplus

import (
	"context"
	"errors"
	"net"
	"sync"
)

// ClientAuthenSession is a TACACS+ client authentication session.
type ClientAuthenSession struct {
	*session
}

// Close closes the client authentication session.
func (c *ClientAuthenSession) Close() {
	c.close()
}

// Abort sends a message back to the server aborting the session with the supplied reason.
func (c *ClientAuthenSession) Abort(ctx context.Context, reason string) error {
	if len(reason) > maxUint16 {
		reason = reason[:maxUint16]
	}
	err := c.writePacket(ctx, &authenContinue{Abort: true, Data: []byte(reason)})
	c.close()
	return err
}

// Continue is used to send msg in response to a previous AuthenReply.
// A new AuthenReply or error is returned.
func (c *ClientAuthenSession) Continue(ctx context.Context, msg string) (*AuthenReply, error) {
	// sequence number too large to continue
	if c.seq >= 0xfe {
		_ = c.Abort(ctx, "")
		return nil, errors.New("session aborted, too many packets")
	}

	rep := new(AuthenReply)
	if err := sendRequest(ctx, c.session, &authenContinue{UserMsg: msg}, rep); err != nil {
		c.close()
		return nil, err
	}
	if rep.last() {
		c.close()
	}
	return rep, nil
}

func sendRequest(ctx context.Context, s *session, req, rep packet) error {
	err := s.writePacket(ctx, req)
	if err != nil || rep == nil {
		return err
	}
	return s.readPacket(ctx, rep)
}

// Client is a TACACS+ client that connects to a single TACACS+ server.
//
// If the Client's ConnConfig enables session multiplexing, the client will
// cache a single open connection for this purpose.
type Client struct {
	Addr       string     // TCP address of tacacs server.
	ConnConfig ConnConfig // TACACS+ connection configuration.

	// Optional DialContext function used to create the network connection.
	DialContext func(ctx context.Context, net, addr string) (net.Conn, error)

	mu   sync.Mutex // protects access to conn
	conn *conn      // current cached mux connection
}

// Close closes the cached connection.
func (c *Client) Close() {
	c.mu.Lock()
	conn := c.conn
	c.mu.Unlock()
	if conn != nil {
		conn.close()
	}
}

var zeroDialer net.Dialer

func (c *Client) dial(ctx context.Context) (net.Conn, error) {
	if c.DialContext != nil {
		return c.DialContext(ctx, "tcp", c.Addr)
	}
	return zeroDialer.DialContext(ctx, "tcp", c.Addr)
}

func (c *Client) newSession(ctx context.Context, ver, t uint8) (*session, error) {
	if c.ConnConfig.Mux {
		// try to use existing cached connection
		c.mu.Lock()
		conn := c.conn
		c.mu.Unlock()
		if conn != nil {
			if s, _ := conn.newClientSession(ctx, ver, t); s != nil {
				return s, nil
			}
		}
	}

	// create new connection
	nc, err := c.dial(ctx)
	if err != nil {
		return nil, err
	}
	conn := newConn(nc, nil, c.ConnConfig)
	go conn.serve()

	s, err := conn.newClientSession(ctx, ver, t)
	if err != nil {
		conn.close()
		return nil, err
	}
	if c.ConnConfig.Mux {
		// attempt to cache multiplexed connection
		c.mu.Lock()
		defer c.mu.Unlock()
		if c.conn == nil {
			// cache this connection
			c.conn = conn
			go func() {
				// clear cached reference when conn closes
				<-conn.done
				c.mu.Lock()
				c.conn = nil
				c.mu.Unlock()
			}()
		} else {
			// already cached one connection, so create goroutine
			// that closes connection when session is closed so
			// we don't leak idle connections.
			go func() {
				<-s.done
				conn.close()
			}()
		}
	}
	return s, nil
}

func (c *Client) startSession(ctx context.Context, ver, t uint8, req, rep packet) (*session, error) {
	s, err := c.newSession(ctx, ver, t)
	if err != nil {
		return nil, err
	}
	if err = sendRequest(ctx, s, req, rep); err != nil {
		s.close()
		return nil, err
	}
	return s, nil
}

// SendAcctRequest sends an AcctRequest to the server returning an AcctReply or error.
func (c *Client) SendAcctRequest(ctx context.Context, req *AcctRequest) (*AcctReply, error) {
	rep := new(AcctReply)
	s, err := c.startSession(ctx, verDefault, sessTypeAcct, req, rep)
	if err != nil {
		return nil, err
	}
	s.close()
	return rep, nil
}

// SendAuthorRequest sends an AuthorRequest to the server returning an AuthorResponse or error.
func (c *Client) SendAuthorRequest(ctx context.Context, req *AuthorRequest) (*AuthorResponse, error) {
	resp := new(AuthorResponse)
	s, err := c.startSession(ctx, verDefault, sessTypeAuthor, req, resp)
	if err != nil {
		return nil, err
	}
	s.close()
	return resp, nil
}

// SendAuthenStart sends an AuthenStart to the server returning an AuthenReply and
// optional ClientAuthenSession or an error. If ClientAuthenSession is set it should be
// used to complete the current interactive authentication session.
func (c *Client) SendAuthenStart(ctx context.Context, as *AuthenStart) (*AuthenReply, *ClientAuthenSession, error) {
	rep := new(AuthenReply)
	s, err := c.startSession(ctx, as.version(), sessTypeAuthen, as, rep)
	if err != nil {
		return nil, nil, err
	}
	if rep.last() {
		s.close()
		return rep, nil, nil
	}
	return rep, &ClientAuthenSession{s}, nil
}
<commit_msg>api change: rename ClientAuthenSession to ClientSession. Move sendRequest method to ClientSession so we can use ClientSession internally for all request types. Change Abort to use sendRequest so all reading & writing of sessions is in one method.<commit_after>package tacplus

import (
	"context"
	"errors"
	"net"
	"sync"
)

// ClientSession is a TACACS+ client session.
type ClientSession struct {
	*session
}

// Close closes the client session.
func (c *ClientSession) Close() {
	c.close()
}

// Abort sends a message back to the server aborting the session with the supplied reason.
func (c *ClientSession) Abort(ctx context.Context, reason string) error {
	if len(reason) > maxUint16 {
		reason = reason[:maxUint16]
	}
	err := c.sendRequest(ctx, &authenContinue{Abort: true, Data: []byte(reason)}, nil)
	c.close()
	return err
}

// Continue is used to send msg in response to a previous AuthenReply.
// A new AuthenReply or error is returned.
func (c *ClientSession) Continue(ctx context.Context, msg string) (*AuthenReply, error) {
	// sequence number too large to continue
	if c.seq >= 0xfe {
		_ = c.Abort(ctx, "")
		return nil, errors.New("session aborted, too many packets")
	}

	rep := new(AuthenReply)
	if err := c.sendRequest(ctx, &authenContinue{UserMsg: msg}, rep); err != nil {
		c.close()
		return nil, err
	}
	if rep.last() {
		c.close()
	}
	return rep, nil
}

func (c *ClientSession) sendRequest(ctx context.Context, req, rep packet) error {
	err := c.writePacket(ctx, req)
	if err != nil || rep == nil {
		return err
	}
	return c.readPacket(ctx, rep)
}

// Client is a TACACS+ client that connects to a single TACACS+ server.
//
// If the Client's ConnConfig enables session multiplexing, the client will
// cache a single open connection for this purpose.
type Client struct {
	Addr       string     // TCP address of tacacs server.
	ConnConfig ConnConfig // TACACS+ connection configuration.

	// Optional DialContext function used to create the network connection.
	DialContext func(ctx context.Context, net, addr string) (net.Conn, error)

	mu   sync.Mutex // protects access to conn
	conn *conn      // current cached mux connection
}

// Close closes the cached connection.
func (c *Client) Close() {
	c.mu.Lock()
	conn := c.conn
	c.mu.Unlock()
	if conn != nil {
		conn.close()
	}
}

var zeroDialer net.Dialer

func (c *Client) dial(ctx context.Context) (net.Conn, error) {
	if c.DialContext != nil {
		return c.DialContext(ctx, "tcp", c.Addr)
	}
	return zeroDialer.DialContext(ctx, "tcp", c.Addr)
}

func (c *Client) newSession(ctx context.Context, ver, t uint8) (*session, error) {
	if c.ConnConfig.Mux {
		// try to use existing cached connection
		c.mu.Lock()
		conn := c.conn
		c.mu.Unlock()
		if conn != nil {
			if s, _ := conn.newClientSession(ctx, ver, t); s != nil {
				return s, nil
			}
		}
	}

	// create new connection
	nc, err := c.dial(ctx)
	if err != nil {
		return nil, err
	}
	conn := newConn(nc, nil, c.ConnConfig)
	go conn.serve()

	s, err := conn.newClientSession(ctx, ver, t)
	if err != nil {
		conn.close()
		return nil, err
	}
	if c.ConnConfig.Mux {
		// attempt to cache multiplexed connection
		c.mu.Lock()
		defer c.mu.Unlock()
		if c.conn == nil {
			// cache this connection
			c.conn = conn
			go func() {
				// clear cached reference when conn closes
				<-conn.done
				c.mu.Lock()
				c.conn = nil
				c.mu.Unlock()
			}()
		} else {
			// already cached one connection, so create goroutine
			// that closes connection when session is closed so
			// we don't leak idle connections.
			go func() {
				<-s.done
				conn.close()
			}()
		}
	}
	return s, nil
}

func (c *Client) startSession(ctx context.Context, ver, t uint8, req, rep packet) (*ClientSession, error) {
	s, err := c.newSession(ctx, ver, t)
	if err != nil {
		return nil, err
	}
	cs := &ClientSession{s}
	if err = cs.sendRequest(ctx, req, rep); err != nil {
		cs.close()
		return nil, err
	}
	return cs, nil
}

// SendAcctRequest sends an AcctRequest to the server returning an AcctReply or error.
func (c *Client) SendAcctRequest(ctx context.Context, req *AcctRequest) (*AcctReply, error) {
	rep := new(AcctReply)
	s, err := c.startSession(ctx, verDefault, sessTypeAcct, req, rep)
	if err != nil {
		return nil, err
	}
	s.close()
	return rep, nil
}

// SendAuthorRequest sends an AuthorRequest to the server returning an AuthorResponse or error.
func (c *Client) SendAuthorRequest(ctx context.Context, req *AuthorRequest) (*AuthorResponse, error) {
	resp := new(AuthorResponse)
	s, err := c.startSession(ctx, verDefault, sessTypeAuthor, req, resp)
	if err != nil {
		return nil, err
	}
	s.close()
	return resp, nil
}

// SendAuthenStart sends an AuthenStart to the server returning an AuthenReply and
// optional ClientSession or an error. If ClientSession is set it should be
// used to complete the current interactive authentication session.
func (c *Client) SendAuthenStart(ctx context.Context, as *AuthenStart) (*AuthenReply, *ClientSession, error) {
	rep := new(AuthenReply)
	s, err := c.startSession(ctx, as.version(), sessTypeAuthen, as, rep)
	if err != nil {
		return nil, nil, err
	}
	if rep.last() {
		s.close()
		return rep, nil, nil
	}
	return rep, s, nil
}
<|endoftext|>


<commit_before>/*
A smart client for go.

Usage:

 client, err := couchbase.Connect("http://myserver:8091/")
 handleError(err)
 pool, err := client.GetPool("default")
 handleError(err)
 bucket, err := pool.getBucket("MyAwesomeBucket")
 handleError(err)
 ...

or a shortcut for the bucket directly

 bucket, err := couchbase.GetBucket("http://myserver:8091/", "default", "default")
*/
package couchbase

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

func (b *Bucket) ensureConnection(which int) error {
	if b.connections == nil {
		b.connections = []*memcached.Client{}
	}
	if b.connections[which] == nil {
		var err error
		b.connections[which], err = memcached.Connect("tcp",
			b.VBucketServerMap.ServerList[which])
		if err != nil {
			return err
		}

		if b.Name != "default" {
			b.connections[which].Auth(b.Name, "")
		}

	}
	return nil
}

// Execute a function on a memcached connection to the node owning key "k"
//
// Note that this automatically handles transient errors by replaying
// your function on a "not-my-vbucket" error, so don't assume
// your command will only be executed only once.
func (b *Bucket) Do(k string, f func(mc *memcached.Client, vb uint16) error) error {
	vb := b.VBHash(k)
	for {
		masterId := b.VBucketServerMap.VBucketMap[vb][0]
		if err := b.ensureConnection(masterId); err != nil {
			return err
		}
		err := f(b.connections[masterId], uint16(vb))
		switch err.(type) {
		default:
			return err
		case gomemcached.MCResponse:
			st := err.(gomemcached.MCResponse).Status
			atomic.AddUint64(&b.pool.client.Statuses[st], 1)
			if st == gomemcached.NOT_MY_VBUCKET {
				b.refresh()
			} else {
				return err
			}
		}
	}
	panic("Unreachable.")
}

type gathered_stats struct {
	sn   string
	vals map[string]string
}

func getStatsParallel(b *Bucket, offset int, which string, ch chan<- gathered_stats) {
	sn := b.VBucketServerMap.ServerList[offset]

	results := map[string]string{}
	err := b.ensureConnection(offset)
	if err != nil {
		ch <- gathered_stats{sn, results}
	} else {
		st, err := b.connections[offset].StatsMap(which)
		if err == nil {
			ch <- gathered_stats{sn, st}
		} else {
			ch <- gathered_stats{sn, results}
		}
	}
}

// Get a set of stats from all servers.
//
// Returns a map of server ID -> map of stat key to map value.
func (b *Bucket) GetStats(which string) map[string]map[string]string {
	rv := map[string]map[string]string{}

	if b.VBucketServerMap.ServerList == nil {
		return rv
	}
	// Go grab all the things at once.
	todo := len(b.VBucketServerMap.ServerList)
	ch := make(chan gathered_stats, todo)

	for offset, _ := range b.VBucketServerMap.ServerList {
		go getStatsParallel(b, offset, which, ch)
	}

	// Gather the results
	for i := 0; i < len(b.VBucketServerMap.ServerList); i++ {
		g := <-ch
		if len(g.vals) > 0 {
			rv[g.sn] = g.vals
		}
	}

	return rv
}

func (b *Bucket) doBulkGet(vb uint16, keys []string,
	ch chan<- map[string]*gomemcached.MCResponse) {
	for {
		masterId := b.VBucketServerMap.VBucketMap[vb][0]
		if err := b.ensureConnection(masterId); err != nil {
			ch <- map[string]*gomemcached.MCResponse{}
		}

		m, err := b.connections[masterId].GetBulk(vb, keys)
		switch err.(type) {
		default:
			ch <- m
		case gomemcached.MCResponse:
			st := err.(gomemcached.MCResponse).Status
			atomic.AddUint64(&b.pool.client.Statuses[st], 1)
			if st == gomemcached.NOT_MY_VBUCKET {
				b.refresh()
			} else {
				ch <- map[string]*gomemcached.MCResponse{}
			}
		}
	}
}

func (b *Bucket) GetBulk(keys []string) map[string]*gomemcached.MCResponse {
	// Organize by vbucket
	kdm := map[uint16][]string{}
	for _, k := range keys {
		vb := uint16(b.VBHash(k))
		a, ok := kdm[vb]
		if !ok {
			a = []string{}
		}
		kdm[vb] = append(a, k)
	}

	ch := make(chan map[string]*gomemcached.MCResponse)

	for k, v := range kdm {
		go b.doBulkGet(k, v, ch)
	}

	rv := map[string]*gomemcached.MCResponse{}
	for _ = range kdm {
		m := <-ch
		for k, v := range m {
			rv[k] = v
		}
	}

	return rv
}

// Set a value in this bucket.
// The value will be serialized into a JSON document.
func (b *Bucket) Set(k string, v interface{}) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		data, err := json.Marshal(v)
		if err != nil {
			return err
		}
		res, err := mc.Set(vb, k, 0, 0, data)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return nil
	})
}

// Get a value from this bucket.
// The value is expected to be a JSON stream and will be deserialized
// into rv.
func (b *Bucket) Get(k string, rv interface{}) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Get(vb, k)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return json.Unmarshal(res.Body, rv)
	})
}

// Delete a key from this bucket.
func (b *Bucket) Delete(k string) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Del(vb, k)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return nil
	})
}

// Increment a key
func (b *Bucket) Incr(k string, amt, def uint64, exp int) (uint64, error) {
	var rv uint64
	err := b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Incr(vb, k, amt, def, exp)
		if err != nil {
			return err
		}
		rv = res
		return nil
	})
	return rv, err
}

type ViewRow struct {
	ID    string
	Key   interface{}
	Value interface{}
	Doc   *interface{}
}

type ViewResult struct {
	TotalRows int `json:"total_rows"`
	Rows      []ViewRow
	Errors    []struct {
		From   string
		Reason string
	}
}

// Execute a view
func (b *Bucket) View(ddoc, name string, params map[string]interface{}) (vres ViewResult, err error) {
	// Pick a random node to service our request.
	node := b.Nodes[rand.Intn(len(b.Nodes))]
	u, err := url.Parse(node.CouchAPIBase)
	if err != nil {
		return ViewResult{}, err
	}

	values := url.Values{}
	for k, v := range params {
		values[k] = []string{fmt.Sprintf("%v", v)}
	}

	u.Path = fmt.Sprintf("/%s/_design/%s/_view/%s", b.Name, ddoc, name)
	u.RawQuery = values.Encode()

	res, err := http.Get(u.String())
	if err != nil {
		return ViewResult{}, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return ViewResult{}, errors.New(res.Status)
	}

	d := json.NewDecoder(res.Body)
	if err = d.Decode(&vres); err != nil {
		return ViewResult{}, err
	}
	return vres, nil

}
<commit_msg>Drop connections on errors that aren't mc protocol errors.<commit_after>/*
A smart client for go.

Usage:

 client, err := couchbase.Connect("http://myserver:8091/")
 handleError(err)
 pool, err := client.GetPool("default")
 handleError(err)
 bucket, err := pool.getBucket("MyAwesomeBucket")
 handleError(err)
 ...

or a shortcut for the bucket directly

 bucket, err := couchbase.GetBucket("http://myserver:8091/", "default", "default")
*/
package couchbase

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

func (b *Bucket) ensureConnection(which int) error {
	if b.connections == nil {
		b.connections = []*memcached.Client{}
	}
	if b.connections[which] == nil {
		var err error
		b.connections[which], err = memcached.Connect("tcp",
			b.VBucketServerMap.ServerList[which])
		if err != nil {
			return err
		}

		if b.Name != "default" {
			b.connections[which].Auth(b.Name, "")
		}

	}
	return nil
}

// Execute a function on a memcached connection to the node owning key "k"
//
// Note that this automatically handles transient errors by replaying
// your function on a "not-my-vbucket" error, so don't assume
// your command will only be executed only once.
func (b *Bucket) Do(k string, f func(mc *memcached.Client, vb uint16) error) error {
	vb := b.VBHash(k)
	for {
		masterId := b.VBucketServerMap.VBucketMap[vb][0]
		if err := b.ensureConnection(masterId); err != nil {
			return err
		}
		err := f(b.connections[masterId], uint16(vb))
		switch err.(type) {
		default:
			b.connections[masterId].Close()
			b.connections[masterId] = nil
			return err
		case nil:
			return nil
		case gomemcached.MCResponse:
			st := err.(gomemcached.MCResponse).Status
			atomic.AddUint64(&b.pool.client.Statuses[st], 1)
			if st == gomemcached.NOT_MY_VBUCKET {
				b.refresh()
			} else {
				return err
			}
		}
	}
	panic("Unreachable.")
}

type gathered_stats struct {
	sn   string
	vals map[string]string
}

func getStatsParallel(b *Bucket, offset int, which string, ch chan<- gathered_stats) {
	sn := b.VBucketServerMap.ServerList[offset]

	results := map[string]string{}
	err := b.ensureConnection(offset)
	if err != nil {
		ch <- gathered_stats{sn, results}
	} else {
		st, err := b.connections[offset].StatsMap(which)
		if err == nil {
			ch <- gathered_stats{sn, st}
		} else {
			ch <- gathered_stats{sn, results}
		}
	}
}

// Get a set of stats from all servers.
//
// Returns a map of server ID -> map of stat key to map value.
func (b *Bucket) GetStats(which string) map[string]map[string]string {
	rv := map[string]map[string]string{}

	if b.VBucketServerMap.ServerList == nil {
		return rv
	}
	// Go grab all the things at once.
	todo := len(b.VBucketServerMap.ServerList)
	ch := make(chan gathered_stats, todo)

	for offset, _ := range b.VBucketServerMap.ServerList {
		go getStatsParallel(b, offset, which, ch)
	}

	// Gather the results
	for i := 0; i < len(b.VBucketServerMap.ServerList); i++ {
		g := <-ch
		if len(g.vals) > 0 {
			rv[g.sn] = g.vals
		}
	}

	return rv
}

func (b *Bucket) doBulkGet(vb uint16, keys []string,
	ch chan<- map[string]*gomemcached.MCResponse) {
	for {
		masterId := b.VBucketServerMap.VBucketMap[vb][0]
		if err := b.ensureConnection(masterId); err != nil {
			ch <- map[string]*gomemcached.MCResponse{}
		}

		m, err := b.connections[masterId].GetBulk(vb, keys)
		switch err.(type) {
		default:
			ch <- m
		case gomemcached.MCResponse:
			st := err.(gomemcached.MCResponse).Status
			atomic.AddUint64(&b.pool.client.Statuses[st], 1)
			if st == gomemcached.NOT_MY_VBUCKET {
				b.refresh()
			} else {
				ch <- map[string]*gomemcached.MCResponse{}
			}
		}
	}
}

func (b *Bucket) GetBulk(keys []string) map[string]*gomemcached.MCResponse {
	// Organize by vbucket
	kdm := map[uint16][]string{}
	for _, k := range keys {
		vb := uint16(b.VBHash(k))
		a, ok := kdm[vb]
		if !ok {
			a = []string{}
		}
		kdm[vb] = append(a, k)
	}

	ch := make(chan map[string]*gomemcached.MCResponse)

	for k, v := range kdm {
		go b.doBulkGet(k, v, ch)
	}

	rv := map[string]*gomemcached.MCResponse{}
	for _ = range kdm {
		m := <-ch
		for k, v := range m {
			rv[k] = v
		}
	}

	return rv
}

// Set a value in this bucket.
// The value will be serialized into a JSON document.
func (b *Bucket) Set(k string, v interface{}) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		data, err := json.Marshal(v)
		if err != nil {
			return err
		}
		res, err := mc.Set(vb, k, 0, 0, data)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return nil
	})
}

// Get a value from this bucket.
// The value is expected to be a JSON stream and will be deserialized
// into rv.
func (b *Bucket) Get(k string, rv interface{}) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Get(vb, k)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return json.Unmarshal(res.Body, rv)
	})
}

// Delete a key from this bucket.
func (b *Bucket) Delete(k string) error {
	return b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Del(vb, k)
		if err != nil {
			return err
		}
		if res.Status != gomemcached.SUCCESS {
			return res
		}
		return nil
	})
}

// Increment a key
func (b *Bucket) Incr(k string, amt, def uint64, exp int) (uint64, error) {
	var rv uint64
	err := b.Do(k, func(mc *memcached.Client, vb uint16) error {
		res, err := mc.Incr(vb, k, amt, def, exp)
		if err != nil {
			return err
		}
		rv = res
		return nil
	})
	return rv, err
}

type ViewRow struct {
	ID    string
	Key   interface{}
	Value interface{}
	Doc   *interface{}
}

type ViewResult struct {
	TotalRows int `json:"total_rows"`
	Rows      []ViewRow
	Errors    []struct {
		From   string
		Reason string
	}
}

// Execute a view
func (b *Bucket) View(ddoc, name string, params map[string]interface{}) (vres ViewResult, err error) {
	// Pick a random node to service our request.
	node := b.Nodes[rand.Intn(len(b.Nodes))]
	u, err := url.Parse(node.CouchAPIBase)
	if err != nil {
		return ViewResult{}, err
	}

	values := url.Values{}
	for k, v := range params {
		values[k] = []string{fmt.Sprintf("%v", v)}
	}

	u.Path = fmt.Sprintf("/%s/_design/%s/_view/%s", b.Name, ddoc, name)
	u.RawQuery = values.Encode()

	res, err := http.Get(u.String())
	if err != nil {
		return ViewResult{}, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return ViewResult{}, errors.New(res.Status)
	}

	d := json.NewDecoder(res.Body)
	if err = d.Decode(&vres); err != nil {
		return ViewResult{}, err
	}
	return vres, nil

}
<|endoftext|>


<commit_before>package gohttp

import (
	"bytes"
	"crypto/tls"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

type Request struct {
	*http.Request
}

func (self *Request) SetHeader(k, v string) *Request {
	self.Header.Add(k, v)
	return self
}

func (self *Request) Headers(kv map[string]string) *Request {
	for k, v := range kv {
		self.SetHeader(k, v)
	}
	return self
}

type Response struct {
	*http.Response
}

func (self *Response) Code() int {
	return self.StatusCode
}

func (self *Response) Bytes() ([]byte, error) {
	return ioutil.ReadAll(self.Body)
}

func (self *Response) String() string {
	if resp, err := self.Bytes(); err != nil {
		return ""
	} else {
		return string(resp)
	}

}

func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
	req, err := http.NewRequest(method, urlStr, body)
	return &Request{req}, err
}

type Client struct {
	method     string
	url        string
	path       string
	query      string
	fragment   string
	cookies    map[string]string
	headers    map[string]string
	body       interface{}
	proxy      string
	timeout    int
	retries    int
	verifySsl  bool //true:强制使用https,false:不校验https证书
	keepAlived bool
	transport  http.Transport
}

func NewClient() *Client {
	return &Client{
		method:     "GET",
		cookies:    make(map[string]string),
		headers:    make(map[string]string),
		verifySsl:  false,
		keepAlived: true,
	}
}

//构造request body [interface{} -> io.Reader]
func parseBody(v interface{}) (io.Reader, error) {
	if v == nil {
		return nil, nil
	}
	bts, err := Bytes(v)
	if err != nil {
		return nil, err
	}
	body := bytes.NewBuffer(bts)
	return body, nil
}

func (self *Client) newRequest() (*http.Request, error) {
	u, err := self.newURL()
	if err != nil {
		return nil, err
	}

	body, err := parseBody(self.body)
	if err != nil {
		return nil, err
	}

	req, err := NewRequest(self.method, u.String(), body)
	for k, v := range self.headers {
		req.Header.Set(k, v)
	}
	for k, v := range self.cookies {
		req.AddCookie(&http.Cookie{Name: k, Value: v})
	}
	return req.Request, err
}

func (self *Client) setClient() (*http.Client, error) {
	if self.proxy != "" {
		proxy, err := url.Parse(self.proxy)
		if err != nil {
			return nil, err
		}
		self.transport.Proxy = http.ProxyURL(proxy)
	}
	self.transport.DisableKeepAlives = !self.keepAlived
	self.transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: !self.verifySsl}
	client := &http.Client{Transport: &self.transport}
	client.Timeout = time.Duration(self.timeout) * time.Second
	return client, nil
}

func (self *Client) Reset() *Client {
	self.method = "GET"
	self.url = ""
	self.path = ""
	self.query = ""
	self.fragment = ""
	self.cookies = make(map[string]string)
	self.headers = make(map[string]string)
	self.body = nil
	self.proxy = ""
	self.timeout = 0
	self.retries = 0
	self.verifySsl = false
	self.keepAlived = true
	self.transport = http.Transport{}
	return self
}

func (self *Client) doReq(method string) (*Response, error) {
	self.method = method
	req, err := self.newRequest()
	if err != nil {
		return nil, err
	}

	client, err := self.setClient()
	if err != nil {
		return nil, err
	}

	resp, err := client.Do(req)
	return &Response{resp}, err
}

// 长连接,Default is true
func (self *Client) KeepAlived(used bool) *Client {
	self.keepAlived = used
	return self
}

// 强制使用HTTPS,Default is false
func (self *Client) VerifySSL(used bool) *Client {
	self.verifySsl = used
	return self
}

func (self *Client) URL(urlstr string) *Client {
	self.url = urlstr
	return self
}

func (self *Client) Path(path string) *Client {
	self.path = path
	return self
}

func (self *Client) Proxy(proxy string) *Client {
	self.proxy = proxy
	return self
}

func (self *Client) Timeout(timeout int) *Client {
	self.timeout = timeout
	return self
}

func (self *Client) Cookie(k, v string) *Client {
	self.cookies[k] = v
	return self
}

func (self *Client) Header(k, v string) *Client {
	self.headers[k] = v
	return self
}

func (self *Client) Headers(kv map[string]string) *Client {
	for k, v := range kv {
		self.Header(k, v)
	}
	return self
}

func (self *Client) Body(body interface{}) *Client {
	self.body = body
	return self
}

func (self *Client) Retries(count int) *Client {
	self.retries = count
	return self
}

func (self *Client) newURL() (*url.URL, error) {
	u, err := url.Parse(self.url)
	if err != nil {
		return u, err
	}
	if self.path != "" {
		u.Path = self.path
	}
	if self.path != "" {
		u.RawQuery = self.query
	}
	return u, err
}

func (self *Client) Get() (*Response, error)  { return self.doReq("GET") }
func (self *Client) Post() (*Response, error) { return self.doReq("POST") }
func (self *Client) Head() (*Response, error) { return self.doReq("HEAD") }
func (self *Client) Put() (*Response, error)  { return self.doReq("PUT") }
<commit_msg>Fix client.go query contains<commit_after>package gohttp

import (
	"bytes"
	"crypto/tls"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

type Request struct {
	*http.Request
}

func (self *Request) SetHeader(k, v string) *Request {
	self.Header.Add(k, v)
	return self
}

func (self *Request) Headers(kv map[string]string) *Request {
	for k, v := range kv {
		self.SetHeader(k, v)
	}
	return self
}

type Response struct {
	*http.Response
}

func (self *Response) Code() int {
	return self.StatusCode
}

func (self *Response) Bytes() ([]byte, error) {
	return ioutil.ReadAll(self.Body)
}

func (self *Response) String() string {
	if resp, err := self.Bytes(); err != nil {
		return ""
	} else {
		return string(resp)
	}

}

func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
	req, err := http.NewRequest(method, url.QueryEscape(urlStr), body)
	return &Request{req}, err
}

type Client struct {
	method     string
	url        string
	path       string
	query      string
	fragment   string
	cookies    map[string]string
	headers    map[string]string
	body       interface{}
	proxy      string
	timeout    int
	retries    int
	verifySsl  bool //true:强制使用https,false:不校验https证书
	keepAlived bool
	transport  http.Transport
}

func NewClient() *Client {
	return &Client{
		method:     "GET",
		cookies:    make(map[string]string),
		headers:    make(map[string]string),
		verifySsl:  false,
		keepAlived: true,
	}
}

//构造request body [interface{} -> io.Reader]
func parseBody(v interface{}) (io.Reader, error) {
	if v == nil {
		return nil, nil
	}
	bts, err := Bytes(v)
	if err != nil {
		return nil, err
	}
	body := bytes.NewBuffer(bts)
	return body, nil
}

func (self *Client) newRequest() (*http.Request, error) {
	u, err := self.newURL()
	if err != nil {
		return nil, err
	}

	body, err := parseBody(self.body)
	if err != nil {
		return nil, err
	}

	req, err := NewRequest(self.method, u.String(), body)
	for k, v := range self.headers {
		req.Header.Set(k, v)
	}
	for k, v := range self.cookies {
		req.AddCookie(&http.Cookie{Name: k, Value: v})
	}
	return req.Request, err
}

func (self *Client) setClient() (*http.Client, error) {
	if self.proxy != "" {
		proxy, err := url.Parse(self.proxy)
		if err != nil {
			return nil, err
		}
		self.transport.Proxy = http.ProxyURL(proxy)
	}
	self.transport.DisableKeepAlives = !self.keepAlived
	self.transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: !self.verifySsl}
	client := &http.Client{Transport: &self.transport}
	client.Timeout = time.Duration(self.timeout) * time.Second
	return client, nil
}

func (self *Client) Reset() *Client {
	self.method = "GET"
	self.url = ""
	self.path = ""
	self.query = ""
	self.fragment = ""
	self.cookies = make(map[string]string)
	self.headers = make(map[string]string)
	self.body = nil
	self.proxy = ""
	self.timeout = 0
	self.retries = 0
	self.verifySsl = false
	self.keepAlived = true
	self.transport = http.Transport{}
	return self
}

func (self *Client) doReq(method string) (*Response, error) {
	self.method = method
	req, err := self.newRequest()
	if err != nil {
		return nil, err
	}

	client, err := self.setClient()
	if err != nil {
		return nil, err
	}

	resp, err := client.Do(req)
	return &Response{resp}, err
}

// 长连接,Default is true
func (self *Client) KeepAlived(used bool) *Client {
	self.keepAlived = used
	return self
}

// 强制使用HTTPS,Default is false
func (self *Client) VerifySSL(used bool) *Client {
	self.verifySsl = used
	return self
}

func (self *Client) URL(urlstr string) *Client {
	self.url = urlstr
	return self
}

func (self *Client) Path(path string) *Client {
	self.path = path
	return self
}

func (self *Client) Proxy(proxy string) *Client {
	self.proxy = proxy
	return self
}

func (self *Client) Timeout(timeout int) *Client {
	self.timeout = timeout
	return self
}

func (self *Client) Cookie(k, v string) *Client {
	self.cookies[k] = v
	return self
}

func (self *Client) Header(k, v string) *Client {
	self.headers[k] = v
	return self
}

func (self *Client) Headers(kv map[string]string) *Client {
	for k, v := range kv {
		self.Header(k, v)
	}
	return self
}

func (self *Client) Body(body interface{}) *Client {
	self.body = body
	return self
}

func (self *Client) Retries(count int) *Client {
	self.retries = count
	return self
}

func (self *Client) newURL() (*url.URL, error) {
	u, err := url.Parse(self.url)
	if err != nil {
		return u, err
	}
	if self.path != "" {
		u.Path = self.path
	}
	if self.query != "" {
		u.RawQuery = self.query
	}
	return u, err
}

func (self *Client) Get() (*Response, error)  { return self.doReq("GET") }
func (self *Client) Post() (*Response, error) { return self.doReq("POST") }
func (self *Client) Head() (*Response, error) { return self.doReq("HEAD") }
func (self *Client) Put() (*Response, error)  { return self.doReq("PUT") }
<|endoftext|>


<commit_before>// Package mktmpio provides easy access to the database servier provisioning
// services at https://mktmp.io/
package mktmpio

import (
	"encoding/json"
	"errors"
	"golang.org/x/net/websocket"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

// Client provides authenticated API access for creating, listing, and destorying
// database servers.
type Client struct {
	token     string
	url       string
	UserAgent string
}

// NewClient creates a mktmpio Client using credentials loaded from the user
// config stored in ~/.mktmpio.yml
func NewClient(cfg *Config) (*Client, error) {
	client := &Client{
		token:     cfg.Token,
		url:       cfg.URL,
		UserAgent: "go-mktmpio",
	}
	if client.url == "" {
		client.url = MktmpioURL
	}
	return client, nil
}

// Create creates a server of the type specified by `service`.
func (c Client) jsonRequest(method, path string, instance *Instance) error {
	reqURL := c.url + path
	req, _ := http.NewRequest(method, reqURL, nil)
	req.Header.Set("Accept", "application/json")
	req.Header.Set("User-Agent", c.UserAgent)
	req.Header.Set("X-Auth-Token", c.token)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if instance != nil {
		return json.Unmarshal(body, instance)
	}
	return nil
}

// Create creates a server of the type specified by `service`.
func (c Client) Create(service string) (*Instance, error) {
	instance := &Instance{client: c}
	reqURL := "/new/" + service
	if err := c.jsonRequest("POST", reqURL, instance); err != nil {
		return nil, err
	}
	if len(instance.Error) > 0 {
		return nil, errors.New(instance.Error)
	}
	return instance, nil
}

// Destroy shuts down and deletes the server identified by `id`.
func (c Client) Destroy(id string) error {
	path := "/i/" + id
	return c.jsonRequest("DELETE", path, nil)
}

// Attach creates a remote shell for the instance identified by `id` and then
// returns a Reader and a Writer for communicating with it.
func (c Client) Attach(id string) (io.ReadWriteCloser, error) {
	wsURL, err := url.Parse(c.url)
	if err != nil {
		return nil, err
	}
	if wsURL.Scheme == "https" {
		wsURL.Scheme = "wss"
		wsURL.Host = "mktmp.io:8443"
	} else {
		wsURL.Scheme = "ws"
	}
	wsURL.Path = "/ws"
	wsURL.RawQuery = "id=" + id
	cfg, err := websocket.NewConfig(wsURL.String(), "http://localhost/")
	if err != nil {
		return nil, err
	}
	cfg.Header.Set("Accept", "application/json")
	cfg.Header.Set("User-Agent", "go-mktmpio")
	cfg.Header.Set("X-Auth-Token", c.token)
	return websocket.DialConfig(cfg)
}
<commit_msg>fix certificate error on go-1.2<commit_after>// Package mktmpio provides easy access to the database servier provisioning
// services at https://mktmp.io/
package mktmpio

import (
	"encoding/json"
	"errors"
	"golang.org/x/net/websocket"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

// go-1.2 does not automatically load SHA2-384, which is what parts of
// mktmp.io's cert chain use.
// See also: http://bridge.grumpy-troll.org/2014/05/golang-tls-comodo/
import _ "crypto/sha512" // side-effect only

// Client provides authenticated API access for creating, listing, and destorying
// database servers.
type Client struct {
	token     string
	url       string
	UserAgent string
}

// NewClient creates a mktmpio Client using credentials loaded from the user
// config stored in ~/.mktmpio.yml
func NewClient(cfg *Config) (*Client, error) {
	client := &Client{
		token:     cfg.Token,
		url:       cfg.URL,
		UserAgent: "go-mktmpio",
	}
	if client.url == "" {
		client.url = MktmpioURL
	}
	return client, nil
}

// Create creates a server of the type specified by `service`.
func (c Client) jsonRequest(method, path string, instance *Instance) error {
	reqURL := c.url + path
	req, _ := http.NewRequest(method, reqURL, nil)
	req.Header.Set("Accept", "application/json")
	req.Header.Set("User-Agent", c.UserAgent)
	req.Header.Set("X-Auth-Token", c.token)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if instance != nil {
		return json.Unmarshal(body, instance)
	}
	return nil
}

// Create creates a server of the type specified by `service`.
func (c Client) Create(service string) (*Instance, error) {
	instance := &Instance{client: c}
	reqURL := "/new/" + service
	if err := c.jsonRequest("POST", reqURL, instance); err != nil {
		return nil, err
	}
	if len(instance.Error) > 0 {
		return nil, errors.New(instance.Error)
	}
	return instance, nil
}

// Destroy shuts down and deletes the server identified by `id`.
func (c Client) Destroy(id string) error {
	path := "/i/" + id
	return c.jsonRequest("DELETE", path, nil)
}

// Attach creates a remote shell for the instance identified by `id` and then
// returns a Reader and a Writer for communicating with it.
func (c Client) Attach(id string) (io.ReadWriteCloser, error) {
	wsURL, err := url.Parse(c.url)
	if err != nil {
		return nil, err
	}
	if wsURL.Scheme == "https" {
		wsURL.Scheme = "wss"
		wsURL.Host = "mktmp.io:8443"
	} else {
		wsURL.Scheme = "ws"
	}
	wsURL.Path = "/ws"
	wsURL.RawQuery = "id=" + id
	cfg, err := websocket.NewConfig(wsURL.String(), "http://localhost/")
	if err != nil {
		return nil, err
	}
	cfg.Header.Set("Accept", "application/json")
	cfg.Header.Set("User-Agent", "go-mktmpio")
	cfg.Header.Set("X-Auth-Token", c.token)
	return websocket.DialConfig(cfg)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.

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.
*/
// this code is copy from https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go
package gowbem

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/http/httputil"
	"net/url"
	"strconv"
	"sync/atomic"
)

type HasFault interface {
	Fault() error
}

type DecodeError struct {
	bytes []byte
	err   error
}

func (f *DecodeError) Error() string {
	return f.err.Error() + ", xml as follow:\r\n" + string(f.bytes)
}

type FaultError struct {
	bytes []byte
	err   error
}

func (f *FaultError) Error() string {
	return f.err.Error() + ", xml as follow:\r\n" + string(f.bytes)
}

type RoundTripper interface {
	RoundTrip(action string, reqBody interface{}, resBody HasFault, cached *bytes.Buffer) error
}

var cn uint64 // Client counter

type Client struct {
	rn uint64 // Request counter

	http.Client

	u           url.URL
	insecure    bool
	contentType string

	cn_str string // Client counter
	cn     uint64 // Client counter
	cached *bytes.Buffer
}

func NewClient(u *url.URL, insecure bool) *Client {
	c := &Client{}
	c.init(u, insecure)
	return c
}

func (c *Client) init(u *url.URL, insecure bool) {
	c.u = *u
	c.insecure = insecure
	c.cn = atomic.AddUint64(&cn, 1)
	c.rn = 0
	c.cached = bytes.NewBuffer(make([]byte, 0, 8*1024*1024))

	c.cn_str = strconv.FormatUint(c.cn, 10)

	if c.u.Scheme == "https" {
		c.Client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: c.insecure}}
	}

	c.Jar, _ = cookiejar.New(nil)
	//c.u.User = nil
}

func (c *Client) generateId() string {
	return c.cn_str + "-" + GenerateId()
}

func (c *Client) URL() url.URL {
	return c.u
}

type marshaledClient struct {
	Cookies  []*http.Cookie
	URL      *url.URL
	Insecure bool
}

func (c *Client) MarshalJSON() ([]byte, error) {
	m := marshaledClient{
		Cookies:  c.Jar.Cookies(&c.u),
		URL:      &c.u,
		Insecure: c.insecure,
	}

	return json.Marshal(m)
}

func (c *Client) UnmarshalJSON(b []byte) error {
	var m marshaledClient

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

	*c = *NewClient(m.URL, m.Insecure)
	c.Jar.SetCookies(m.URL, m.Cookies)
	return nil
}

func (c *Client) RoundTrip(ctx context.Context, action string, headers map[string]string, reqBody interface{}, resBody HasFault) error {
	err := c.roundTrip(ctx, action, headers, reqBody, resBody)
	if err != nil && c.rn <= 1 {
		if c.contentType == "" {
			if headers == nil {
				headers = map[string]string{
					`Content-Type`: `text/xml; charset="utf-8"`,
				}
			} else {
				headers[`Content-Type`] = `text/xml; charset="utf-8"`
			}

			e := c.roundTrip(ctx, action, headers, reqBody, resBody)
			if e == nil {
				c.contentType = `text/xml; charset="utf-8"`
				return nil
			}
		}
	}
	return err
}

func (c *Client) roundTrip(ctx context.Context, action string, headers map[string]string, reqBody interface{}, resBody HasFault) error {
	var httpreq *http.Request
	var httpres *http.Response
	var dumpWriter io.WriteCloser
	var err error

	num := atomic.AddUint64(&c.rn, 1)
	c.cached.Reset()

	c.cached.WriteString(xml.Header)

	if err = xml.NewEncoder(c.cached).Encode(reqBody); err != nil {
		panic(err)
	}
	rawreqbody := c.cached

	httpreq, err = http.NewRequest(action, c.u.String(), rawreqbody)
	if err != nil {
		panic(err)
	}
	if ctx != nil {
		httpreq = httpreq.WithContext(ctx)
	}

	//if pwd, ok := c.u.User.Password(); ok {
	//	httpreq.SetBasicAuth(c.u.User.Username(), pwd)
	//}

	//httpreq.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
	if c.contentType == "" {
		httpreq.Header.Set(`Content-Type`, `application/xml; charset="utf-8"`)
	} else {
		httpreq.Header.Set(`Content-Type`, c.contentType)
	}
	if 0 != len(headers) {
		for k, v := range headers {
			httpreq.Header.Set(k, v)
		}
	}

	if DebugEnabled() {
		b, _ := httputil.DumpRequest(httpreq, false)
		dumpWriter = DebugNewFile(fmt.Sprintf("%d-%04d.log", c.cn, num))
		defer dumpWriter.Close()
		dumpWriter.Write(b)
		dumpWriter.Write(c.cached.Bytes())
	}

	//tstart := time.Now()
	httpres, err = c.Client.Do(httpreq)
	//tstop := time.Now()

	// if DebugEnabled() {
	// 	now := time.Now().Format("2006-01-02T15-04-05.999999999")
	// 	ms := tstop.Sub(tstart) / time.Millisecond
	// 	fmt.Fprintf(c.log, "%s: %4d took %6dms\n", now, num, ms)
	// }

	if err != nil {
		if DebugEnabled() {
			dumpWriter.Write([]byte("\r\n"))
			dumpWriter.Write([]byte(err.Error()))
		}

		return err
	}

	//var rawresbody io.Reader = httpres.Body
	defer httpres.Body.Close()

	if httpres.ContentLength <= 0 && (httpres.StatusCode < http.StatusOK || httpres.StatusCode >= http.StatusMultipleChoices) {

		if DebugEnabled() {
			b, _ := httputil.DumpResponse(httpres, false)
			dumpWriter.Write([]byte("\r\n"))
			dumpWriter.Write(b)
			dumpWriter.Write(c.cached.Bytes())
		}

		// 修复 pg 导到一个问题， 当pg出错时返回错误响应时，没有 ContentLength， tcp 连接也不关闭。
		// 这时读 httpres.Body 时会导致本方法挂起。
		// This is Pegasus bug, pegasus will return a error response that http version is 1.0 and ContentLength is missing.
		// And tcp connection isn't disconnect by the pegasus server.
		cimError := httpres.Header.Get("CIMError")
		errorDetail := httpres.Header.Get("PGErrorDetail")
		if "" == cimError {
			if "" != errorDetail {
				return errors.New(errorDetail)
			}
			return errors.New(httpres.Status)
		} else {
			if "" != errorDetail {
				return errors.New(cimError + ": " + errorDetail)
			}
			return errors.New(cimError)
		}
	}

	c.cached.Reset()
	if _, err = io.Copy(c.cached, httpres.Body); nil != err {
		return err
	}

	if DebugEnabled() {
		b, _ := httputil.DumpResponse(httpres, false)
		dumpWriter.Write([]byte("\r\n"))
		dumpWriter.Write(b)
		dumpWriter.Write(c.cached.Bytes())
	}

	if 200 != httpres.StatusCode {
		if 0 == c.cached.Len() {
			return errors.New(httpres.Status)
		}
		return errors.New(httpres.Status + ":" + c.cached.String())
	}

	dec := xml.NewDecoder(bytes.NewReader(c.cached.Bytes()))
	err = dec.Decode(resBody)
	if err != nil {
		return &DecodeError{bytes: c.cached.Bytes(), err: err}
	}

	if fault := resBody.Fault(); fault != nil {
		return &FaultError{bytes: c.cached.Bytes(), err: fault}
	}

	return nil
}

func StringsWith(instance CIMInstance, key string, defaultVlaue []string) []string {
	prop := instance.GetPropertyByName(key)
	if prop == nil {
		return defaultVlaue
	}
	value := prop.GetValue()
	if value == nil {
		return defaultVlaue
	}
	switch vv := value.(type) {
	case []string:
		return vv
	case []interface{}:
		var ss = make([]string, 0, len(vv))
		for _, v := range vv {
			ss = append(ss, fmt.Sprint(v))
		}
		return ss
	default:
		panic(fmt.Sprintf("[wbem] value isn't a array - %T %#v.", value, value))
	}
}
<commit_msg>add content-type support<commit_after>/*
Copyright (c) 2015 VMware, Inc. All Rights Reserved.

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.
*/
// this code is copy from https://github.com/vmware/govmomi/blob/master/vim25/soap/client.go
package gowbem

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/http/httputil"
	"net/url"
	"strconv"
	"sync/atomic"
)

type HasFault interface {
	Fault() error
}

type DecodeError struct {
	bytes []byte
	err   error
}

func (f *DecodeError) Error() string {
	return f.err.Error() + ", xml as follow:\r\n" + string(f.bytes)
}

type FaultError struct {
	bytes []byte
	err   error
}

func (f *FaultError) Error() string {
	return f.err.Error() + ", xml as follow:\r\n" + string(f.bytes)
}

type RoundTripper interface {
	RoundTrip(action string, reqBody interface{}, resBody HasFault, cached *bytes.Buffer) error
}

var cn uint64 // Client counter

type Client struct {
	rn uint64 // Request counter

	http.Client

	u           url.URL
	insecure    bool
	contentType string

	cn_str string // Client counter
	cn     uint64 // Client counter
	cached *bytes.Buffer
}

func NewClient(u *url.URL, insecure bool) *Client {
	c := &Client{}
	c.init(u, insecure)
	return c
}

func (c *Client) init(u *url.URL, insecure bool) {
	c.u = *u
	c.insecure = insecure
	c.cn = atomic.AddUint64(&cn, 1)
	c.rn = 0
	c.cached = bytes.NewBuffer(make([]byte, 0, 8*1024*1024))

	c.cn_str = strconv.FormatUint(c.cn, 10)

	if c.u.Scheme == "https" {
		c.Client.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: c.insecure}}
	}

	c.Jar, _ = cookiejar.New(nil)
	//c.u.User = nil
}

func (c *Client) generateId() string {
	return c.cn_str + "-" + GenerateId()
}

func (c *Client) URL() url.URL {
	return c.u
}

type marshaledClient struct {
	Cookies  []*http.Cookie
	URL      *url.URL
	Insecure bool
}

func (c *Client) MarshalJSON() ([]byte, error) {
	m := marshaledClient{
		Cookies:  c.Jar.Cookies(&c.u),
		URL:      &c.u,
		Insecure: c.insecure,
	}

	return json.Marshal(m)
}

func (c *Client) UnmarshalJSON(b []byte) error {
	var m marshaledClient

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

	*c = *NewClient(m.URL, m.Insecure)
	c.Jar.SetCookies(m.URL, m.Cookies)
	return nil
}

func (c *Client) RoundTrip(ctx context.Context, action string, headers map[string]string, reqBody interface{}, resBody HasFault) error {
	err := c.roundTrip(ctx, action, headers, reqBody, resBody)
	if err != nil && atomic.LoadUint64(&c.rn) <= 1 {
		if c.contentType == "" {
			if headers == nil {
				headers = map[string]string{
					`Content-Type`: `text/xml; charset="utf-8"`,
				}
			} else {
				headers[`Content-Type`] = `text/xml; charset="utf-8"`
			}

			e := c.roundTrip(ctx, action, headers, reqBody, resBody)
			if e == nil {
				c.contentType = `text/xml; charset="utf-8"`
				return nil
			}
		}
	}
	return err
}

func (c *Client) roundTrip(ctx context.Context, action string, headers map[string]string, reqBody interface{}, resBody HasFault) error {
	var httpreq *http.Request
	var httpres *http.Response
	var dumpWriter io.WriteCloser
	var err error

	num := atomic.AddUint64(&c.rn, 1)
	c.cached.Reset()

	c.cached.WriteString(xml.Header)

	if err = xml.NewEncoder(c.cached).Encode(reqBody); err != nil {
		panic(err)
	}
	rawreqbody := c.cached

	httpreq, err = http.NewRequest(action, c.u.String(), rawreqbody)
	if err != nil {
		panic(err)
	}
	if ctx != nil {
		httpreq = httpreq.WithContext(ctx)
	}

	//if pwd, ok := c.u.User.Password(); ok {
	//	httpreq.SetBasicAuth(c.u.User.Username(), pwd)
	//}

	//httpreq.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
	if c.contentType == "" {
		httpreq.Header.Set(`Content-Type`, `application/xml; charset="utf-8"`)
	} else {
		httpreq.Header.Set(`Content-Type`, c.contentType)
	}
	if 0 != len(headers) {
		for k, v := range headers {
			httpreq.Header.Set(k, v)
		}
	}

	if DebugEnabled() {
		b, _ := httputil.DumpRequest(httpreq, false)
		dumpWriter = DebugNewFile(fmt.Sprintf("%d-%04d.log", c.cn, num))
		defer dumpWriter.Close()
		dumpWriter.Write(b)
		dumpWriter.Write(c.cached.Bytes())
	}

	//tstart := time.Now()
	httpres, err = c.Client.Do(httpreq)
	//tstop := time.Now()

	// if DebugEnabled() {
	// 	now := time.Now().Format("2006-01-02T15-04-05.999999999")
	// 	ms := tstop.Sub(tstart) / time.Millisecond
	// 	fmt.Fprintf(c.log, "%s: %4d took %6dms\n", now, num, ms)
	// }

	if err != nil {
		if DebugEnabled() {
			dumpWriter.Write([]byte("\r\n"))
			dumpWriter.Write([]byte(err.Error()))
		}

		return err
	}

	//var rawresbody io.Reader = httpres.Body
	defer httpres.Body.Close()

	if httpres.ContentLength <= 0 && (httpres.StatusCode < http.StatusOK || httpres.StatusCode >= http.StatusMultipleChoices) {

		if DebugEnabled() {
			b, _ := httputil.DumpResponse(httpres, false)
			dumpWriter.Write([]byte("\r\n"))
			dumpWriter.Write(b)
			dumpWriter.Write(c.cached.Bytes())
		}

		// 修复 pg 导到一个问题， 当pg出错时返回错误响应时，没有 ContentLength， tcp 连接也不关闭。
		// 这时读 httpres.Body 时会导致本方法挂起。
		// This is Pegasus bug, pegasus will return a error response that http version is 1.0 and ContentLength is missing.
		// And tcp connection isn't disconnect by the pegasus server.
		cimError := httpres.Header.Get("CIMError")
		errorDetail := httpres.Header.Get("PGErrorDetail")
		if "" == cimError {
			if "" != errorDetail {
				return errors.New(errorDetail)
			}
			return errors.New(httpres.Status)
		} else {
			if "" != errorDetail {
				return errors.New(cimError + ": " + errorDetail)
			}
			return errors.New(cimError)
		}
	}

	c.cached.Reset()
	if _, err = io.Copy(c.cached, httpres.Body); nil != err {
		return err
	}

	if DebugEnabled() {
		b, _ := httputil.DumpResponse(httpres, false)
		dumpWriter.Write([]byte("\r\n"))
		dumpWriter.Write(b)
		dumpWriter.Write(c.cached.Bytes())
	}

	if 200 != httpres.StatusCode {
		if 0 == c.cached.Len() {
			return errors.New(httpres.Status)
		}
		return errors.New(httpres.Status + ":" + c.cached.String())
	}

	dec := xml.NewDecoder(bytes.NewReader(c.cached.Bytes()))
	err = dec.Decode(resBody)
	if err != nil {
		return &DecodeError{bytes: c.cached.Bytes(), err: err}
	}

	if fault := resBody.Fault(); fault != nil {
		return &FaultError{bytes: c.cached.Bytes(), err: fault}
	}

	return nil
}

func StringsWith(instance CIMInstance, key string, defaultVlaue []string) []string {
	prop := instance.GetPropertyByName(key)
	if prop == nil {
		return defaultVlaue
	}
	value := prop.GetValue()
	if value == nil {
		return defaultVlaue
	}
	switch vv := value.(type) {
	case []string:
		return vv
	case []interface{}:
		var ss = make([]string, 0, len(vv))
		for _, v := range vv {
			ss = append(ss, fmt.Sprint(v))
		}
		return ss
	default:
		panic(fmt.Sprintf("[wbem] value isn't a array - %T %#v.", value, value))
	}
}
<|endoftext|>


<commit_before>package gandalf

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

type Client struct {
	Endpoint string
}

// repository represents a git repository.
type repository struct {
	Name     string   `json:"name"`
	Users    []string `json:"users"`
	IsPublic bool     `json:"ispublic"`
}

// repository represents a git user.
type user struct {
	Name string            `json:"name"`
	Keys map[string]string `json:"keys"`
}

type httpError struct {
	code int
	reason string
}

func (e *httpError) Error() string {
	return e.reason
}

func (c *Client) doRequest(method, path string, body io.Reader) (*http.Response, error) {
	request, err := http.NewRequest(method, c.Endpoint+path, body)
	if err != nil {
		return nil, err
	}
	if body != nil {
		request.Header.Set("Content-Type", "application/json")
	}
	response, err := (&http.Client{}).Do(request)
	if err != nil {
		return response, err
	}
	return response, nil
}

func (c *Client) formatBody(b interface{}) (*bytes.Buffer, error) {
	body := bytes.NewBufferString("null")
	if b != nil {
		j, err := json.Marshal(&b)
		if err != nil {
			return body, err
		}
		body = bytes.NewBuffer(j)
	}
	return body, nil
}

func (c *Client) post(b interface{}, path string) error {
	body, err := c.formatBody(b)
	if err != nil {
		return err
	}
	response, err := c.doRequest("POST", path, body)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return nil
}

func (c *Client) delete(b interface{}, path string) error {
	body, err := c.formatBody(b)
	if err != nil {
		return err
	}
	response, err := c.doRequest("DELETE", path, body)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return err
}

func (c *Client) get(path string) error {
	response, err := c.doRequest("GET", path, nil)
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return err
}

// NewRepository creates a new repository with a given name and,
// grants access to a list of users
// and defines whether the repository is public.
func (c *Client) NewRepository(name string, users []string, isPublic bool) (repository, error) {
	r := repository{Name: name, Users: users, IsPublic: isPublic}
	if err := c.post(r, "/repository"); err != nil {
		return repository{}, err
	}
	return r, nil
}

// NewUser creates a new user with her/his given keys.
func (c *Client) NewUser(name string, keys map[string]string) (user, error) {
	u := user{Name: name, Keys: keys}
	if err := c.post(u, "/user"); err != nil {
		return user{}, err
	}
	return u, nil
}

// RemoveUser removes a user.
func (c *Client) RemoveUser(name string) error {
	return c.delete(nil, "/user/"+name)
}

// RemoveRepository removes a repository.
func (c *Client) RemoveRepository(name string) error {
	return c.delete(nil, "/repository/"+name)
}

// GrantAccess grants access to N users into N repositories.
func (c *Client) GrantAccess(rNames, uNames []string) error {
	b := map[string][]string{"repositories": rNames, "users": uNames}
	return c.post(b, "/repository/grant")
}

// RevokeAccess revokes access from N users from N repositories.
func (c *Client) RevokeAccess(rNames, uNames []string) error {
	b := map[string][]string{"repositories": rNames, "users": uNames}
	return c.delete(b, "/repository/revoke")
}

// AddKey adds keys to the user.
func (c *Client) AddKey(uName string, key map[string]string) error {
	url := fmt.Sprintf("/user/%s/key", uName)
	return c.post(key, url)
}

// RemoveKey removes the key from the user.
func (c *Client) RemoveKey(uName, kName string) error {
	url := fmt.Sprintf("/user/%s/key/%s", uName, kName)
	return c.delete(nil, url)
}
<commit_msg>all: gofmt -s -w .<commit_after>package gandalf

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

type Client struct {
	Endpoint string
}

// repository represents a git repository.
type repository struct {
	Name     string   `json:"name"`
	Users    []string `json:"users"`
	IsPublic bool     `json:"ispublic"`
}

// repository represents a git user.
type user struct {
	Name string            `json:"name"`
	Keys map[string]string `json:"keys"`
}

type httpError struct {
	code   int
	reason string
}

func (e *httpError) Error() string {
	return e.reason
}

func (c *Client) doRequest(method, path string, body io.Reader) (*http.Response, error) {
	request, err := http.NewRequest(method, c.Endpoint+path, body)
	if err != nil {
		return nil, err
	}
	if body != nil {
		request.Header.Set("Content-Type", "application/json")
	}
	response, err := (&http.Client{}).Do(request)
	if err != nil {
		return response, err
	}
	return response, nil
}

func (c *Client) formatBody(b interface{}) (*bytes.Buffer, error) {
	body := bytes.NewBufferString("null")
	if b != nil {
		j, err := json.Marshal(&b)
		if err != nil {
			return body, err
		}
		body = bytes.NewBuffer(j)
	}
	return body, nil
}

func (c *Client) post(b interface{}, path string) error {
	body, err := c.formatBody(b)
	if err != nil {
		return err
	}
	response, err := c.doRequest("POST", path, body)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return nil
}

func (c *Client) delete(b interface{}, path string) error {
	body, err := c.formatBody(b)
	if err != nil {
		return err
	}
	response, err := c.doRequest("DELETE", path, body)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return err
}

func (c *Client) get(path string) error {
	response, err := c.doRequest("GET", path, nil)
	if response.StatusCode != 200 {
		b, _ := ioutil.ReadAll(response.Body)
		return &httpError{code: response.StatusCode, reason: string(b)}
	}
	return err
}

// NewRepository creates a new repository with a given name and,
// grants access to a list of users
// and defines whether the repository is public.
func (c *Client) NewRepository(name string, users []string, isPublic bool) (repository, error) {
	r := repository{Name: name, Users: users, IsPublic: isPublic}
	if err := c.post(r, "/repository"); err != nil {
		return repository{}, err
	}
	return r, nil
}

// NewUser creates a new user with her/his given keys.
func (c *Client) NewUser(name string, keys map[string]string) (user, error) {
	u := user{Name: name, Keys: keys}
	if err := c.post(u, "/user"); err != nil {
		return user{}, err
	}
	return u, nil
}

// RemoveUser removes a user.
func (c *Client) RemoveUser(name string) error {
	return c.delete(nil, "/user/"+name)
}

// RemoveRepository removes a repository.
func (c *Client) RemoveRepository(name string) error {
	return c.delete(nil, "/repository/"+name)
}

// GrantAccess grants access to N users into N repositories.
func (c *Client) GrantAccess(rNames, uNames []string) error {
	b := map[string][]string{"repositories": rNames, "users": uNames}
	return c.post(b, "/repository/grant")
}

// RevokeAccess revokes access from N users from N repositories.
func (c *Client) RevokeAccess(rNames, uNames []string) error {
	b := map[string][]string{"repositories": rNames, "users": uNames}
	return c.delete(b, "/repository/revoke")
}

// AddKey adds keys to the user.
func (c *Client) AddKey(uName string, key map[string]string) error {
	url := fmt.Sprintf("/user/%s/key", uName)
	return c.post(key, url)
}

// RemoveKey removes the key from the user.
func (c *Client) RemoveKey(uName, kName string) error {
	url := fmt.Sprintf("/user/%s/key/%s", uName, kName)
	return c.delete(nil, url)
}
<|endoftext|>


<commit_before>package keen

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	baseUrl = "https://api.keen.io/3.0/projects/"
)

type KeenProperties struct {
	Timestamp string `json: "timestamp"`
}

// Timestamp formats a time.Time object in the ISO-8601 format keen expects
func Timestamp(t time.Time) string {
	return t.UTC().Format("2006-01-02T15:04:05.000Z")
}

type Client struct {
	ApiKey       string
	ProjectToken string
	HttpClient   http.Client
}

func (c *Client) AddEvent(collection string, event interface{}) error {
	resp, err := c.request("POST", fmt.Sprintf("/events/%s", collection), event)
	if err != nil {
		return err
	}

	return c.respToError(resp)
}

func (c *Client) AddEvents(events map[string][]interface{}) error {
	resp, err := c.request("POST", "/events", events)
	if err != nil {
		return err
	}

	return c.respToError(resp)
}

func (c *Client) respToError(resp *http.Response) error {
	defer resp.Body.Close()
	if resp.StatusCode >= 200 || resp.StatusCode < 300 {
		return nil
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	return fmt.Errorf("Non 200 reply from keen.io: %s", data)
}

func (c *Client) request(method, path string, payload interface{}) (*http.Response, error) {
	// serialize payload
	body, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	// construct url
	url := baseUrl + c.ProjectToken + path

	// new request
	req, err := http.NewRequest(method, url, bytes.NewReader(body))
	if err != nil {
		return nil, err
	}

	// add auth
	req.Header.Add("Authorization", c.ApiKey)

	// set length/content-type
	if body != nil {
		req.Header.Add("Content-Type", "application/json")
		req.ContentLength = int64(len(body))
	}

	return c.HttpClient.Do(req)
}
<commit_msg>json struct tag is space-sensitive<commit_after>package keen

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	baseUrl = "https://api.keen.io/3.0/projects/"
)

type KeenProperties struct {
	Timestamp string `json:"timestamp"`
}

// Timestamp formats a time.Time object in the ISO-8601 format keen expects
func Timestamp(t time.Time) string {
	return t.UTC().Format("2006-01-02T15:04:05.000Z")
}

type Client struct {
	ApiKey       string
	ProjectToken string
	HttpClient   http.Client
}

func (c *Client) AddEvent(collection string, event interface{}) error {
	resp, err := c.request("POST", fmt.Sprintf("/events/%s", collection), event)
	if err != nil {
		return err
	}

	return c.respToError(resp)
}

func (c *Client) AddEvents(events map[string][]interface{}) error {
	resp, err := c.request("POST", "/events", events)
	if err != nil {
		return err
	}

	return c.respToError(resp)
}

func (c *Client) respToError(resp *http.Response) error {
	defer resp.Body.Close()
	if resp.StatusCode >= 200 || resp.StatusCode < 300 {
		return nil
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	return fmt.Errorf("Non 200 reply from keen.io: %s", data)
}

func (c *Client) request(method, path string, payload interface{}) (*http.Response, error) {
	// serialize payload
	body, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	// construct url
	url := baseUrl + c.ProjectToken + path

	// new request
	req, err := http.NewRequest(method, url, bytes.NewReader(body))
	if err != nil {
		return nil, err
	}

	// add auth
	req.Header.Add("Authorization", c.ApiKey)

	// set length/content-type
	if body != nil {
		req.Header.Add("Content-Type", "application/json")
		req.ContentLength = int64(len(body))
	}

	return c.HttpClient.Do(req)
}
<|endoftext|>


<commit_before>package db

import (
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
)

type Server struct {
	ID                 bson.ObjectId `json:"id" bson:"_id,omitempty"`
	CMDBName           string        `json:"CMDBName"`
	Function           string        `json:"Function"`
	SerialNumber       string        `json:"SerialNumber"`
	AssetCode          string        `json:"Assetcode" `
	HardwareDefinition `json:"Hardwarerows"`
	Localisation       `json:"Localisationrows"`
	Networking         []Networks `json:"Networksrows"`
	Remarks            string     `json:"Remarks"`
	Status             string     `json:"Status"`
}

type HardwareDefinition struct {
	Model string `json:"Model"`
	CPU   string `json:"CPU"`
	RAM   string `json:"RAM"`
}

type Localisation struct {
	Room     string `json:"Room"`
	Building string `json:"Building"`
	Rack     string `json:"Rack"`
}

type Networks struct {
	IpAddr     string `json:"Ipaddr"`
	PatchPanel string `json:"Patchpanel"`
	ServerPort string `json:"Serverport"`
	Switch     string `json:"Switch"`
	Vlan       string `json:"Vlan"`
	MAC        string `json:"MAC"`
}

type Network struct {
	NCMDBName     string `json:"NCMDBName"`
	NFunction     string `json:"NFunction"`
	NSerialNumber string `json:"NSerialNumber"`
	NAssetCode    int    `json:"NAssetCode"`
	NRows         []Localisation
}

type Person struct {
	User     string
	Password string
	Mail     string
}

var db *mgo.Database

func init() {
	session, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}

	db = session.DB("cloudtab")
}

func collection() *mgo.Collection {
	return db.C("items")
}

func GetAll() ([]Server, error) {
	res := []Server{}

	if err := collection().Find(nil).All(&res); err != nil {
		return nil, err
	}

	return res, nil
}

func Save(item Server) error {
	return collection().Insert(item)
}

func Update(key string, item string, values Networks) error {
	// return collection().Remove(bson.M{"_id": bson.ObjectIdHex(id)})
	// db.items.updateOne({cmdbname:"ServerTest99"},{$addToSet:{"networking": [ { "ipaddr" : "abcd", "patchpanel" : "abcd", "serverport" : "abcd", "switch" : "abcd", "vlan" : "abcd", "mac" : "abcdefg" } ]}})
	_, err := collection().Upsert(bson.M{"_id": bson.ObjectIdHex(key)}, bson.M{"$addToSet": bson.M{item: values}})
	fmt.Println(err, key, bson.ObjectIdHex(key), item, values)
	return err
}

func GetOne(id string) (*Server, error) {
	res := Server{}

	if err := collection().Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&res); err != nil {
		return nil, err
	}
	return &res, nil
}

func Remove(id string) error {
	return collection().Remove(bson.M{"_id": bson.ObjectIdHex(id)})
}
<commit_msg>Add update func for adding multiple network<commit_after>package db

import (
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
)

type Server struct {
	ID                 bson.ObjectId `json:"id" bson:"_id,omitempty"`
	CMDBName           string        `json:"CMDBName"`
	Function           string        `json:"Function"`
	SerialNumber       string        `json:"SerialNumber"`
	AssetCode          string        `json:"Assetcode" `
	HardwareDefinition `json:"Hardwarerows"`
	Localisation       `json:"Localisationrows"`
	Networking         []Networks `json:"Networksrows"`
	Remarks            string     `json:"Remarks"`
	Status             string     `json:"Status"`
}

type HardwareDefinition struct {
	Model string `json:"Model"`
	CPU   string `json:"CPU"`
	RAM   string `json:"RAM"`
}

type Localisation struct {
	Room     string `json:"Room"`
	Building string `json:"Building"`
	Rack     string `json:"Rack"`
}

type Networks struct {
	IpAddr     string `json:"Ipaddr"`
	PatchPanel string `json:"Patchpanel"`
	ServerPort string `json:"Serverport"`
	Switch     string `json:"Switch"`
	Vlan       string `json:"Vlan"`
	MAC        string `json:"MAC"`
}

type Network struct {
	NCMDBName     string `json:"NCMDBName"`
	NFunction     string `json:"NFunction"`
	NSerialNumber string `json:"NSerialNumber"`
	NAssetCode    int    `json:"NAssetCode"`
	NRows         []Localisation
}

type Person struct {
	User     string
	Password string
	Mail     string
}

var db *mgo.Database

func init() {
	session, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}

	db = session.DB("cloudtab")
}

func collection() *mgo.Collection {
	return db.C("items")
}

func GetAll() ([]Server, error) {
	res := []Server{}

	if err := collection().Find(nil).All(&res); err != nil {
		return nil, err
	}

	return res, nil
}

func Save(item Server) error {
	return collection().Insert(item)
}

func Update(key string, item string, values Networks) error {
	// Func ONLY available for []network{} collection
	// return collection().Remove(bson.M{"_id": bson.ObjectIdHex(id)})
	// db.items.updateOne({cmdbname:"ServerTest99"},{$addToSet:{"networking": [ { "ipaddr" : "abcd", "patchpanel" : "abcd", "serverport" : "abcd", "switch" : "abcd", "vlan" : "abcd", "mac" : "abcdefg" } ]}})
	_, err := collection().Upsert(bson.M{"_id": bson.ObjectIdHex(key)}, bson.M{"$addToSet": bson.M{item: values}})
	fmt.Println(err, key, bson.ObjectIdHex(key), item, values)
	return err
}

func GetOne(id string) (*Server, error) {
	res := Server{}

	if err := collection().Find(bson.M{"_id": bson.ObjectIdHex(id)}).One(&res); err != nil {
		return nil, err
	}
	return &res, nil
}

func Remove(id string) error {
	return collection().Remove(bson.M{"_id": bson.ObjectIdHex(id)})
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"time"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}

func TimeNowString() string {
	return fmt.Sprintf("%v", time.Unix(0, time.Now().UnixNano()/(int64(time.Millisecond)/int64(time.Nanosecond))*int64(time.Millisecond)))[:23]
}
<commit_msg>Added EscapeLatex<commit_after>package common

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
	"time"
)

func ValidBarcode8(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{8,8}$")
	return re.MatchString(s)
}

func ValidBarcode7(s string) bool {
	re := regexp.MustCompile("^[A-Z0-9]{7,7}$")
	return re.MatchString(s)
}

func ValidCarton20(s string) bool {
	re := regexp.MustCompile("^[0-9]{20,20}$")
	return re.MatchString(s)
}

func ReverseProxy(proxyPort string, pathMap map[string]string) {

	for urlPath, targetPort := range pathMap {
		u, _ := url.Parse("http://127.0.0.1:" + targetPort)
		http.Handle(urlPath, httputil.NewSingleHostReverseProxy(u))
	}

	http.ListenAndServe(":"+proxyPort, nil)

}

func TimeNowString() string {
	return fmt.Sprintf("%v", time.Unix(0, time.Now().UnixNano()/(int64(time.Millisecond)/int64(time.Nanosecond))*int64(time.Millisecond)))[:23]
}

func EscapeLatex(s string) string {
	s2 := strings.Replace(s, "\\", "\\textbackslash", -1)
	s2 = strings.Replace(s2, "&", "\\&", -1)
	s2 = strings.Replace(s2, "%", "\\%", -1)
	s2 = strings.Replace(s2, "$", "\\$", -1)
	s2 = strings.Replace(s2, "#", "\\#", -1)
	s2 = strings.Replace(s2, "_", "\\_", -1)
	s2 = strings.Replace(s2, "", "\\$", -1)
	s2 = strings.Replace(s2, "{", "\\{", -1)
	s2 = strings.Replace(s2, "}", "\\}", -1)
	s2 = strings.Replace(s2, "~", "\\textasciitilde", -1)
	return strings.Replace(s2, "^", "\\textasciicircum", -1)

}
<|endoftext|>


<commit_before>// Copyright 2014 Brian J. Downs
//
// 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 openweathermap

const unitError = "unit unavailable"
const langError = "language unavailable"

var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"}
var (
	baseURL      = "http://api.openweathermap.org/data/2.5/weather?%s"
	iconURL      = "http://openweathermap.org/img/w/%s"
	stationURL   = "http://api.openweathermap.org/data/2.5/station?id=%d"
	forecastBase = "http://api.openweathermap.org/data/2.5/forecast/daily?%s=%s&mode=json&units=%s&lang=%s&cnt=%d"
	historyURL   = "http://api.openweathermap.org/data/2.5/history/%s"
	dataPostURL  = "http://openweathermap.org/data/post"
)

// LangCodes holds all supported languages to be used
// inspried from and sourced from @bambocher (github.com/bambocher)
var LangCodes = map[string]string{
	"EN":    "English",
	"RU":    "Russian",
	"IT":    "Italian",
	"ES":    "Spanish",
	"SP":    "Spanish",
	"UK":    "Ukrainian",
	"UA":    "Ukrainian",
	"DE":    "German",
	"PT":    "Portuguese",
	"RO":    "Romanian",
	"PL":    "Polish",
	"FI":    "Finnish",
	"NL":    "Dutch",
	"FR":    "French",
	"BG":    "Bulgarian",
	"SV":    "Swedish",
	"SE":    "Swedish",
	"TR":    "Turkish",
	"HR":    "Croatian",
	"CA":    "Catalan",
	"ZH_TW": "Chinese Traditional",
	"ZH":    "Chinese Simplified",
	"ZH_CN": "Chinese Simplified",
}

// Config will hold default settings to be passed into the
// "New{current, forecast, etc}" function.
type Config struct {
	Mode     string // User choice of JSON or XML
	Unit     string // F, C, or K
	Lang     string // should reference a key in the LangCodes map
	APIKey   string // API Key for connecting to the OWM
	Username string // Username for posting data
	Password string // Pasword for posting data
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data in returned
// JSON or as parameter data for requests using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request
// and the surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	ID      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   float64 `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	ID          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the temperates, humidity, pressure for the request.
type Main struct {
	Temp       float64 `json:"temp"`
	TempMin    float64 `json:"temp_min"`
	TempMax    float64 `json:"temp_max"`
	Pressure   float64 `json:"pressure"`
	sea_level  float64 `json:"sea_level"`
	grnd_level float64 `json:"grnd_level"`
	Humidity   int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}

// ValidDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
func ValidDataUnit(u string) bool {
	for d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidLangValue makes sure the string passed in is an
// acceptable lang code.
func ValidLangCode(c string) bool {
	for d, _ := range LangCodes {
		if c == d {
			return true
		}
	}
	return false
}

// ValidDataUnitSymbol makes sure the string passed in is an
// acceptable data unit symbol.
func ValidDataUnitSymbol(u string) bool {
	for _, d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// CheckAPIKeyExists will see if an API key has been set.
func (c *Config) CheckAPIKeyExists() bool { return len(c.APIKey) > 1 }
<commit_msg>fix go vet problems<commit_after>// Copyright 2014 Brian J. Downs
//
// 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 openweathermap

const unitError = "unit unavailable"
const langError = "language unavailable"

var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"}
var (
	baseURL      = "http://api.openweathermap.org/data/2.5/weather?%s"
	iconURL      = "http://openweathermap.org/img/w/%s"
	stationURL   = "http://api.openweathermap.org/data/2.5/station?id=%d"
	forecastBase = "http://api.openweathermap.org/data/2.5/forecast/daily?%s=%s&mode=json&units=%s&lang=%s&cnt=%d"
	historyURL   = "http://api.openweathermap.org/data/2.5/history/%s"
	dataPostURL  = "http://openweathermap.org/data/post"
)

// LangCodes holds all supported languages to be used
// inspried from and sourced from @bambocher (github.com/bambocher)
var LangCodes = map[string]string{
	"EN":    "English",
	"RU":    "Russian",
	"IT":    "Italian",
	"ES":    "Spanish",
	"SP":    "Spanish",
	"UK":    "Ukrainian",
	"UA":    "Ukrainian",
	"DE":    "German",
	"PT":    "Portuguese",
	"RO":    "Romanian",
	"PL":    "Polish",
	"FI":    "Finnish",
	"NL":    "Dutch",
	"FR":    "French",
	"BG":    "Bulgarian",
	"SV":    "Swedish",
	"SE":    "Swedish",
	"TR":    "Turkish",
	"HR":    "Croatian",
	"CA":    "Catalan",
	"ZH_TW": "Chinese Traditional",
	"ZH":    "Chinese Simplified",
	"ZH_CN": "Chinese Simplified",
}

// Config will hold default settings to be passed into the
// "New{current, forecast, etc}" function.
type Config struct {
	Mode     string // User choice of JSON or XML
	Unit     string // F, C, or K
	Lang     string // should reference a key in the LangCodes map
	APIKey   string // API Key for connecting to the OWM
	Username string // Username for posting data
	Password string // Pasword for posting data
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data in returned
// JSON or as parameter data for requests using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request
// and the surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	ID      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   float64 `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	ID          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the temperates, humidity, pressure for the request.
type Main struct {
	Temp       float64 `json:"temp"`
	TempMin    float64 `json:"temp_min"`
	TempMax    float64 `json:"temp_max"`
	Pressure   float64 `json:"pressure"`
	Sea_level  float64 `json:"sea_level"`
	Grnd_level float64 `json:"grnd_level"`
	Humidity   int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}

// ValidDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
func ValidDataUnit(u string) bool {
	for d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidLangValue makes sure the string passed in is an
// acceptable lang code.
func ValidLangCode(c string) bool {
	for d, _ := range LangCodes {
		if c == d {
			return true
		}
	}
	return false
}

// ValidDataUnitSymbol makes sure the string passed in is an
// acceptable data unit symbol.
func ValidDataUnitSymbol(u string) bool {
	for _, d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// CheckAPIKeyExists will see if an API key has been set.
func (c *Config) CheckAPIKeyExists() bool { return len(c.APIKey) > 1 }
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
)

var cfgfile string = "./pushovercfg.json"

type GConfig struct {
	Notifications Notifiers
	Watches   []WatchFile
}

type WatchFile struct {
	Path         string
	TriggerWords []string
}

type Notifiers struct {
	PushOver NPushOver
	PushAlot NPushAlot
	Azise NAzise
}

/* Notifiers */
type NPushOver struct {
	UserToken string
	AppToken  string
}

type NPushAlot struct {
	Token string
}

type NAzise struct {
	Secret string
}

func GetDefaultConfig() GConfig {
	var tfg GConfig
	tfg.Watches = make([]WatchFile, 0)
	defaultwatch := WatchFile{
		Path: "/var/log/auth.log",
		TriggerWords: []string{
			"Accepted publickey",
			"Accepted password",
		},
	}
	tfg.Watches = append(tfg.Watches, defaultwatch)

	var nfr Notifiers
	var pusho NPushOver
	var pusha NPushAlot
	var azise NAzise

	pusho.UserToken = "token"
	pusho.AppToken = "token"
	nfr.PushOver = pusho

	pusha.Token = "token"
	nfr.PushAlot = pusha

	azise.Secret = "secret"
	nfr.Azise = azise

	tfg.Notifications = nfr
	return tfg
}

func CheckIfResetConfig(args []string) {
	if len(args) == 2 {
		if args[1] == "reset" {
			e := os.Remove(cfgfile)
			if e != nil {
				log.Fatal("Could not remove current config file. Permissions issue?")
			}
			Default := GetDefaultConfig()
			out, e := json.Marshal(Default)
			e = ioutil.WriteFile(cfgfile, out, 600)
			if e != nil {
				log.Fatal("cannot open settings file :(")
			}
			log.Fatal("Built config file. please fill it in.")
		}
	}
}

func GetCFG() GConfig {
	b, e := ioutil.ReadFile(cfgfile)
	tfg := GetDefaultConfig()
	if e != nil {
		out, e := json.Marshal(tfg)
		e = ioutil.WriteFile(cfgfile, out, 600)
		if e != nil {
			log.Fatal("cannot open settings file :(")
		}
		log.Fatal("Built config file. please fill it in.")
	}

	e = json.Unmarshal(b, &tfg)
	if e != nil {
		log.Fatalf("Could not parse config settings. You may have to remove %s", cfgfile)
	}

	var nfc = tfg.Notifications
	if !CanPushOver(nfc) && !CanPushAlot(nfc) {
		log.Fatalf("Please fill in at least one push service in %s", cfgfile)
	}

	return tfg
}
<commit_msg>Rename config<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"
)

var cfgfile string = "./pushonauthcfg.json"

type GConfig struct {
	Notifications Notifiers
	Watches   []WatchFile
}

type WatchFile struct {
	Path         string
	TriggerWords []string
}

type Notifiers struct {
	PushOver NPushOver
	PushAlot NPushAlot
	Azise NAzise
}

/* Notifiers */
type NPushOver struct {
	UserToken string
	AppToken  string
}

type NPushAlot struct {
	Token string
}

type NAzise struct {
	Secret string
}

func GetDefaultConfig() GConfig {
	var tfg GConfig
	tfg.Watches = make([]WatchFile, 0)
	defaultwatch := WatchFile{
		Path: "/var/log/auth.log",
		TriggerWords: []string{
			"Accepted publickey",
			"Accepted password",
		},
	}
	tfg.Watches = append(tfg.Watches, defaultwatch)

	var nfr Notifiers
	var pusho NPushOver
	var pusha NPushAlot
	var azise NAzise

	pusho.UserToken = "token"
	pusho.AppToken = "token"
	nfr.PushOver = pusho

	pusha.Token = "token"
	nfr.PushAlot = pusha

	azise.Secret = "secret"
	nfr.Azise = azise

	tfg.Notifications = nfr
	return tfg
}

func CheckIfResetConfig(args []string) {
	if len(args) == 2 {
		if args[1] == "reset" {
			e := os.Remove(cfgfile)
			if e != nil {
				log.Fatal("Could not remove current config file. Permissions issue?")
			}
			Default := GetDefaultConfig()
			out, e := json.Marshal(Default)
			e = ioutil.WriteFile(cfgfile, out, 600)
			if e != nil {
				log.Fatal("cannot open settings file :(")
			}
			log.Fatal("Built config file. please fill it in.")
		}
	}
}

func GetCFG() GConfig {
	b, e := ioutil.ReadFile(cfgfile)
	tfg := GetDefaultConfig()
	if e != nil {
		out, e := json.Marshal(tfg)
		e = ioutil.WriteFile(cfgfile, out, 600)
		if e != nil {
			log.Fatal("cannot open settings file :(")
		}
		log.Fatal("Built config file. please fill it in.")
	}

	e = json.Unmarshal(b, &tfg)
	if e != nil {
		log.Fatalf("Could not parse config settings. You may have to remove %s", cfgfile)
	}

	var nfc = tfg.Notifications
	if !CanPushOver(nfc) && !CanPushAlot(nfc) {
		log.Fatalf("Please fill in at least one push service in %s", cfgfile)
	}

	return tfg
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"os"
	"sync"
)

type Server struct {
	ID         int
	Name, Path string
	Args       []string
	status     string
	Map        int
}

type Map struct {
	ID         int
	Name, Path string
	Status     string
	Server     int
}

type Config struct {
	mu         sync.RWMutex
	filename   string
	ServerName string
	ServersDir string
	MapsDir    string
	Port       uint16
	Servers    serverMap
	Maps       mapMap
	selected   int
}

type serverMap map[int]Server

func (m serverMap) MarshalJSON() ([]byte, error) {
	s := make([]Server, 0, len(m))
	for _, v := range m {
		s = append(s, v)
	}
	return json.Marshal(s)
}

func (m serverMap) UnmarshalJSON(b []byte) error {
	var s []Server
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	for _, v := range s {
		m[v.ID] = v
	}
	return nil
}

type mapMap map[int]Map

func (m mapMap) MarshalJSON() ([]byte, error) {
	s := make([]Map, 0, len(m))
	for _, v := range m {
		s = append(s, v)
	}
	return json.Marshal(s)
}

func (m mapMap) UnmarshalJSON(b []byte) error {
	var s []Map
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	for _, v := range s {
		m[v.ID] = v
	}
	return nil
}

func loadConfig(filename string) (*Config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	c := &Config{
		filename:   filename,
		ServerName: "Minecraft",
		Port:       8080,
		Servers:    make(serverMap),
		Maps:       make(mapMap),
		selected:   -1,
	}
	err = json.NewDecoder(f).Decode(c)
	if err != nil {
		return nil, err
	}
	return c, nil
}

func (c *Config) save() error {
	f, err := os.Create(c.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	return json.NewEncoder(f).Encode(c)
}

func (c *Config) createServer(name, path string) int {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	id := 0
	for {
		_, ok := c.Servers[id]
		if !ok {
			break
		}
		id++
	}
	c.Servers[id] = Server{ID: id, Name: name, Path: path, Args: []string{"-Xmx1024M", "-Xms1024M"}, Map: -1}
	return id
}

func (c *Config) newMap(name, path string) int {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	id := 0
	for {
		_, ok := c.Maps[id]
		if !ok {
			break
		}
		id++
	}
	c.Maps[id] = Map{ID: id, Name: name, Path: path, Server: -1}
	return id
}

func (c *Config) serverStatus(id int, status string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	s, ok := c.Servers[id]
	if !ok {
		return
	}
	s.status = status
	c.Servers[id] = s
}
<commit_msg>Added server state<commit_after>package main

import (
	"encoding/json"
	"os"
	"sync"
)

type Server struct {
	ID         int
	Name, Path string
	Args       []string
	status     string
	state      int
	Map        int
}

type Map struct {
	ID         int
	Name, Path string
	Status     string
	Server     int
}

type Config struct {
	mu         sync.RWMutex
	filename   string
	ServerName string
	ServersDir string
	MapsDir    string
	Port       uint16
	Servers    serverMap
	Maps       mapMap
	selected   int
}

type serverMap map[int]Server

func (m serverMap) MarshalJSON() ([]byte, error) {
	s := make([]Server, 0, len(m))
	for _, v := range m {
		s = append(s, v)
	}
	return json.Marshal(s)
}

func (m serverMap) UnmarshalJSON(b []byte) error {
	var s []Server
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	for _, v := range s {
		m[v.ID] = v
	}
	return nil
}

type mapMap map[int]Map

func (m mapMap) MarshalJSON() ([]byte, error) {
	s := make([]Map, 0, len(m))
	for _, v := range m {
		s = append(s, v)
	}
	return json.Marshal(s)
}

func (m mapMap) UnmarshalJSON(b []byte) error {
	var s []Map
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	for _, v := range s {
		m[v.ID] = v
	}
	return nil
}

func loadConfig(filename string) (*Config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	c := &Config{
		filename:   filename,
		ServerName: "Minecraft",
		Port:       8080,
		Servers:    make(serverMap),
		Maps:       make(mapMap),
		selected:   -1,
	}
	err = json.NewDecoder(f).Decode(c)
	if err != nil {
		return nil, err
	}
	return c, nil
}

func (c *Config) save() error {
	f, err := os.Create(c.filename)
	if err != nil {
		return err
	}
	defer f.Close()
	return json.NewEncoder(f).Encode(c)
}

func (c *Config) createServer(name, path string) int {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	id := 0
	for {
		_, ok := c.Servers[id]
		if !ok {
			break
		}
		id++
	}
	c.Servers[id] = Server{ID: id, Name: name, Path: path, Args: []string{"-Xmx1024M", "-Xms1024M"}, Map: -1}
	return id
}

func (c *Config) newMap(name, path string) int {
	c.mu.Lock()
	defer c.mu.Unlock()
	defer c.save()
	id := 0
	for {
		_, ok := c.Maps[id]
		if !ok {
			break
		}
		id++
	}
	c.Maps[id] = Map{ID: id, Name: name, Path: path, Server: -1}
	return id
}

func (c *Config) serverStatus(id int, status string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	s, ok := c.Servers[id]
	if !ok {
		return
	}
	s.status = status
	c.Servers[id] = s
}
<|endoftext|>


<commit_before>package imgur

const (
	apiEndpoint        = "https://api.imgur.com/3/"
	apiEndpointMashape = "https://imgur-apiv3.p.mashape.com/3/"
)
<commit_msg>Updated endpoint for payed API<commit_after>package imgur

const (
	apiEndpoint        = "https://api.imgur.com/3/"
	apiEndpointMashape = "https://imgur-apiv3.p.rapidapi.com/3/"
)
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.com/phrase/phraseapp-api-client/Godeps/_workspace/src/gopkg.in/yaml.v2"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const configName = ".phraseapp.yml"
const defaultDir = ".config/phraseapp"

func ConfigDefaultCredentials() (*phraseapp.AuthCredentials, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCredentials(content)
}

func ConfigDefaultParams() (phraseapp.DefaultParams, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseDefaults(content)
}

func ConfigCallArgs() (map[string]string, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCallArgs(content)
}

// Paths and content
func ConfigContent() (string, error) {
	path, err := phraseConfigPath()
	if err != nil {
		return "", nil
	}

	b, err := bytesAtPath(path)
	if err != nil {
		return "", nil
	}
	return string(b), nil
}

func phraseConfigPath() (string, error) {
	callerPath, err := os.Getwd()
	if err != nil {
		return "", err
	}

	possiblePath := path.Join(callerPath, configName)
	if _, err := os.Stat(possiblePath); err == nil {
		return possiblePath, nil
	}

	return defaultConfigDir()
}

func bytesAtPath(path string) ([]byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return ioutil.ReadAll(f)
}

func defaultConfigDir() (string, error) {
	usr, e := user.Current()
	if e != nil {
		return "", nil
	}
	return path.Join(usr.HomeDir, defaultDir, configName), nil
}

// Parsing
type credentialConf struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		Host        string `yaml:"host"`
		Username    string
		TFA         bool
	}
}

func parseCredentials(yml string) (*phraseapp.AuthCredentials, error) {
	var conf *credentialConf

	if err := yaml.Unmarshal([]byte(yml), &conf); err != nil {
		return nil, err
	}

	phrase := conf.Phraseapp
	credentials := &phraseapp.AuthCredentials{Token: phrase.AccessToken, Username: phrase.Username, TFA: phrase.TFA, Host: phrase.Host}

	return credentials, nil
}

type defaultsConf struct {
	Phraseapp struct {
		Defaults phraseapp.DefaultParams
	}
}

func parseDefaults(yml string) (phraseapp.DefaultParams, error) {
	var conf *defaultsConf

	err := yaml.Unmarshal([]byte(yml), &conf)
	if err != nil {
		return nil, err
	}

	return conf.Phraseapp.Defaults, nil
}

type CallArgs struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		ProjectId   string `yaml:"project_id"`
		Page        int
		PerPage     int
	}
}

func parseCallArgs(yml string) (map[string]string, error) {
	var callArgs *CallArgs

	err := yaml.Unmarshal([]byte(yml), &callArgs)
	if err != nil {
		return nil, err
	}

	m := make(map[string]string)

	if callArgs != nil {
		m["ProjectId"] = callArgs.Phraseapp.ProjectId
		m["AccessToken"] = callArgs.Phraseapp.AccessToken
	}

	return m, nil
}
<commit_msg>adds default config content if config is unreadable<commit_after>package main

import (
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.com/phrase/phraseapp-api-client/Godeps/_workspace/src/gopkg.in/yaml.v2"
	"github.com/phrase/phraseapp-go/phraseapp"
)

const configName = ".phraseapp.yml"
const defaultDir = ".config/phraseapp"

func ConfigDefaultCredentials() (*phraseapp.AuthCredentials, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCredentials(content)
}

func ConfigDefaultParams() (phraseapp.DefaultParams, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseDefaults(content)
}

func ConfigCallArgs() (map[string]string, error) {
	content, err := ConfigContent()
	if err != nil {
		return nil, err
	}

	return parseCallArgs(content)
}

// Paths and content
func ConfigContent() (string, error) {
	path, err := phraseConfigPath()
	if err != nil {
		return "{}", nil
	}

	bytes, err := readFile(path)
	if err != nil {
		return "{}", nil
	}
	return string(bytes), nil
}

func phraseConfigPath() (string, error) {
	callerPath, err := os.Getwd()
	if err != nil {
		return "", err
	}

	possiblePath := path.Join(callerPath, configName)
	if _, err := os.Stat(possiblePath); err == nil {
		return possiblePath, nil
	}

	return defaultConfigDir()
}

func readFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	return ioutil.ReadAll(file)
}

func defaultConfigDir() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", nil
	}
	return path.Join(usr.HomeDir, defaultDir, configName), nil
}

// Parsing
type credentialConf struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		Host        string `yaml:"host"`
		Username    string
		TFA         bool
	}
}

func parseCredentials(yml string) (*phraseapp.AuthCredentials, error) {
	var conf *credentialConf

	if err := yaml.Unmarshal([]byte(yml), &conf); err != nil {
		return nil, err
	}

	phrase := conf.Phraseapp
	credentials := &phraseapp.AuthCredentials{Token: phrase.AccessToken, Username: phrase.Username, TFA: phrase.TFA, Host: phrase.Host}

	return credentials, nil
}

type defaultsConf struct {
	Phraseapp struct {
		Defaults phraseapp.DefaultParams
	}
}

func parseDefaults(yml string) (phraseapp.DefaultParams, error) {
	var conf *defaultsConf

	err := yaml.Unmarshal([]byte(yml), &conf)
	if err != nil {
		return nil, err
	}

	return conf.Phraseapp.Defaults, nil
}

type CallArgs struct {
	Phraseapp struct {
		AccessToken string `yaml:"access_token"`
		ProjectId   string `yaml:"project_id"`
		Page        int
		PerPage     int
	}
}

func parseCallArgs(yml string) (map[string]string, error) {
	var callArgs *CallArgs

	err := yaml.Unmarshal([]byte(yml), &callArgs)
	if err != nil {
		return nil, err
	}

	m := make(map[string]string)

	if callArgs != nil {
		m["ProjectId"] = callArgs.Phraseapp.ProjectId
		m["AccessToken"] = callArgs.Phraseapp.AccessToken
	}

	return m, nil
}
<|endoftext|>