<commit_before>package server

import (
	"math"
	"time"
)

// RegionArea is the area (in coordinate degrees)
const RegionArea = 1.0

// EventBufferSize limits the number of events that each network can hold.
// Theoretically in the maximum load scenario (with (180*180) networks) our
// max buffered events will be (180*180*256) = ~8.3 Million events which amounts
// to 67.2 Million Bytes at a minimum. This is reasonably manageable even in an unlikely case
const EventBufferSize = 1 << 8

// Client is the representation of chat clients
type Client struct {
	ID string
	Lat,
	Long float64
}

// ClientWorld represents the entirety of server-managed networks and clients.
// It is the first line in event handling
type ClientWorld struct {
	Networks  []ClientNetwork
	eventChan chan NetworkEvent
}

func (c *ClientWorld) handleClientConnect(client *Client) {
	//Code to handle client connect
}

func (c *ClientWorld) handleClientDisconnect(clientID string) {
	//Code to handle client disconnect
}

// SendEvent is a convenience function
func (c *ClientWorld) SendEvent(event NetworkEvent) {
	c.eventChan <- event
}

func (c *ClientWorld) waitForEvents() {
	for {
		event := <-c.eventChan
		switch t := event.Type(); t {
		case EventClientConnect:
			c.handleClientConnect(event.(ClientConnectionEvent).client)
		case EventClientDisconnect:
			c.handleClientDisconnect(event.(ClientDisconnectionEvent).clientID)
		}
	}
}

//NewClient creates a new client and returns its reference
func NewClient(lat, long float64) (client *Client) {
	client = new(Client)
	client.Lat = lat
	client.Long = long
	return
}

//ClientNetwork is the representation of the Network of all client regions
type ClientNetwork struct {
	root        *clientRegion
	allRegions  []*clientRegion
	latRange    [2]float64
	longRange   [2]float64
	messageChan chan ClientMessageEvent
}

// To avoid the use of mux's use a channel to shuttle events into the network
// This way we can perform operations without having to use locks
func (c *ClientNetwork) waitForMessages() {
	for {
		event := <-c.messageChan
		var aggregateMessages = []ClientMessageEvent{event}
		var done bool
		for !done {
			select {
			case e := <-c.messageChan:
				aggregateMessages = append(aggregateMessages, e)
			case <-time.Tick(1 * time.Microsecond):
				done = true
			}
		}
	}
}

// AddClient adds a client to the network in the appropriate region
func (c *ClientNetwork) AddClient(client *Client) (connected bool) {
	lat := math.Floor(client.Lat)
	long := math.Floor(client.Long)
	// we want to also track possible connecting regions in the case that
	// we need to add a region. Key as follows:
	// 0: Up
	// 1: Left
	// 2: Down
	// 3: Right
	var possibleRegionConnects = [4]*clientRegion{nil, nil, nil, nil}
	for _, region := range c.allRegions {
		if region.Lat == lat && region.Long == long {
			region.AddClient(client)
			connected = true
			return
		}
		if (region.Lat-lat) == RegionArea && (region.Long-long) == 0 {
			possibleRegionConnects[0] = region
			connected = true
		}
		if (region.Lat-lat) == -RegionArea && (region.Long-long) == 0 {
			possibleRegionConnects[3] = region
			connected = true
		}
		if (region.Lat-lat) == 0 && (region.Long-long) == -RegionArea {
			possibleRegionConnects[1] = region
			connected = true
		}
		if (region.Lat-lat) == 0 && (region.Long-long) == RegionArea {
			possibleRegionConnects[3] = region
			connected = true
		}
	}

	if !connected {
		return
	}

	newRegion := newClientRegion(client.Lat, client.Long)
	newRegion.AddClient(client)

	for i, r := range possibleRegionConnects {
		if r == nil {
			continue
		}
		switch i {
		case 0:
			newRegion.Up = r
			r.Down = newRegion
		case 1:
			newRegion.Left = r
			r.Right = newRegion
		case 2:
			newRegion.Down = r
			r.Up = newRegion
		case 3:
			newRegion.Right = r
			r.Left = newRegion
		}
	}

	// Append the region to the region array
	c.allRegions = append(c.allRegions, newRegion)

	// Also update our rectangular boundary
	if newRegion.Lat == c.latRange[1] {
		c.latRange[1]++
	}
	if newRegion.Lat < c.latRange[0] {
		c.latRange[0]--
	}
	if newRegion.Long == c.longRange[1] {
		c.longRange[1]++
	}
	if newRegion.Long == c.longRange[0] {
		c.longRange[0]--
	}
	return
}

// NewClientNetwork creates a new network of client regions
func NewClientNetwork(root *clientRegion) (network *ClientNetwork) {
	network = new(ClientNetwork)
	network.root = root
	network.allRegions = []*clientRegion{root}

	network.latRange = [2]float64{root.Lat, root.Lat + RegionArea}
	network.longRange = [2]float64{root.Long, root.Long + RegionArea}

	network.messageChan = make(chan ClientMessageEvent, EventBufferSize)

	go network.waitForMessages()

	return
}

type clientRegion struct {
	Up,
	Left,
	Down,
	Right *clientRegion
	clients map[string]*Client
	isRoot,
	visited bool
	Lat,
	Long float64
}

func (c *clientRegion) isConnectedToRoot(previousConnection bool) bool {
	if c.visited {
		return previousConnection
	}
	c.visited = true
	if c.isRoot {
		return true
	}
	// Graph search order is Up Left Down Right
	if c.Up != nil && c.Up.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Left != nil && c.Left.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Down != nil && c.Down.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Right != nil && c.Right.isConnectedToRoot(previousConnection) {
		return true
	}
	return false
}

func (c *clientRegion) findClientRegion(lat, long float64) *clientRegion {
	if c.visited {
		return nil
	}
	c.visited = true
	if c.Lat == lat && c.Long == long {
		return c
	}
	// Graph search order is Up Left Down Right
	if c.Up != nil {
		if n := c.Up.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Left != nil {
		if n := c.Left.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Down != nil {
		if n := c.Down.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Right != nil {
		if n := c.Right.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	return nil
}

//AddClient adds a client to a region. In the case that we already have the client in the region we ignore.
func (c *clientRegion) AddClient(client *Client) {
	if _, ok := c.clients[client.ID]; ok {
		return
	}
	c.clients[client.ID] = client
}

func newClientRegion(lat, long float64) (region *clientRegion) {
	region = new(clientRegion)
	region.clients = make(map[string]*Client)
	region.Lat = lat
	region.Long = long
	return
}
<commit_msg>Added client merge code for the case of merging networks<commit_after>package server

import (
	"math"
	"time"
)

// RegionArea is the area (in coordinate degrees)
const RegionArea = 1.0

// EventBufferSize limits the number of events that each network can hold.
// Theoretically in the maximum load scenario (with (180*180) networks) our
// max buffered events will be (180*180*256) = ~8.3 Million events which amounts
// to 67.2 Million Bytes at a minimum. This is reasonably manageable even in an unlikely case
const EventBufferSize = 1 << 8

// Client is the representation of chat clients
type Client struct {
	ID string
	Lat,
	Long float64
}

// ClientWorld represents the entirety of server-managed networks and clients.
// It is the first line in event handling
type ClientWorld struct {
	Networks  []*ClientNetwork
	eventChan chan NetworkEvent
}

func (c *ClientWorld) mergeNetworks(networks []*ClientNetwork, lat, long float64) {
	var rootNetRegion = networks[0].root.findClientRegion(lat, long)
	for _, network := range networks[1:] {
		region := network.root.findClientRegion(lat, long)
		// merge the clients to the new root region
		for id, client := range region.clients {
			rootNetRegion.clients[id] = client
		}

		// Now splice out the node
		if region.Up != nil {
			rootNetRegion.Up = region.Up
			region.Up.Down = rootNetRegion
			region.Up = nil
		}
		if region.Left != nil {
			rootNetRegion.Left = region.Left
			region.Left.Right = rootNetRegion
			region.Left = nil
		}
		if region.Down != nil {
			rootNetRegion.Down = region.Down
			region.Down.Up = rootNetRegion
			region.Down = nil
		}
		if region.Right != nil {
			rootNetRegion.Right = region.Right
			region.Right.Left = rootNetRegion
			region.Right = nil
		}
	}
}

func (c *ClientWorld) handleClientConnect(client *Client) {
	//Code to handle client connect
	var connectedNetworks []*ClientNetwork
	for _, network := range c.Networks {
		if network.possiblyContains(client) {
			if network.AddClient(client) {
				connectedNetworks = append(connectedNetworks, network)
			}
		}
	}
	if len(connectedNetworks) > 1 {
		c.mergeNetworks(connectedNetworks, math.Floor(client.Lat), math.Floor(client.Long))
	}
}

func (c *ClientWorld) handleClientDisconnect(clientID string) {
	//Code to handle client disconnect
}

// SendEvent is a convenience function
func (c *ClientWorld) SendEvent(event NetworkEvent) {
	c.eventChan <- event
}

func (c *ClientWorld) waitForEvents() {
	for {
		event := <-c.eventChan
		switch t := event.Type(); t {
		case EventClientConnect:
			c.handleClientConnect(event.(ClientConnectionEvent).client)
		case EventClientDisconnect:
			c.handleClientDisconnect(event.(ClientDisconnectionEvent).clientID)
		}
	}
}

//NewClient creates a new client and returns its reference
func NewClient(lat, long float64) (client *Client) {
	client = new(Client)
	client.Lat = lat
	client.Long = long
	return
}

//ClientNetwork is the representation of the Network of all client regions
type ClientNetwork struct {
	root        *clientRegion
	allRegions  []*clientRegion
	latRange    [2]float64
	longRange   [2]float64
	messageChan chan ClientMessageEvent
}

func (c *ClientNetwork) possiblyContains(client *Client) bool {
	return (client.Lat >= c.latRange[0] && client.Lat < c.latRange[1] &&
		client.Long >= c.longRange[0] && client.Long < c.longRange[1])
}

// To avoid the use of mux's use a channel to shuttle events into the network
// This way we can perform operations without having to use locks
func (c *ClientNetwork) waitForMessages() {
	for {
		event := <-c.messageChan
		var aggregateMessages = []ClientMessageEvent{event}
		var done bool
		for !done {
			select {
			case e := <-c.messageChan:
				aggregateMessages = append(aggregateMessages, e)
			case <-time.Tick(1 * time.Microsecond):
				done = true
			}
		}
	}
}

// AddClient adds a client to the network in the appropriate region
func (c *ClientNetwork) AddClient(client *Client) (connected bool) {
	lat := math.Floor(client.Lat)
	long := math.Floor(client.Long)
	// we want to also track possible connecting regions in the case that
	// we need to add a region. Key as follows:
	// 0: Up
	// 1: Left
	// 2: Down
	// 3: Right
	var possibleRegionConnects = [4]*clientRegion{nil, nil, nil, nil}
	for _, region := range c.allRegions {
		if region.Lat == lat && region.Long == long {
			region.AddClient(client)
			connected = true
			return
		}
		if (region.Lat-lat) == RegionArea && (region.Long-long) == 0 {
			possibleRegionConnects[0] = region
			connected = true
		}
		if (region.Lat-lat) == -RegionArea && (region.Long-long) == 0 {
			possibleRegionConnects[3] = region
			connected = true
		}
		if (region.Lat-lat) == 0 && (region.Long-long) == -RegionArea {
			possibleRegionConnects[1] = region
			connected = true
		}
		if (region.Lat-lat) == 0 && (region.Long-long) == RegionArea {
			possibleRegionConnects[3] = region
			connected = true
		}
	}

	if !connected {
		return
	}

	newRegion := newClientRegion(client.Lat, client.Long)
	newRegion.AddClient(client)

	for i, r := range possibleRegionConnects {
		if r == nil {
			continue
		}
		switch i {
		case 0:
			newRegion.Up = r
			r.Down = newRegion
		case 1:
			newRegion.Left = r
			r.Right = newRegion
		case 2:
			newRegion.Down = r
			r.Up = newRegion
		case 3:
			newRegion.Right = r
			r.Left = newRegion
		}
	}

	// Append the region to the region array
	c.allRegions = append(c.allRegions, newRegion)

	// Also update our rectangular boundary
	if newRegion.Lat == c.latRange[1] {
		c.latRange[1]++
	}
	if newRegion.Lat < c.latRange[0] {
		c.latRange[0]--
	}
	if newRegion.Long == c.longRange[1] {
		c.longRange[1]++
	}
	if newRegion.Long == c.longRange[0] {
		c.longRange[0]--
	}
	return
}

// NewClientNetwork creates a new network of client regions
func NewClientNetwork(root *clientRegion) (network *ClientNetwork) {
	network = new(ClientNetwork)
	network.root = root
	network.allRegions = []*clientRegion{root}

	network.latRange = [2]float64{root.Lat, root.Lat + RegionArea}
	network.longRange = [2]float64{root.Long, root.Long + RegionArea}

	network.messageChan = make(chan ClientMessageEvent, EventBufferSize)

	go network.waitForMessages()

	return
}

type clientRegion struct {
	Up,
	Left,
	Down,
	Right *clientRegion
	clients map[string]*Client
	isRoot,
	visited bool
	Lat,
	Long float64
}

func (c *clientRegion) isConnectedToRoot(previousConnection bool) bool {
	if c.visited {
		return previousConnection
	}
	c.visited = true
	if c.isRoot {
		return true
	}
	// Graph search order is Up Left Down Right
	if c.Up != nil && c.Up.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Left != nil && c.Left.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Down != nil && c.Down.isConnectedToRoot(previousConnection) {
		return true
	}
	if c.Right != nil && c.Right.isConnectedToRoot(previousConnection) {
		return true
	}
	return false
}

func (c *clientRegion) findClientRegion(lat, long float64) *clientRegion {
	if c.visited {
		return nil
	}
	c.visited = true
	if c.Lat == lat && c.Long == long {
		return c
	}
	// Graph search order is Up Left Down Right
	if c.Up != nil {
		if n := c.Up.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Left != nil {
		if n := c.Left.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Down != nil {
		if n := c.Down.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	if c.Right != nil {
		if n := c.Right.findClientRegion(lat, long); n != nil {
			return n
		}
	}
	return nil
}

//AddClient adds a client to a region. In the case that we already have the client in the region we ignore.
func (c *clientRegion) AddClient(client *Client) {
	if _, ok := c.clients[client.ID]; ok {
		return
	}
	c.clients[client.ID] = client
}

func newClientRegion(lat, long float64) (region *clientRegion) {
	region = new(clientRegion)
	region.clients = make(map[string]*Client)
	region.Lat = lat
	region.Long = long
	return
}
<|endoftext|>


<commit_before>package rockredis

import (
	"bytes"

	"github.com/absolute8511/ZanRedisDB/common"
	"github.com/absolute8511/gorocksdb"
)

type Iterator interface {
	Next()
	Prev()
	Valid() bool
	Seek([]byte)
	SeekForPrev([]byte)
	SeekToFirst()
	SeekToLast()
	Close()
	RefKey() []byte
	Key() []byte
	RefValue() []byte
	Value() []byte
	NoTimestamp(vt byte)
}

type Range struct {
	Min  []byte
	Max  []byte
	Type uint8
}

type Limit struct {
	Offset int
	Count  int
}

type DBIterator struct {
	*gorocksdb.Iterator
	snap         *gorocksdb.Snapshot
	ro           *gorocksdb.ReadOptions
	db           *gorocksdb.DB
	removeTsType byte
}

// low_bound is inclusive
// upper bound is exclusive
func NewDBIterator(db *gorocksdb.DB, withSnap bool, prefixSame bool, lowbound []byte, upbound []byte, ignoreDel bool) (*DBIterator, error) {
	db.RLock()
	dbit := &DBIterator{
		db: db,
	}
	readOpts := gorocksdb.NewDefaultReadOptions()
	readOpts.SetFillCache(false)
	readOpts.SetVerifyChecksums(false)
	if prefixSame {
		readOpts.SetPrefixSameAsStart(true)
	}
	if lowbound != nil {
		readOpts.SetIterLowerBound(lowbound)
	}
	if upbound != nil {
		readOpts.SetIterUpperBound(upbound)
	}
	if ignoreDel {
		// may iterator some deleted keys still not compacted.
		readOpts.SetIgnoreRangeDeletions(true)
	}
	dbit.ro = readOpts
	var err error
	if withSnap {
		dbit.snap, err = db.NewSnapshot()
		if err != nil {
			dbit.Close()
			return nil, err
		}
		readOpts.SetSnapshot(dbit.snap)
	}
	dbit.Iterator, err = db.NewIterator(readOpts)
	if err != nil {
		dbit.Close()
		return nil, err
	}
	return dbit, nil
}

func (it *DBIterator) RefKey() []byte {
	return it.Iterator.Key().Data()
}

func (it *DBIterator) Key() []byte {
	return it.Iterator.Key().Bytes()
}

func (it *DBIterator) RefValue() []byte {
	v := it.Iterator.Value().Data()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) Value() []byte {
	v := it.Iterator.Value().Bytes()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) NoTimestamp(vt byte) {
	it.removeTsType = vt
}

func (it *DBIterator) Close() {
	if it.Iterator != nil {
		it.Iterator.Close()
	}
	if it.ro != nil {
		it.ro.Destroy()
	}
	if it.snap != nil {
		it.snap.Release()
	}
	it.db.RUnlock()
}

// note: all the iterator use the prefix iterator flag. Which means it may skip the keys for different table
// prefix.
func NewDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	lowerBound = nil
	upperBound = nil

	//dbLog.Infof("iterator %v : %v", lowerBound, upperBound)
	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewSnapshotDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	lowerBound = nil
	upperBound = nil
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	lowerBound = nil
	upperBound = nil
	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

func NewSnapshotDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	lowerBound = nil
	upperBound = nil
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

type RangeLimitedIterator struct {
	Iterator
	l Limit
	r Range
	// maybe step should not auto increase, we need count for actually element
	step    int
	reverse bool
}

func (it *RangeLimitedIterator) Valid() bool {
	if it.l.Offset < 0 {
		return false
	}
	if it.l.Count >= 0 && it.step >= it.l.Count {
		return false
	}
	if !it.Iterator.Valid() {
		return false
	}

	if !it.reverse {
		if it.r.Max != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Max)
			if it.r.Type&common.RangeROpen > 0 {
				return !(r >= 0)
			} else {
				return !(r > 0)
			}
		}
	} else {
		if it.r.Min != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Min)
			if it.r.Type&common.RangeLOpen > 0 {
				return !(r <= 0)
			} else {
				return !(r < 0)
			}
		}
	}
	return true
}

func (it *RangeLimitedIterator) Next() {
	it.step++
	if !it.reverse {
		it.Iterator.Next()
	} else {
		it.Iterator.Prev()
	}
}

func NewRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, false)
}
func NewRevRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, true)
}
func NewRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, false)
}
func NewRevRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, true)
}
func rangeLimitIterator(i Iterator, r *Range, l *Limit, reverse bool) *RangeLimitedIterator {
	it := &RangeLimitedIterator{
		Iterator: i,
		l:        *l,
		r:        *r,
		reverse:  reverse,
		step:     0,
	}
	if l.Offset < 0 {
		return it
	}
	if !reverse {
		if r.Min == nil {
			it.Iterator.SeekToFirst()
		} else {
			it.Iterator.Seek(r.Min)
			if r.Type&common.RangeLOpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Min) {
					it.Iterator.Next()
				}
			}
		}
	} else {
		if r.Max == nil {
			it.Iterator.SeekToLast()
		} else {
			it.Iterator.SeekForPrev(r.Max)
			if !it.Iterator.Valid() {
				it.Iterator.SeekToLast()
				if it.Iterator.Valid() && bytes.Compare(it.Iterator.RefKey(), r.Max) == 1 {
					dbLog.Infof("iterator seek to last key %v should not great than seek to max %v", it.Iterator.RefKey(), r.Max)
				}
			}
			if r.Type&common.RangeROpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Max) {
					it.Iterator.Prev()
				}
			}
		}
	}
	for i := 0; i < l.Offset; i++ {
		if it.Iterator.Valid() {
			if !it.reverse {
				it.Iterator.Next()
			} else {
				it.Iterator.Prev()
			}
		}
	}
	return it
}
<commit_msg>fix iterator bound<commit_after>package rockredis

import (
	"bytes"

	"github.com/absolute8511/ZanRedisDB/common"
	"github.com/absolute8511/gorocksdb"
)

type Iterator interface {
	Next()
	Prev()
	Valid() bool
	Seek([]byte)
	SeekForPrev([]byte)
	SeekToFirst()
	SeekToLast()
	Close()
	RefKey() []byte
	Key() []byte
	RefValue() []byte
	Value() []byte
	NoTimestamp(vt byte)
}

type Range struct {
	Min  []byte
	Max  []byte
	Type uint8
}

type Limit struct {
	Offset int
	Count  int
}

type DBIterator struct {
	*gorocksdb.Iterator
	snap         *gorocksdb.Snapshot
	ro           *gorocksdb.ReadOptions
	db           *gorocksdb.DB
	upperBound   *gorocksdb.IterBound
	lowerBound   *gorocksdb.IterBound
	removeTsType byte
}

// low_bound is inclusive
// upper bound is exclusive
func NewDBIterator(db *gorocksdb.DB, withSnap bool, prefixSame bool, lowbound []byte, upbound []byte, ignoreDel bool) (*DBIterator, error) {
	db.RLock()
	dbit := &DBIterator{
		db: db,
	}
	readOpts := gorocksdb.NewDefaultReadOptions()
	readOpts.SetFillCache(false)
	readOpts.SetVerifyChecksums(false)
	if prefixSame {
		readOpts.SetPrefixSameAsStart(true)
	}
	if lowbound != nil {
		dbit.lowerBound = gorocksdb.NewIterBound(lowbound)
		readOpts.SetIterLowerBound(dbit.lowerBound)
	}
	if upbound != nil {
		dbit.upperBound = gorocksdb.NewIterBound(upbound)
		readOpts.SetIterUpperBound(dbit.upperBound)
	}
	if ignoreDel {
		// may iterator some deleted keys still not compacted.
		readOpts.SetIgnoreRangeDeletions(true)
	}
	dbit.ro = readOpts
	var err error
	if withSnap {
		dbit.snap, err = db.NewSnapshot()
		if err != nil {
			dbit.Close()
			return nil, err
		}
		readOpts.SetSnapshot(dbit.snap)
	}
	dbit.Iterator, err = db.NewIterator(readOpts)
	if err != nil {
		dbit.Close()
		return nil, err
	}
	return dbit, nil
}

func (it *DBIterator) RefKey() []byte {
	return it.Iterator.Key().Data()
}

func (it *DBIterator) Key() []byte {
	return it.Iterator.Key().Bytes()
}

func (it *DBIterator) RefValue() []byte {
	v := it.Iterator.Value().Data()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) Value() []byte {
	v := it.Iterator.Value().Bytes()
	if (it.removeTsType == KVType || it.removeTsType == HashType) && len(v) >= tsLen {
		v = v[:len(v)-tsLen]
	}
	return v
}

func (it *DBIterator) NoTimestamp(vt byte) {
	it.removeTsType = vt
}

func (it *DBIterator) Close() {
	if it.Iterator != nil {
		it.Iterator.Close()
	}
	if it.ro != nil {
		it.ro.Destroy()
	}
	if it.snap != nil {
		it.snap.Release()
	}
	if it.upperBound != nil {
		it.upperBound.Destroy()
	}
	if it.lowerBound != nil {
		it.lowerBound.Destroy()
	}
	it.db.RUnlock()
}

// note: all the iterator use the prefix iterator flag. Which means it may skip the keys for different table
// prefix.
func NewDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}

	//dbLog.Infof("iterator %v : %v", lowerBound, upperBound)
	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewSnapshotDBRangeLimitIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	offset int, count int, reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	} else {
		return NewRevRangeLimitIterator(dbit, &Range{Min: min, Max: max, Type: rtype},
			&Limit{Offset: offset, Count: count}), nil
	}
}

func NewDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, false, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

func NewSnapshotDBRangeIterator(db *gorocksdb.DB, min []byte, max []byte, rtype uint8,
	reverse bool) (*RangeLimitedIterator, error) {
	upperBound := max
	lowerBound := min
	if rtype&common.RangeROpen <= 0 && upperBound != nil {
		// range right not open, we need inclusive the max,
		// however upperBound is exclusive
		upperBound = append(upperBound, 0)
	}
	dbit, err := NewDBIterator(db, true, true, lowerBound, upperBound, false)
	if err != nil {
		return nil, err
	}
	if !reverse {
		return NewRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	} else {
		return NewRevRangeIterator(dbit, &Range{Min: min, Max: max, Type: rtype}), nil
	}
}

type RangeLimitedIterator struct {
	Iterator
	l Limit
	r Range
	// maybe step should not auto increase, we need count for actually element
	step    int
	reverse bool
}

func (it *RangeLimitedIterator) Valid() bool {
	if it.l.Offset < 0 {
		return false
	}
	if it.l.Count >= 0 && it.step >= it.l.Count {
		return false
	}
	if !it.Iterator.Valid() {
		return false
	}

	if !it.reverse {
		if it.r.Max != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Max)
			if it.r.Type&common.RangeROpen > 0 {
				return !(r >= 0)
			} else {
				return !(r > 0)
			}
		}
	} else {
		if it.r.Min != nil {
			r := bytes.Compare(it.Iterator.RefKey(), it.r.Min)
			if it.r.Type&common.RangeLOpen > 0 {
				return !(r <= 0)
			} else {
				return !(r < 0)
			}
		}
	}
	return true
}

func (it *RangeLimitedIterator) Next() {
	it.step++
	if !it.reverse {
		it.Iterator.Next()
	} else {
		it.Iterator.Prev()
	}
}

func NewRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, false)
}
func NewRevRangeLimitIterator(i Iterator, r *Range, l *Limit) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, l, true)
}
func NewRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, false)
}
func NewRevRangeIterator(i Iterator, r *Range) *RangeLimitedIterator {
	return rangeLimitIterator(i, r, &Limit{0, -1}, true)
}
func rangeLimitIterator(i Iterator, r *Range, l *Limit, reverse bool) *RangeLimitedIterator {
	it := &RangeLimitedIterator{
		Iterator: i,
		l:        *l,
		r:        *r,
		reverse:  reverse,
		step:     0,
	}
	if l.Offset < 0 {
		return it
	}
	if !reverse {
		if r.Min == nil {
			it.Iterator.SeekToFirst()
		} else {
			it.Iterator.Seek(r.Min)
			if r.Type&common.RangeLOpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Min) {
					it.Iterator.Next()
				}
			}
		}
	} else {
		if r.Max == nil {
			it.Iterator.SeekToLast()
		} else {
			it.Iterator.SeekForPrev(r.Max)
			if !it.Iterator.Valid() {
				it.Iterator.SeekToLast()
				if it.Iterator.Valid() && bytes.Compare(it.Iterator.RefKey(), r.Max) == 1 {
					dbLog.Infof("iterator seek to last key %v should not great than seek to max %v", it.Iterator.RefKey(), r.Max)
				}
			}
			if r.Type&common.RangeROpen > 0 {
				if it.Iterator.Valid() && bytes.Equal(it.Iterator.RefKey(), r.Max) {
					it.Iterator.Prev()
				}
			}
		}
	}
	for i := 0; i < l.Offset; i++ {
		if it.Iterator.Valid() {
			if !it.reverse {
				it.Iterator.Next()
			} else {
				it.Iterator.Prev()
			}
		}
	}
	return it
}
<|endoftext|>


<commit_before>package user

import (
	"net/url"
	"github.com/drone/routes/exp/context"
)

// Key used to store the user in the session
const userKey = "_user"

// User represents a user of the application.
type User struct {
    Id    string // the unique permanent ID of the user.
	Name  string // the human-readable ID of the user.
	Email string
	Photo string

    FederatedIdentity string
    FederatedProvider string
}

// Decode will create a user from a URL Query string.
func Decode(v string) *User {
	values, err := url.ParseQuery(v)
	if err != nil {
		return nil
	}

	return &User {
		Id    : values.Get("id"),
		Name  : values.Get("name"),
		Email : values.Get("email"),
		Photo : values.Get("photo"),
	}
}

// Encode will encode a user as a URL query string.
func (u *User) Encode() string {
	values := url.Values{}
	values.Set("id", u.Id)
	values.Set("name", u.Name)
	values.Set("email", u.Email)
	values.Set("photo", u.Photo)
	return values.Encode()
}

// Current returns the currently logged-in user, or nil if the user is not
// signed in.
func Current(c *context.Context) *User {
	v := c.Values.Get(userKey)
	if v == nil {
		return nil
	}

	u, ok := v.(*User)
	if !ok {
		return nil
	}

	return u
}

// Set sets the currently logged-in user. This is typically used by middleware
// that handles user authentication.
func Set(c *context.Context, u *User) {
	c.Values.Set(userKey, u)
}
<commit_msg>Updated user.User to include additional attributes (map string)<commit_after>package user

import (
	"net/url"
	"github.com/drone/routes/exp/context"
)

// Key used to store the user in the session
const userKey = "_user"

// User represents a user of the application.
type User struct {
    Id    string // the unique permanent ID of the user.
	Name  string // the human-readable ID of the user.
	Email string
	Photo string

    FederatedIdentity string
    FederatedProvider string

	// additional, custom Attributes
	Attrs map[string]string
}

// Decode will create a user from a URL Query string.
func Decode(v string) *User {
	values, err := url.ParseQuery(v)
	if err != nil {
		return nil
	}

	attrs := map[string]string{}
	for key, _ := range values {
		attrs[key]=values.Get(key)
	}

	return &User {
		Id    : values.Get("id"),
		Name  : values.Get("name"),
		Email : values.Get("email"),
		Photo : values.Get("photo"),
		Attrs : attrs,
	}
}

// Encode will encode a user as a URL query string.
func (u *User) Encode() string {
	values := url.Values{}

	// add custom attributes
	if u.Attrs != nil {
		for key, val := range u.Attrs {
			values.Set(key, val)
		}
	}

	values.Set("id", u.Id)
	values.Set("name", u.Name)
	values.Set("email", u.Email)
	values.Set("photo", u.Photo)
	return values.Encode()
}

// Current returns the currently logged-in user, or nil if the user is not
// signed in.
func Current(c *context.Context) *User {
	v := c.Values.Get(userKey)
	if v == nil {
		return nil
	}

	u, ok := v.(*User)
	if !ok {
		return nil
	}

	return u
}

// Set sets the currently logged-in user. This is typically used by middleware
// that handles user authentication.
func Set(c *context.Context, u *User) {
	c.Values.Set(userKey, u)
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"fmt"
	"runtime/debug"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/micro/go-log"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/codec"
	"github.com/micro/go-micro/metadata"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/transport"

	"github.com/micro/util/go/lib/addr"
)

type rpcServer struct {
	router *router
	exit   chan chan error

	sync.RWMutex
	opts        Options
	handlers    map[string]Handler
	subscribers map[*subscriber][]broker.Subscriber
	// used for first registration
	registered bool
	// graceful exit
	wg sync.WaitGroup
}

func newRpcServer(opts ...Option) Server {
	options := newOptions(opts...)
	return &rpcServer{
		opts:        options,
		router:      DefaultRouter,
		handlers:    make(map[string]Handler),
		subscribers: make(map[*subscriber][]broker.Subscriber),
		exit:        make(chan chan error),
	}
}

// ServeConn serves a single connection
func (s *rpcServer) ServeConn(sock transport.Socket) {
	defer func() {
		// close socket
		sock.Close()

		if r := recover(); r != nil {
			log.Log("panic recovered: ", r)
			log.Log(string(debug.Stack()))
		}
	}()

	for {
		var msg transport.Message
		if err := sock.Recv(&msg); err != nil {
			return
		}

		// add to wait group
		s.wg.Add(1)

		// we use this Timeout header to set a server deadline
		to := msg.Header["Timeout"]
		// we use this Content-Type header to identify the codec needed
		ct := msg.Header["Content-Type"]

		// strip our headers
		hdr := make(map[string]string)
		for k, v := range msg.Header {
			hdr[k] = v
		}

		// set local/remote ips
		hdr["Local"] = sock.Local()
		hdr["Remote"] = sock.Remote()

		// create new context
		ctx := metadata.NewContext(context.Background(), hdr)

		// set the timeout if we have it
		if len(to) > 0 {
			if n, err := strconv.ParseUint(to, 10, 64); err == nil {
				ctx, _ = context.WithTimeout(ctx, time.Duration(n))
			}
		}

		// no content type
		if len(ct) == 0 {
			msg.Header["Content-Type"] = DefaultContentType
			ct = DefaultContentType
		}

		// setup old protocol
		cf := setupProtocol(&msg)

		// no old codec
		if cf == nil {
			// TODO: needs better error handling
			var err error
			if cf, err = s.newCodec(ct); err != nil {
				sock.Send(&transport.Message{
					Header: map[string]string{
						"Content-Type": "text/plain",
					},
					Body: []byte(err.Error()),
				})
				s.wg.Done()
				return
			}
		}

		rcodec := newRpcCodec(&msg, sock, cf)

		// internal request
		request := &rpcRequest{
			service:     getHeader("Micro-Service", msg.Header),
			method:      getHeader("Micro-Method", msg.Header),
			endpoint:    getHeader("Micro-Endpoint", msg.Header),
			contentType: ct,
			codec:       rcodec,
			header:      msg.Header,
			body:        msg.Body,
			socket:      sock,
			stream:      true,
		}

		// internal response
		response := &rpcResponse{
			header: make(map[string]string),
			socket: sock,
			codec:  rcodec,
		}

		// set router
		r := s.opts.Router

		// if nil use default router
		if s.opts.Router == nil {
			r = s.router
		}

		// create a wrapped function
		handler := func(ctx context.Context, req Request, rsp interface{}) error {
			return r.ServeRequest(ctx, req, rsp.(Response))
		}

		for i := len(s.opts.HdlrWrappers); i > 0; i-- {
			handler = s.opts.HdlrWrappers[i-1](handler)
		}

		// TODO: handle error better
		if err := handler(ctx, request, response); err != nil {
			if err != lastStreamResponseError {
				// write an error response
				err = rcodec.Write(&codec.Message{
					Header: msg.Header,
					Error:  err.Error(),
					Type:   codec.Error,
				}, nil)
				// could not write the error response
				if err != nil {
					log.Logf("rpc: unable to write error response: %v", err)
				}
			}
			s.wg.Done()
			return
		}

		// done
		s.wg.Done()
	}
}

func (s *rpcServer) newCodec(contentType string) (codec.NewCodec, error) {
	if cf, ok := s.opts.Codecs[contentType]; ok {
		return cf, nil
	}
	if cf, ok := DefaultCodecs[contentType]; ok {
		return cf, nil
	}
	return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
}

func (s *rpcServer) Options() Options {
	s.RLock()
	opts := s.opts
	s.RUnlock()
	return opts
}

func (s *rpcServer) Init(opts ...Option) error {
	s.Lock()
	for _, opt := range opts {
		opt(&s.opts)
	}
	s.Unlock()
	return nil
}

func (s *rpcServer) NewHandler(h interface{}, opts ...HandlerOption) Handler {
	return s.router.NewHandler(h, opts...)
}

func (s *rpcServer) Handle(h Handler) error {
	s.Lock()
	defer s.Unlock()

	if err := s.router.Handle(h); err != nil {
		return err
	}

	s.handlers[h.Name()] = h

	return nil
}

func (s *rpcServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
	return newSubscriber(topic, sb, opts...)
}

func (s *rpcServer) Subscribe(sb Subscriber) error {
	sub, ok := sb.(*subscriber)
	if !ok {
		return fmt.Errorf("invalid subscriber: expected *subscriber")
	}
	if len(sub.handlers) == 0 {
		return fmt.Errorf("invalid subscriber: no handler functions")
	}

	if err := validateSubscriber(sb); err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()
	_, ok = s.subscribers[sub]
	if ok {
		return fmt.Errorf("subscriber %v already exists", s)
	}
	s.subscribers[sub] = nil
	return nil
}

func (s *rpcServer) Register() error {
	// parse address for host, port
	config := s.Options()
	var advt, host string
	var port int

	// check the advertise address first
	// if it exists then use it, otherwise
	// use the address
	if len(config.Advertise) > 0 {
		advt = config.Advertise
	} else {
		advt = config.Address
	}

	parts := strings.Split(advt, ":")
	if len(parts) > 1 {
		host = strings.Join(parts[:len(parts)-1], ":")
		port, _ = strconv.Atoi(parts[len(parts)-1])
	} else {
		host = parts[0]
	}

	addr, err := addr.Extract(host)
	if err != nil {
		return err
	}

	// make copy of metadata
	md := make(metadata.Metadata)
	for k, v := range config.Metadata {
		md[k] = v
	}

	// register service
	node := &registry.Node{
		Id:       config.Name + "-" + config.Id,
		Address:  addr,
		Port:     port,
		Metadata: md,
	}

	node.Metadata["transport"] = config.Transport.String()
	node.Metadata["broker"] = config.Broker.String()
	node.Metadata["server"] = s.String()
	node.Metadata["registry"] = config.Registry.String()
	node.Metadata["protocol"] = "mucp"

	s.RLock()
	// Maps are ordered randomly, sort the keys for consistency
	var handlerList []string
	for n, e := range s.handlers {
		// Only advertise non internal handlers
		if !e.Options().Internal {
			handlerList = append(handlerList, n)
		}
	}
	sort.Strings(handlerList)

	var subscriberList []*subscriber
	for e := range s.subscribers {
		// Only advertise non internal subscribers
		if !e.Options().Internal {
			subscriberList = append(subscriberList, e)
		}
	}
	sort.Slice(subscriberList, func(i, j int) bool {
		return subscriberList[i].topic > subscriberList[j].topic
	})

	var endpoints []*registry.Endpoint
	for _, n := range handlerList {
		endpoints = append(endpoints, s.handlers[n].Endpoints()...)
	}
	for _, e := range subscriberList {
		endpoints = append(endpoints, e.Endpoints()...)
	}
	s.RUnlock()

	service := &registry.Service{
		Name:      config.Name,
		Version:   config.Version,
		Nodes:     []*registry.Node{node},
		Endpoints: endpoints,
	}

	s.Lock()
	registered := s.registered
	s.Unlock()

	if !registered {
		log.Logf("Registering node: %s", node.Id)
	}

	// create registry options
	rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}

	if err := config.Registry.Register(service, rOpts...); err != nil {
		return err
	}

	// already registered? don't need to register subscribers
	if registered {
		return nil
	}

	s.Lock()
	defer s.Unlock()

	s.registered = true

	for sb, _ := range s.subscribers {
		handler := s.createSubHandler(sb, s.opts)
		var opts []broker.SubscribeOption
		if queue := sb.Options().Queue; len(queue) > 0 {
			opts = append(opts, broker.Queue(queue))
		}
		if cx := sb.Options().Context; cx != nil {
			opts = append(opts, broker.SubscribeContext(cx))
		}
		sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
		if err != nil {
			return err
		}
		s.subscribers[sb] = []broker.Subscriber{sub}
	}

	return nil
}

func (s *rpcServer) Deregister() error {
	config := s.Options()
	var advt, host string
	var port int

	// check the advertise address first
	// if it exists then use it, otherwise
	// use the address
	if len(config.Advertise) > 0 {
		advt = config.Advertise
	} else {
		advt = config.Address
	}

	parts := strings.Split(advt, ":")
	if len(parts) > 1 {
		host = strings.Join(parts[:len(parts)-1], ":")
		port, _ = strconv.Atoi(parts[len(parts)-1])
	} else {
		host = parts[0]
	}

	addr, err := addr.Extract(host)
	if err != nil {
		return err
	}

	node := &registry.Node{
		Id:      config.Name + "-" + config.Id,
		Address: addr,
		Port:    port,
	}

	service := &registry.Service{
		Name:    config.Name,
		Version: config.Version,
		Nodes:   []*registry.Node{node},
	}

	log.Logf("Deregistering node: %s", node.Id)
	if err := config.Registry.Deregister(service); err != nil {
		return err
	}

	s.Lock()

	if !s.registered {
		s.Unlock()
		return nil
	}

	s.registered = false

	for sb, subs := range s.subscribers {
		for _, sub := range subs {
			log.Logf("Unsubscribing from topic: %s", sub.Topic())
			sub.Unsubscribe()
		}
		s.subscribers[sb] = nil
	}

	s.Unlock()
	return nil
}

func (s *rpcServer) Start() error {
	registerDebugHandler(s)
	config := s.Options()

	// start listening on the transport
	ts, err := config.Transport.Listen(config.Address)
	if err != nil {
		return err
	}

	log.Logf("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())

	// swap address
	s.Lock()
	addr := s.opts.Address
	s.opts.Address = ts.Addr()
	s.Unlock()

	// connect to the broker
	if err := config.Broker.Connect(); err != nil {
		return err
	}

	log.Logf("Broker [%s] Listening on %s", config.Broker.String(), config.Broker.Address())

	// announce self to the world
	if err := s.Register(); err != nil {
		log.Log("Server register error: ", err)
	}

	exit := make(chan bool)

	go func() {
		for {
			// listen for connections
			err := ts.Accept(s.ServeConn)

			// TODO: listen for messages
			// msg := broker.Exchange(service).Consume()

			select {
			// check if we're supposed to exit
			case <-exit:
				return
			// check the error and backoff
			default:
				if err != nil {
					log.Logf("Accept error: %v", err)
					time.Sleep(time.Second)
					continue
				}
			}

			// no error just exit
			return
		}
	}()

	go func() {
		t := new(time.Ticker)

		// only process if it exists
		if s.opts.RegisterInterval > time.Duration(0) {
			// new ticker
			t = time.NewTicker(s.opts.RegisterInterval)
		}

		// return error chan
		var ch chan error

	Loop:
		for {
			select {
			// register self on interval
			case <-t.C:
				if err := s.Register(); err != nil {
					log.Log("Server register error: ", err)
				}
			// wait for exit
			case ch = <-s.exit:
				t.Stop()
				close(exit)
				break Loop
			}
		}

		// deregister self
		if err := s.Deregister(); err != nil {
			log.Log("Server deregister error: ", err)
		}

		// wait for requests to finish
		if wait(s.opts.Context) {
			s.wg.Wait()
		}

		// close transport listener
		ch <- ts.Close()

		// disconnect the broker
		config.Broker.Disconnect()

		// swap back address
		s.Lock()
		s.opts.Address = addr
		s.Unlock()
	}()

	return nil
}

func (s *rpcServer) Stop() error {
	ch := make(chan error)
	s.exit <- ch
	return <-ch
}

func (s *rpcServer) String() string {
	return "rpc"
}
<commit_msg>add more verbose output<commit_after>package server

import (
	"context"
	"fmt"
	"runtime/debug"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/micro/go-log"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/codec"
	"github.com/micro/go-micro/metadata"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/transport"

	"github.com/micro/util/go/lib/addr"
)

type rpcServer struct {
	router *router
	exit   chan chan error

	sync.RWMutex
	opts        Options
	handlers    map[string]Handler
	subscribers map[*subscriber][]broker.Subscriber
	// used for first registration
	registered bool
	// graceful exit
	wg sync.WaitGroup
}

func newRpcServer(opts ...Option) Server {
	options := newOptions(opts...)
	return &rpcServer{
		opts:        options,
		router:      DefaultRouter,
		handlers:    make(map[string]Handler),
		subscribers: make(map[*subscriber][]broker.Subscriber),
		exit:        make(chan chan error),
	}
}

// ServeConn serves a single connection
func (s *rpcServer) ServeConn(sock transport.Socket) {
	defer func() {
		// close socket
		sock.Close()

		if r := recover(); r != nil {
			log.Log("panic recovered: ", r)
			log.Log(string(debug.Stack()))
		}
	}()

	for {
		var msg transport.Message
		if err := sock.Recv(&msg); err != nil {
			return
		}

		// add to wait group
		s.wg.Add(1)

		// we use this Timeout header to set a server deadline
		to := msg.Header["Timeout"]
		// we use this Content-Type header to identify the codec needed
		ct := msg.Header["Content-Type"]

		// strip our headers
		hdr := make(map[string]string)
		for k, v := range msg.Header {
			hdr[k] = v
		}

		// set local/remote ips
		hdr["Local"] = sock.Local()
		hdr["Remote"] = sock.Remote()

		// create new context
		ctx := metadata.NewContext(context.Background(), hdr)

		// set the timeout if we have it
		if len(to) > 0 {
			if n, err := strconv.ParseUint(to, 10, 64); err == nil {
				ctx, _ = context.WithTimeout(ctx, time.Duration(n))
			}
		}

		// no content type
		if len(ct) == 0 {
			msg.Header["Content-Type"] = DefaultContentType
			ct = DefaultContentType
		}

		// setup old protocol
		cf := setupProtocol(&msg)

		// no old codec
		if cf == nil {
			// TODO: needs better error handling
			var err error
			if cf, err = s.newCodec(ct); err != nil {
				sock.Send(&transport.Message{
					Header: map[string]string{
						"Content-Type": "text/plain",
					},
					Body: []byte(err.Error()),
				})
				s.wg.Done()
				return
			}
		}

		rcodec := newRpcCodec(&msg, sock, cf)

		// internal request
		request := &rpcRequest{
			service:     getHeader("Micro-Service", msg.Header),
			method:      getHeader("Micro-Method", msg.Header),
			endpoint:    getHeader("Micro-Endpoint", msg.Header),
			contentType: ct,
			codec:       rcodec,
			header:      msg.Header,
			body:        msg.Body,
			socket:      sock,
			stream:      true,
		}

		// internal response
		response := &rpcResponse{
			header: make(map[string]string),
			socket: sock,
			codec:  rcodec,
		}

		// set router
		r := s.opts.Router

		// if nil use default router
		if s.opts.Router == nil {
			r = s.router
		}

		// create a wrapped function
		handler := func(ctx context.Context, req Request, rsp interface{}) error {
			return r.ServeRequest(ctx, req, rsp.(Response))
		}

		for i := len(s.opts.HdlrWrappers); i > 0; i-- {
			handler = s.opts.HdlrWrappers[i-1](handler)
		}

		// TODO: handle error better
		if err := handler(ctx, request, response); err != nil {
			if err != lastStreamResponseError {
				// write an error response
				err = rcodec.Write(&codec.Message{
					Header: msg.Header,
					Error:  err.Error(),
					Type:   codec.Error,
				}, nil)
				// could not write the error response
				if err != nil {
					log.Logf("rpc: unable to write error response: %v", err)
				}
			}
			s.wg.Done()
			return
		}

		// done
		s.wg.Done()
	}
}

func (s *rpcServer) newCodec(contentType string) (codec.NewCodec, error) {
	if cf, ok := s.opts.Codecs[contentType]; ok {
		return cf, nil
	}
	if cf, ok := DefaultCodecs[contentType]; ok {
		return cf, nil
	}
	return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
}

func (s *rpcServer) Options() Options {
	s.RLock()
	opts := s.opts
	s.RUnlock()
	return opts
}

func (s *rpcServer) Init(opts ...Option) error {
	s.Lock()
	for _, opt := range opts {
		opt(&s.opts)
	}
	s.Unlock()
	return nil
}

func (s *rpcServer) NewHandler(h interface{}, opts ...HandlerOption) Handler {
	return s.router.NewHandler(h, opts...)
}

func (s *rpcServer) Handle(h Handler) error {
	s.Lock()
	defer s.Unlock()

	if err := s.router.Handle(h); err != nil {
		return err
	}

	s.handlers[h.Name()] = h

	return nil
}

func (s *rpcServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
	return newSubscriber(topic, sb, opts...)
}

func (s *rpcServer) Subscribe(sb Subscriber) error {
	sub, ok := sb.(*subscriber)
	if !ok {
		return fmt.Errorf("invalid subscriber: expected *subscriber")
	}
	if len(sub.handlers) == 0 {
		return fmt.Errorf("invalid subscriber: no handler functions")
	}

	if err := validateSubscriber(sb); err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()
	_, ok = s.subscribers[sub]
	if ok {
		return fmt.Errorf("subscriber %v already exists", s)
	}
	s.subscribers[sub] = nil
	return nil
}

func (s *rpcServer) Register() error {
	// parse address for host, port
	config := s.Options()
	var advt, host string
	var port int

	// check the advertise address first
	// if it exists then use it, otherwise
	// use the address
	if len(config.Advertise) > 0 {
		advt = config.Advertise
	} else {
		advt = config.Address
	}

	parts := strings.Split(advt, ":")
	if len(parts) > 1 {
		host = strings.Join(parts[:len(parts)-1], ":")
		port, _ = strconv.Atoi(parts[len(parts)-1])
	} else {
		host = parts[0]
	}

	addr, err := addr.Extract(host)
	if err != nil {
		return err
	}

	// make copy of metadata
	md := make(metadata.Metadata)
	for k, v := range config.Metadata {
		md[k] = v
	}

	// register service
	node := &registry.Node{
		Id:       config.Name + "-" + config.Id,
		Address:  addr,
		Port:     port,
		Metadata: md,
	}

	node.Metadata["transport"] = config.Transport.String()
	node.Metadata["broker"] = config.Broker.String()
	node.Metadata["server"] = s.String()
	node.Metadata["registry"] = config.Registry.String()
	node.Metadata["protocol"] = "mucp"

	s.RLock()
	// Maps are ordered randomly, sort the keys for consistency
	var handlerList []string
	for n, e := range s.handlers {
		// Only advertise non internal handlers
		if !e.Options().Internal {
			handlerList = append(handlerList, n)
		}
	}
	sort.Strings(handlerList)

	var subscriberList []*subscriber
	for e := range s.subscribers {
		// Only advertise non internal subscribers
		if !e.Options().Internal {
			subscriberList = append(subscriberList, e)
		}
	}
	sort.Slice(subscriberList, func(i, j int) bool {
		return subscriberList[i].topic > subscriberList[j].topic
	})

	var endpoints []*registry.Endpoint
	for _, n := range handlerList {
		endpoints = append(endpoints, s.handlers[n].Endpoints()...)
	}
	for _, e := range subscriberList {
		endpoints = append(endpoints, e.Endpoints()...)
	}
	s.RUnlock()

	service := &registry.Service{
		Name:      config.Name,
		Version:   config.Version,
		Nodes:     []*registry.Node{node},
		Endpoints: endpoints,
	}

	s.Lock()
	registered := s.registered
	s.Unlock()

	if !registered {
		log.Logf("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
	}

	// create registry options
	rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}

	if err := config.Registry.Register(service, rOpts...); err != nil {
		return err
	}

	// already registered? don't need to register subscribers
	if registered {
		return nil
	}

	s.Lock()
	defer s.Unlock()

	s.registered = true

	for sb, _ := range s.subscribers {
		handler := s.createSubHandler(sb, s.opts)
		var opts []broker.SubscribeOption
		if queue := sb.Options().Queue; len(queue) > 0 {
			opts = append(opts, broker.Queue(queue))
		}
		if cx := sb.Options().Context; cx != nil {
			opts = append(opts, broker.SubscribeContext(cx))
		}
		sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
		if err != nil {
			return err
		}
		s.subscribers[sb] = []broker.Subscriber{sub}
	}

	return nil
}

func (s *rpcServer) Deregister() error {
	config := s.Options()
	var advt, host string
	var port int

	// check the advertise address first
	// if it exists then use it, otherwise
	// use the address
	if len(config.Advertise) > 0 {
		advt = config.Advertise
	} else {
		advt = config.Address
	}

	parts := strings.Split(advt, ":")
	if len(parts) > 1 {
		host = strings.Join(parts[:len(parts)-1], ":")
		port, _ = strconv.Atoi(parts[len(parts)-1])
	} else {
		host = parts[0]
	}

	addr, err := addr.Extract(host)
	if err != nil {
		return err
	}

	node := &registry.Node{
		Id:      config.Name + "-" + config.Id,
		Address: addr,
		Port:    port,
	}

	service := &registry.Service{
		Name:    config.Name,
		Version: config.Version,
		Nodes:   []*registry.Node{node},
	}

	log.Logf("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
	if err := config.Registry.Deregister(service); err != nil {
		return err
	}

	s.Lock()

	if !s.registered {
		s.Unlock()
		return nil
	}

	s.registered = false

	for sb, subs := range s.subscribers {
		for _, sub := range subs {
			log.Logf("Unsubscribing from topic: %s", sub.Topic())
			sub.Unsubscribe()
		}
		s.subscribers[sb] = nil
	}

	s.Unlock()
	return nil
}

func (s *rpcServer) Start() error {
	registerDebugHandler(s)
	config := s.Options()

	// start listening on the transport
	ts, err := config.Transport.Listen(config.Address)
	if err != nil {
		return err
	}

	log.Logf("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())

	// swap address
	s.Lock()
	addr := s.opts.Address
	s.opts.Address = ts.Addr()
	s.Unlock()

	// connect to the broker
	if err := config.Broker.Connect(); err != nil {
		return err
	}

	log.Logf("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())

	// announce self to the world
	if err := s.Register(); err != nil {
		log.Log("Server register error: ", err)
	}

	exit := make(chan bool)

	go func() {
		for {
			// listen for connections
			err := ts.Accept(s.ServeConn)

			// TODO: listen for messages
			// msg := broker.Exchange(service).Consume()

			select {
			// check if we're supposed to exit
			case <-exit:
				return
			// check the error and backoff
			default:
				if err != nil {
					log.Logf("Accept error: %v", err)
					time.Sleep(time.Second)
					continue
				}
			}

			// no error just exit
			return
		}
	}()

	go func() {
		t := new(time.Ticker)

		// only process if it exists
		if s.opts.RegisterInterval > time.Duration(0) {
			// new ticker
			t = time.NewTicker(s.opts.RegisterInterval)
		}

		// return error chan
		var ch chan error

	Loop:
		for {
			select {
			// register self on interval
			case <-t.C:
				if err := s.Register(); err != nil {
					log.Log("Server register error: ", err)
				}
			// wait for exit
			case ch = <-s.exit:
				t.Stop()
				close(exit)
				break Loop
			}
		}

		// deregister self
		if err := s.Deregister(); err != nil {
			log.Log("Server deregister error: ", err)
		}

		// wait for requests to finish
		if wait(s.opts.Context) {
			s.wg.Wait()
		}

		// close transport listener
		ch <- ts.Close()

		// disconnect the broker
		config.Broker.Disconnect()

		// swap back address
		s.Lock()
		s.opts.Address = addr
		s.Unlock()
	}()

	return nil
}

func (s *rpcServer) Stop() error {
	ch := make(chan error)
	s.exit <- ch
	return <-ch
}

func (s *rpcServer) String() string {
	return "rpc"
}
<|endoftext|>


<commit_before>package GoSDK

import (
	//"fmt"
	"strconv"
)

const (
	_LIB_PREAMBLE  = "/codeadmin/v/2/library"
	_HIST_PREAMBLE = "/codeadmin/v/2/history/library"
)

func (d *DevClient) GetAllLibraries() ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

func (d *DevClient) GetLibraries(systemKey string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE+"/"+systemKey, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

func (d *DevClient) GetLibrary(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

func (d *DevClient) CreateLibrary(systemKey, name string, data map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_LIB_PREAMBLE+"/"+systemKey+"/"+name, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

func (d *DevClient) UpdateLibrary(systemKey, name string, data map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := put(_LIB_PREAMBLE+"/"+systemKey+"/"+name, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

func (d *DevClient) DeleteLibrary(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(_LIB_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return err
	}
	return nil
}

func (d *DevClient) GetVersionHistory(systemKey, name string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_HIST_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

func (d *DevClient) GetVersion(systemKey, name string, version int) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_HIST_PREAMBLE+"/"+systemKey+"/"+name+"/"+strconv.Itoa(version), nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}
<commit_msg>library documentation<commit_after>package GoSDK

import (
	//"fmt"
	"strconv"
)

const (
	_LIB_PREAMBLE  = "/codeadmin/v/2/library"
	_HIST_PREAMBLE = "/codeadmin/v/2/history/library"
)

//GetAllLibraries returns descriptions of all libraries for a platform instance
func (d *DevClient) GetAllLibraries() ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

//GetLibrary returns a list of libraries for a system
func (d *DevClient) GetLibraries(systemKey string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE+"/"+systemKey, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

//GetLibrary returns information about a specific library
func (d *DevClient) GetLibrary(systemKey, name string) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_LIB_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

//CreateLibrary allows the developer to create a library to be called by other service functions
func (d *DevClient) CreateLibrary(systemKey, name string, data map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := post(_LIB_PREAMBLE+"/"+systemKey+"/"+name, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

//UpdateLibrary allows the developer to change the content of the library
func (d *DevClient) UpdateLibrary(systemKey, name string, data map[string]interface{}) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := put(_LIB_PREAMBLE+"/"+systemKey+"/"+name, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

//DeleteLibrary allows the developer to remove library content
func (d *DevClient) DeleteLibrary(systemKey, name string) error {
	creds, err := d.credentials()
	if err != nil {
		return err
	}
	resp, err := delete(_LIB_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return err
	}
	return nil
}

//GetVersionHistory returns a slice of library descriptions corresponding to each library
func (d *DevClient) GetVersionHistory(systemKey, name string) ([]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_HIST_PREAMBLE+"/"+systemKey+"/"+name, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

//GetVersion gets the current version of a library
func (d *DevClient) GetVersion(systemKey, name string, version int) (map[string]interface{}, error) {
	creds, err := d.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(_HIST_PREAMBLE+"/"+systemKey+"/"+name+"/"+strconv.Itoa(version), nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"

	clusterConfig "github.com/lxc/lxd/lxd/cluster/config"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/node"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
)

func daemonConfigRender(state *state.State) (map[string]any, error) {
	config := map[string]any{}

	// Turn the config into a JSON-compatible map
	err := state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
		clusterConfig, err := clusterConfig.Load(tx)
		if err != nil {
			return err
		}
		for key, value := range clusterConfig.Dump() {
			config[key] = value
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	err = state.DB.Node.Transaction(func(tx *db.NodeTx) error {
		nodeConfig, err := node.ConfigLoad(tx)
		if err != nil {
			return err
		}
		for key, value := range nodeConfig.Dump() {
			config[key] = value
		}
		return nil
	})
	if err != nil {
		return nil, err
	}

	return config, nil
}

func daemonConfigSetProxy(d *Daemon, config *clusterConfig.Config) {
	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config.ProxyHTTPS(),
		config.ProxyHTTP(),
		config.ProxyIgnoreHosts(),
	)
}
<commit_msg>lxd/daemon_config: Use GlobalConfig<commit_after>package main

import (
	clusterConfig "github.com/lxc/lxd/lxd/cluster/config"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/node"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
)

func daemonConfigRender(state *state.State) (map[string]any, error) {
	config := map[string]any{}

	// Turn the config into a JSON-compatible map.
	for key, value := range state.GlobalConfig.Dump() {
		config[key] = value
	}

	// Apply the local config.
	err := state.DB.Node.Transaction(func(tx *db.NodeTx) error {
		nodeConfig, err := node.ConfigLoad(tx)
		if err != nil {
			return err
		}

		for key, value := range nodeConfig.Dump() {
			config[key] = value
		}

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

	return config, nil
}

func daemonConfigSetProxy(d *Daemon, config *clusterConfig.Config) {
	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config.ProxyHTTPS(),
		config.ProxyHTTP(),
		config.ProxyIgnoreHosts(),
	)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

type storageBtrfs struct {
	d *Daemon

	storageShared
}

func (s *storageBtrfs) Init(config map[string]interface{}) (storage, error) {
	s.sType = storageTypeBtrfs
	s.sTypeName = storageTypeToString(s.sType)
	if err := s.initShared(); err != nil {
		return s, err
	}

	out, err := exec.LookPath("btrfs")
	if err != nil || len(out) == 0 {
		return s, fmt.Errorf("The 'btrfs' tool isn't available")
	}

	output, err := exec.Command("btrfs", "version").CombinedOutput()
	if err != nil {
		return s, fmt.Errorf("The 'btrfs' tool isn't working properly")
	}

	count, err := fmt.Sscanf(strings.SplitN(string(output), " ", 2)[1], "v%s\n", &s.sTypeVersion)
	if err != nil || count != 1 {
		return s, fmt.Errorf("The 'btrfs' tool isn't working properly")
	}

	return s, nil
}

func (s *storageBtrfs) ContainerCreate(container container) error {
	cPath := container.PathGet("")

	// MkdirAll the pardir of the BTRFS Subvolume.
	if err := os.MkdirAll(filepath.Dir(cPath), 0755); err != nil {
		return err
	}

	// Create the BTRFS Subvolume
	err := s.subvolCreate(cPath)
	if err != nil {
		return err
	}

	if container.IsPrivileged() {
		if err := os.Chmod(cPath, 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageBtrfs) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	imageSubvol := fmt.Sprintf(
		"%s.btrfs",
		shared.VarPath("images", imageFingerprint))

	// Create the btrfs subvol of the image first if it doesn exists.
	if !shared.PathExists(imageSubvol) {
		if err := s.ImageCreate(imageFingerprint); err != nil {
			return err
		}
	}

	// Now make a snapshot of the image subvol
	err := s.subvolSnapshot(imageSubvol, container.PathGet(""), false)
	if err != nil {
		return err
	}

	if !container.IsPrivileged() {
		if err = s.shiftRootfs(container); err != nil {
			s.ContainerDelete(container)
			return err
		}
	} else {
		if err := os.Chmod(container.PathGet(""), 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageBtrfs) ContainerDelete(container container) error {
	cPath := container.PathGet("")

	// First remove the subvol (if it was one).
	if s.isSubvolume(cPath) {
		if err := s.subvolDelete(cPath); err != nil {
			return err
		}
	}

	// Then the directory (if it still exists).
	err := os.RemoveAll(cPath)
	if err != nil {
		s.log.Error("ContainerDelete: failed", log.Ctx{"cPath": cPath, "err": err})
		return fmt.Errorf("Error cleaning up %s: %s", cPath, err)
	}

	return nil
}

func (s *storageBtrfs) ContainerCopy(container container, sourceContainer container) error {

	subvol := sourceContainer.PathGet("")
	dpath := container.PathGet("")

	if s.isSubvolume(subvol) {
		err := s.subvolSnapshot(subvol, dpath, false)
		if err != nil {
			return err
		}
	} else {
		// Create the BTRFS Container.
		if err := s.ContainerCreate(container); err != nil {
			return err
		}

		/*
		 * Copy by using rsync
		 */
		output, err := storageRsyncCopy(
			sourceContainer.PathGet(""),
			container.PathGet(""))
		if err != nil {
			s.ContainerDelete(container)

			s.log.Error("ContainerCopy: rsync failed", log.Ctx{"output": string(output)})
			return fmt.Errorf("rsync failed: %s", string(output))
		}
	}

	if err := s.setUnprivUserAcl(sourceContainer, dpath); err != nil {
		return err
	}

	return container.TemplateApply("copy")
}

func (s *storageBtrfs) ContainerStart(container container) error {
	return nil
}

func (s *storageBtrfs) ContainerStop(container container) error {
	return nil
}

func (s *storageBtrfs) ContainerRename(
	container container, newName string) error {

	oldPath := container.PathGet("")
	newPath := container.PathGet(newName)

	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// TODO: No TemplateApply here?
	return nil
}

func (s *storageBtrfs) ContainerRestore(
	container container, sourceContainer container) error {

	targetSubVol := container.PathGet("")
	sourceSubVol := sourceContainer.PathGet("")
	sourceBackupPath := container.PathGet("") + ".back"

	// Create a backup of the container
	err := os.Rename(container.PathGet(""), sourceBackupPath)
	if err != nil {
		return err
	}

	var failure error
	if s.isSubvolume(sourceSubVol) {
		// Restore using btrfs snapshots.
		err := s.subvolSnapshot(sourceSubVol, targetSubVol, false)
		if err != nil {
			failure = err
		}
	} else {
		// Restore using rsync but create a btrfs subvol.
		if err := s.subvolCreate(targetSubVol); err == nil {
			output, err := storageRsyncCopy(
				sourceSubVol,
				targetSubVol)

			if err != nil {
				s.log.Error(
					"ContainerRestore: rsync failed",
					log.Ctx{"output": string(output)})

				failure = err
			}
		} else {
			failure = err
		}
	}

	// Now allow unprivileged users to access its data.
	if err := s.setUnprivUserAcl(sourceContainer, targetSubVol); err != nil {
		failure = err
	}

	if failure != nil {
		// Restore original container
		s.ContainerDelete(container)
		os.Rename(sourceBackupPath, container.PathGet(""))
	} else {
		// Remove the backup, we made
		if s.isSubvolume(sourceBackupPath) {
			return s.subvolDelete(sourceBackupPath)
		}
		os.RemoveAll(sourceBackupPath)
	}

	return failure
}

func (s *storageBtrfs) ContainerSnapshotCreate(
	snapshotContainer container, sourceContainer container) error {

	subvol := sourceContainer.PathGet("")
	dpath := snapshotContainer.PathGet("")

	if s.isSubvolume(subvol) {
		// Create a readonly snapshot of the source.
		err := s.subvolSnapshot(subvol, dpath, true)
		if err != nil {
			s.ContainerDelete(snapshotContainer)
			return err
		}
	} else {
		/*
		 * Copy by using rsync
		 */
		output, err := storageRsyncCopy(
			subvol,
			dpath)
		if err != nil {
			s.ContainerDelete(snapshotContainer)

			s.log.Error(
				"ContainerSnapshotCreate: rsync failed",
				log.Ctx{"output": string(output)})
			return fmt.Errorf("rsync failed: %s", string(output))
		}
	}

	return nil
}
func (s *storageBtrfs) ContainerSnapshotDelete(
	snapshotContainer container) error {

	err := s.ContainerDelete(snapshotContainer)
	if err != nil {
		return fmt.Errorf("Error deleting snapshot %s: %s", snapshotContainer.NameGet(), err)
	}

	oldPathParent := filepath.Dir(snapshotContainer.PathGet(""))
	if ok, _ := shared.PathIsEmpty(oldPathParent); ok {
		os.Remove(oldPathParent)
	}
	return nil
}

// ContainerSnapshotRename renames a snapshot of a container.
func (s *storageBtrfs) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.PathGet("")
	newPath := snapshotContainer.PathGet(newName)

	// Create the new parent.
	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if !shared.PathExists(filepath.Dir(newPath)) {
			os.MkdirAll(filepath.Dir(newPath), 0700)
		}
	}

	// Now rename the snapshot.
	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// Remove the old parent (on container rename) if its empty.
	if strings.Contains(snapshotContainer.NameGet(), "/") {
		if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
			os.Remove(filepath.Dir(oldPath))
		}
	}

	return nil
}

func (s *storageBtrfs) ImageCreate(fingerprint string) error {
	imagePath := shared.VarPath("images", fingerprint)
	subvol := fmt.Sprintf("%s.btrfs", imagePath)

	if err := s.subvolCreate(subvol); err != nil {
		return err
	}

	if err := untarImage(imagePath, subvol); err != nil {
		return err
	}

	return nil
}

func (s *storageBtrfs) ImageDelete(fingerprint string) error {
	imagePath := shared.VarPath("images", fingerprint)
	subvol := fmt.Sprintf("%s.btrfs", imagePath)

	return s.subvolDelete(subvol)
}

func (s *storageBtrfs) subvolCreate(subvol string) error {
	parentDestPath := filepath.Dir(subvol)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"create",
		subvol).CombinedOutput()
	if err != nil {
		s.log.Debug(
			"subvolume create failed",
			log.Ctx{"subvol": subvol, "output": string(output)},
		)
		return fmt.Errorf(
			"btrfs subvolume create failed, subvol=%s, output%s",
			subvol,
			string(output),
		)
	}

	return nil
}

func (s *storageBtrfs) subvolDelete(subvol string) error {
	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"delete",
		subvol,
	).CombinedOutput()

	if err != nil {
		s.log.Warn(
			"subvolume delete failed",
			log.Ctx{"subvol": subvol, "output": string(output)},
		)
	}
	return nil
}

/*
 * subvolSnapshot creates a snapshot of "source" to "dest"
 * the result will be readonly if "readonly" is True.
 */
func (s *storageBtrfs) subvolSnapshot(source string, dest string, readonly bool) error {
	parentDestPath := filepath.Dir(dest)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	var output []byte
	var err error
	if readonly {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			"-r",
			source,
			dest).CombinedOutput()
	} else {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			source,
			dest).CombinedOutput()
	}
	if err != nil {
		s.log.Error(
			"subvolume snapshot failed",
			log.Ctx{"source": source, "dest": dest, "output": string(output)},
		)
		return fmt.Errorf(
			"subvolume snapshot failed, source=%s, dest=%s, output=%s",
			source,
			dest,
			string(output),
		)
	}

	return err
}

/*
 * isSubvolume returns true if the given Path is a btrfs subvolume
 * else false.
 */
func (s *storageBtrfs) isSubvolume(subvolPath string) bool {
	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"show",
		subvolPath).CombinedOutput()
	if err != nil || strings.HasPrefix(string(output), "ERROR: ") {
		return false
	}

	return true
}
<commit_msg>btrfs: Recursive snapshot and removal<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

type storageBtrfs struct {
	d *Daemon

	storageShared
}

func (s *storageBtrfs) Init(config map[string]interface{}) (storage, error) {
	s.sType = storageTypeBtrfs
	s.sTypeName = storageTypeToString(s.sType)
	if err := s.initShared(); err != nil {
		return s, err
	}

	out, err := exec.LookPath("btrfs")
	if err != nil || len(out) == 0 {
		return s, fmt.Errorf("The 'btrfs' tool isn't available")
	}

	output, err := exec.Command("btrfs", "version").CombinedOutput()
	if err != nil {
		return s, fmt.Errorf("The 'btrfs' tool isn't working properly")
	}

	count, err := fmt.Sscanf(strings.SplitN(string(output), " ", 2)[1], "v%s\n", &s.sTypeVersion)
	if err != nil || count != 1 {
		return s, fmt.Errorf("The 'btrfs' tool isn't working properly")
	}

	return s, nil
}

func (s *storageBtrfs) ContainerCreate(container container) error {
	cPath := container.PathGet("")

	// MkdirAll the pardir of the BTRFS Subvolume.
	if err := os.MkdirAll(filepath.Dir(cPath), 0755); err != nil {
		return err
	}

	// Create the BTRFS Subvolume
	err := s.subvolCreate(cPath)
	if err != nil {
		return err
	}

	if container.IsPrivileged() {
		if err := os.Chmod(cPath, 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageBtrfs) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	imageSubvol := fmt.Sprintf(
		"%s.btrfs",
		shared.VarPath("images", imageFingerprint))

	// Create the btrfs subvol of the image first if it doesn exists.
	if !shared.PathExists(imageSubvol) {
		if err := s.ImageCreate(imageFingerprint); err != nil {
			return err
		}
	}

	// Now make a snapshot of the image subvol
	err := s.subvolsSnapshot(imageSubvol, container.PathGet(""), false)
	if err != nil {
		return err
	}

	if !container.IsPrivileged() {
		if err = s.shiftRootfs(container); err != nil {
			s.ContainerDelete(container)
			return err
		}
	} else {
		if err := os.Chmod(container.PathGet(""), 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageBtrfs) ContainerDelete(container container) error {
	cPath := container.PathGet("")

	// First remove the subvol (if it was one).
	if s.isSubvolume(cPath) {
		if err := s.subvolsDelete(cPath); err != nil {
			return err
		}
	}

	// Then the directory (if it still exists).
	err := os.RemoveAll(cPath)
	if err != nil {
		s.log.Error("ContainerDelete: failed", log.Ctx{"cPath": cPath, "err": err})
		return fmt.Errorf("Error cleaning up %s: %s", cPath, err)
	}

	return nil
}

func (s *storageBtrfs) ContainerCopy(container container, sourceContainer container) error {

	subvol := sourceContainer.PathGet("")
	dpath := container.PathGet("")

	if s.isSubvolume(subvol) {
		// Snapshot the sourcecontainer
		err := s.subvolsSnapshot(subvol, dpath, false)
		if err != nil {
			return err
		}
	} else {
		// Create the BTRFS Container.
		if err := s.ContainerCreate(container); err != nil {
			return err
		}

		/*
		 * Copy by using rsync
		 */
		output, err := storageRsyncCopy(
			sourceContainer.PathGet(""),
			container.PathGet(""))
		if err != nil {
			s.ContainerDelete(container)

			s.log.Error("ContainerCopy: rsync failed", log.Ctx{"output": string(output)})
			return fmt.Errorf("rsync failed: %s", string(output))
		}
	}

	if err := s.setUnprivUserAcl(sourceContainer, dpath); err != nil {
		s.ContainerDelete(container)
		return err
	}

	return container.TemplateApply("copy")
}

func (s *storageBtrfs) ContainerStart(container container) error {
	return nil
}

func (s *storageBtrfs) ContainerStop(container container) error {
	return nil
}

func (s *storageBtrfs) ContainerRename(
	container container, newName string) error {

	oldPath := container.PathGet("")
	newPath := container.PathGet(newName)

	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// TODO: No TemplateApply here?
	return nil
}

func (s *storageBtrfs) ContainerRestore(
	container container, sourceContainer container) error {

	targetSubVol := container.PathGet("")
	sourceSubVol := sourceContainer.PathGet("")
	sourceBackupPath := container.PathGet("") + ".back"

	// Create a backup of the container
	err := os.Rename(container.PathGet(""), sourceBackupPath)
	if err != nil {
		return err
	}

	var failure error
	if s.isSubvolume(sourceSubVol) {
		// Restore using btrfs snapshots.
		err := s.subvolsSnapshot(sourceSubVol, targetSubVol, false)
		if err != nil {
			failure = err
		}
	} else {
		// Restore using rsync but create a btrfs subvol.
		if err := s.subvolCreate(targetSubVol); err == nil {
			output, err := storageRsyncCopy(
				sourceSubVol,
				targetSubVol)

			if err != nil {
				s.log.Error(
					"ContainerRestore: rsync failed",
					log.Ctx{"output": string(output)})

				failure = err
			}
		} else {
			failure = err
		}
	}

	// Now allow unprivileged users to access its data.
	if err := s.setUnprivUserAcl(sourceContainer, targetSubVol); err != nil {
		failure = err
	}

	if failure != nil {
		// Restore original container
		s.ContainerDelete(container)
		os.Rename(sourceBackupPath, container.PathGet(""))
	} else {
		// Remove the backup, we made
		if s.isSubvolume(sourceBackupPath) {
			return s.subvolDelete(sourceBackupPath)
		}
		os.RemoveAll(sourceBackupPath)
	}

	return failure
}

func (s *storageBtrfs) ContainerSnapshotCreate(
	snapshotContainer container, sourceContainer container) error {

	subvol := sourceContainer.PathGet("")
	dpath := snapshotContainer.PathGet("")

	if s.isSubvolume(subvol) {
		// Create a readonly snapshot of the source.
		err := s.subvolsSnapshot(subvol, dpath, true)
		if err != nil {
			s.ContainerSnapshotDelete(snapshotContainer)
			return err
		}
	} else {
		/*
		 * Copy by using rsync
		 */
		output, err := storageRsyncCopy(
			subvol,
			dpath)
		if err != nil {
			s.ContainerSnapshotDelete(snapshotContainer)

			s.log.Error(
				"ContainerSnapshotCreate: rsync failed",
				log.Ctx{"output": string(output)})
			return fmt.Errorf("rsync failed: %s", string(output))
		}
	}

	return nil
}
func (s *storageBtrfs) ContainerSnapshotDelete(
	snapshotContainer container) error {

	err := s.ContainerDelete(snapshotContainer)
	if err != nil {
		return fmt.Errorf("Error deleting snapshot %s: %s", snapshotContainer.NameGet(), err)
	}

	oldPathParent := filepath.Dir(snapshotContainer.PathGet(""))
	if ok, _ := shared.PathIsEmpty(oldPathParent); ok {
		os.Remove(oldPathParent)
	}
	return nil
}

// ContainerSnapshotRename renames a snapshot of a container.
func (s *storageBtrfs) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.PathGet("")
	newPath := snapshotContainer.PathGet(newName)

	// Create the new parent.
	if !shared.PathExists(filepath.Dir(newPath)) {
		os.MkdirAll(filepath.Dir(newPath), 0700)
	}

	// Now rename the snapshot.
	if !s.isSubvolume(oldPath) {
		if err := os.Rename(oldPath, newPath); err != nil {
			return err
		}
	} else {
		if err := s.subvolsSnapshot(oldPath, newPath, true); err != nil {
			return err
		}
		if err := s.subvolsDelete(oldPath); err != nil {
			return err
		}
	}

	// Remove the old parent (on container rename) if its empty.
	if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
		os.Remove(filepath.Dir(oldPath))
	}

	return nil
}

func (s *storageBtrfs) ImageCreate(fingerprint string) error {
	imagePath := shared.VarPath("images", fingerprint)
	subvol := fmt.Sprintf("%s.btrfs", imagePath)

	if err := s.subvolCreate(subvol); err != nil {
		return err
	}

	if err := untarImage(imagePath, subvol); err != nil {
		return err
	}

	return nil
}

func (s *storageBtrfs) ImageDelete(fingerprint string) error {
	imagePath := shared.VarPath("images", fingerprint)
	subvol := fmt.Sprintf("%s.btrfs", imagePath)

	return s.subvolDelete(subvol)
}

func (s *storageBtrfs) subvolCreate(subvol string) error {
	parentDestPath := filepath.Dir(subvol)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"create",
		subvol).CombinedOutput()
	if err != nil {
		s.log.Debug(
			"subvolume create failed",
			log.Ctx{"subvol": subvol, "output": string(output)},
		)
		return fmt.Errorf(
			"btrfs subvolume create failed, subvol=%s, output%s",
			subvol,
			string(output),
		)
	}

	return nil
}

func (s *storageBtrfs) subvolDelete(subvol string) error {
	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"delete",
		subvol,
	).CombinedOutput()

	if err != nil {
		s.log.Warn(
			"subvolume delete failed",
			log.Ctx{"subvol": subvol, "output": string(output)},
		)
	}
	return nil
}

// subvolsDelete is the recursive variant on subvolDelete,
// it first deletes subvolumes of the subvolume and then the
// subvolume itself.
func (s *storageBtrfs) subvolsDelete(subvol string) error {
	// Delete subsubvols.
	subsubvols, err := s.getSubVolumes(subvol)
	if err != nil {
		return err
	}

	for _, subsubvol := range subsubvols {
		s.log.Debug(
			"Deleting subsubvol",
			log.Ctx{
				"subvol":    subvol,
				"subsubvol": subsubvol})

		if err := s.subvolDelete(path.Join(subvol, subsubvol)); err != nil {
			return err
		}
	}

	// Delete the subvol itself
	if err := s.subvolDelete(subvol); err != nil {
		return err
	}

	return nil
}

/*
 * subvolSnapshot creates a snapshot of "source" to "dest"
 * the result will be readonly if "readonly" is True.
 */
func (s *storageBtrfs) subvolSnapshot(
	source string, dest string, readonly bool) error {

	parentDestPath := filepath.Dir(dest)
	if !shared.PathExists(parentDestPath) {
		if err := os.MkdirAll(parentDestPath, 0700); err != nil {
			return err
		}
	}

	if shared.PathExists(dest) {
		if err := os.Remove(dest); err != nil {
			return err
		}
	}

	var output []byte
	var err error
	if readonly {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			"-r",
			source,
			dest).CombinedOutput()
	} else {
		output, err = exec.Command(
			"btrfs",
			"subvolume",
			"snapshot",
			source,
			dest).CombinedOutput()
	}
	if err != nil {
		s.log.Error(
			"subvolume snapshot failed",
			log.Ctx{"source": source, "dest": dest, "output": string(output)},
		)
		return fmt.Errorf(
			"subvolume snapshot failed, source=%s, dest=%s, output=%s",
			source,
			dest,
			string(output),
		)
	}

	return err
}

func (s *storageBtrfs) subvolsSnapshot(
	source string, dest string, readonly bool) error {

	// Get a list of subvolumes of the root
	subsubvols, err := s.getSubVolumes(source)
	if err != nil {
		return err
	}

	if len(subsubvols) > 0 {
		// A root with subvolumes can never be readonly,
		// also don't make subvolumes readonly.
		readonly = false
	}

	// First snapshot the root
	if err := s.subvolSnapshot(source, dest, readonly); err != nil {
		return err
	}

	// Now snapshot all subvolumes of the root.
	for _, subsubvol := range subsubvols {
		if err := s.subvolSnapshot(
			path.Join(source, subsubvol),
			path.Join(dest, subsubvol),
			readonly); err != nil {

			return err
		}
	}

	return nil
}

/*
 * isSubvolume returns true if the given Path is a btrfs subvolume
 * else false.
 */
func (s *storageBtrfs) isSubvolume(subvolPath string) bool {
	output, err := exec.Command(
		"btrfs",
		"subvolume",
		"show",
		subvolPath).CombinedOutput()
	if err != nil || strings.HasPrefix(string(output), "ERROR: ") {
		return false
	}

	return true
}

// getSubVolumes returns a list of relative subvolume paths of "path".
func (s *storageBtrfs) getSubVolumes(path string) ([]string, error) {
	out, err := exec.Command(
		"btrfs",
		"inspect-internal",
		"rootid",
		path).CombinedOutput()
	if err != nil {
		return []string{}, fmt.Errorf(
			"Unable to get btrfs rootid, path='%s', err='%s'",
			path,
			err)
	}
	rootid := strings.TrimRight(string(out), "\n")

	out, err = exec.Command(
		"btrfs",
		"inspect-internal",
		"subvolid-resolve",
		rootid, path).CombinedOutput()
	if err != nil {
		return []string{}, fmt.Errorf(
			"Unable to resolve btrfs rootid, path='%s', err='%s'",
			path,
			err)
	}
	basePath := strings.TrimRight(string(out), "\n")

	out, err = exec.Command(
		"btrfs",
		"subvolume",
		"list",
		"-o",
		path).CombinedOutput()
	if err != nil {
		return []string{}, fmt.Errorf(
			"Unable to list subvolumes, path='%s', err='%s'",
			path,
			err)
	}

	result := []string{}
	lines := strings.Split(string(out), "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}

		cols := strings.Fields(line)
		result = append(result, cols[8][len(basePath):])
	}

	return result, nil
}
<|endoftext|>


<commit_before>// The census package is used to query data from the census API.
//
// It's centered more so around data from Planetside 2
package census

import (
	"strings"
)

var BaseURL = "http://census.daybreakgames.com/"
var BaseURLOld = "http://census.soe.com/"

func init() {
	//BaseURL = BaseURLOld
}

// CensusData is a struct that contains various metadata that a Census request can have.
type CensusData struct {
	Error string `json:"error"`
}

func (c *CensusData) Error() string {
	return c.error
}

// NewCensus returns a new census object given your service ID
func NewCensus(ServiceID string, Namespace string) *Census {
	c := new(Census)
	c.serviceID = ServiceID
	c.namespace = Namespace
	return c
}

// Census is the main object you use to query data
type Census struct {
	serviceID string
	namespace string
}

func (c *Census) CleanNamespace() string {
	if strings.Contains(c.namespace, ":") {
		return strings.Split(c.namespace, ":")[0]
	}
	return c.namespace
}

func (c *Census) IsEU() bool {
	if strings.Contains(c.namespace, "eu") {
		return true
	}
	return false
}
<commit_msg>Change embeded struct CensusData's error structure<commit_after>// The census package is used to query data from the census API.
//
// It's centered more so around data from Planetside 2
package census

import (
	"strings"
)

var BaseURL = "http://census.daybreakgames.com/"
var BaseURLOld = "http://census.soe.com/"

func init() {
	//BaseURL = BaseURLOld
}

// CensusData is a struct that contains various metadata that a Census request can have.
type CensusData struct {
	Error string `json:"error"`
}

// NewCensus returns a new census object given your service ID
func NewCensus(ServiceID string, Namespace string) *Census {
	c := new(Census)
	c.serviceID = ServiceID
	c.namespace = Namespace
	return c
}

// Census is the main object you use to query data
type Census struct {
	serviceID string
	namespace string
}

func (c *Census) CleanNamespace() string {
	if strings.Contains(c.namespace, ":") {
		return strings.Split(c.namespace, ":")[0]
	}
	return c.namespace
}

func (c *Census) IsEU() bool {
	if strings.Contains(c.namespace, "eu") {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Package kb provides keyboard mappings for Chrome DOM Keys for use with input
// events.
package kb

//go:generate go run gen.go -out keys.go -pkg kb

import (
	"unicode"

	"github.com/chromedp/cdproto/input"
)

// Key contains information for generating a key press based off the unicode
// value.
//
// Example data for the following runes:
// 									'\r'  '\n'  | ','  '<'    | 'a'   'A'  | '\u0a07'
// 									_____________________________________________________
type Key struct {
	// Code is the key code:
	// 								"Enter"     | "Comma"     | "KeyA"     | "MediaStop"
	Code string

	// Key is the key value:
	// 								"Enter"     | ","   "<"   | "a"   "A"  | "MediaStop"
	Key string

	// Text is the text for printable keys:
	// 								"\r"  "\r"  | ","   "<"   | "a"   "A"  | ""
	Text string

	// Unmodified is the unmodified text for printable keys:
	// 								"\r"  "\r"  | ","   ","   | "a"   "a"  | ""
	Unmodified string

	// Native is the native scan code.
	// 								0x13  0x13  | 0xbc  0xbc  | 0x61  0x41 | 0x00ae
	Native int64

	// Windows is the windows scan code.
	// 								0x13  0x13  | 0xbc  0xbc  | 0x61  0x41 | 0xe024
	Windows int64

	// Shift indicates whether or not the Shift modifier should be sent.
	// 								false false | false true  | false true | false
	Shift bool

	// Print indicates whether or not the character is a printable character
	// (ie, should a "char" event be generated).
	// 								true  true  | true  true  | true  true | false
	Print bool
}

// EncodeUnidentified encodes a keyDown, char, and keyUp sequence for an unidentified rune.
//
// TODO: write unit tests for non-latin/ascii unicode characters.
func EncodeUnidentified(r rune) []*input.DispatchKeyEventParams {
	// create
	keyDown := input.DispatchKeyEventParams{
		Key: "Unidentified",
		/*NativeVirtualKeyCode:  int64(r), // not sure if should be specifying the key code or not ...
		WindowsVirtualKeyCode: int64(r),*/
	}
	keyUp := keyDown
	keyDown.Type, keyUp.Type = input.KeyDown, input.KeyUp

	// printable, so create char event
	if unicode.IsPrint(r) {
		keyChar := keyDown
		keyChar.Type = input.KeyChar
		keyChar.Text = string(r)
		keyChar.UnmodifiedText = string(r)

		return []*input.DispatchKeyEventParams{&keyDown, &keyChar, &keyUp}
	}

	return []*input.DispatchKeyEventParams{&keyDown, &keyUp}
}

// Encode encodes a keyDown, char, and keyUp sequence for the specified rune.
func Encode(r rune) []*input.DispatchKeyEventParams {
	// force \n -> \r
	if r == '\n' {
		r = '\r'
	}

	// if not known key, encode as unidentified
	v, ok := Keys[r]
	if !ok {
		return EncodeUnidentified(r)
	}

	// create
	keyDown := input.DispatchKeyEventParams{
		Key:                   v.Key,
		Code:                  v.Code,
		NativeVirtualKeyCode:  v.Native,
		WindowsVirtualKeyCode: v.Windows,
	}
	if v.Shift {
		keyDown.Modifiers |= input.ModifierShift
	}
	keyUp := keyDown
	keyDown.Type, keyUp.Type = input.KeyDown, input.KeyUp

	// printable, so create char event
	if v.Print {
		keyChar := keyDown
		keyChar.Type = input.KeyChar
		keyChar.Text = v.Text
		keyChar.UnmodifiedText = v.Unmodified

		// the virtual key code for char events for printable characters will
		// be different than the defined keycode when not shifted...
		//
		// specifically, it always sends the ascii value as the scan code,
		// which is available as the rune.
		keyChar.NativeVirtualKeyCode = int64(r)
		keyChar.WindowsVirtualKeyCode = int64(r)

		return []*input.DispatchKeyEventParams{&keyDown, &keyChar, &keyUp}
	}

	return []*input.DispatchKeyEventParams{&keyDown, &keyUp}
}
<commit_msg>Fixing issue with kb<commit_after>// Package kb provides keyboard mappings for Chrome DOM Keys for use with input
// events.
package kb

//go:generate go run gen.go -out keys.go -pkg kb

import (
	"runtime"
	"unicode"

	"github.com/chromedp/cdproto/input"
)

// Key contains information for generating a key press based off the unicode
// value.
//
// Example data for the following runes:
// 									'\r'  '\n'  | ','  '<'    | 'a'   'A'  | '\u0a07'
// 									_____________________________________________________
type Key struct {
	// Code is the key code:
	// 								"Enter"     | "Comma"     | "KeyA"     | "MediaStop"
	Code string

	// Key is the key value:
	// 								"Enter"     | ","   "<"   | "a"   "A"  | "MediaStop"
	Key string

	// Text is the text for printable keys:
	// 								"\r"  "\r"  | ","   "<"   | "a"   "A"  | ""
	Text string

	// Unmodified is the unmodified text for printable keys:
	// 								"\r"  "\r"  | ","   ","   | "a"   "a"  | ""
	Unmodified string

	// Native is the native scan code.
	// 								0x13  0x13  | 0xbc  0xbc  | 0x61  0x41 | 0x00ae
	Native int64

	// Windows is the windows scan code.
	// 								0x13  0x13  | 0xbc  0xbc  | 0x61  0x41 | 0xe024
	Windows int64

	// Shift indicates whether or not the Shift modifier should be sent.
	// 								false false | false true  | false true | false
	Shift bool

	// Print indicates whether or not the character is a printable character
	// (ie, should a "char" event be generated).
	// 								true  true  | true  true  | true  true | false
	Print bool
}

// EncodeUnidentified encodes a keyDown, char, and keyUp sequence for an unidentified rune.
//
// TODO: write unit tests for non-latin/ascii unicode characters.
func EncodeUnidentified(r rune) []*input.DispatchKeyEventParams {
	// create
	keyDown := input.DispatchKeyEventParams{
		Key: "Unidentified",
		/*NativeVirtualKeyCode:  int64(r), // not sure if should be specifying the key code or not ...
		WindowsVirtualKeyCode: int64(r),*/
	}
	keyUp := keyDown
	keyDown.Type, keyUp.Type = input.KeyDown, input.KeyUp

	// printable, so create char event
	if unicode.IsPrint(r) {
		keyChar := keyDown
		keyChar.Type = input.KeyChar
		keyChar.Text = string(r)
		keyChar.UnmodifiedText = string(r)

		return []*input.DispatchKeyEventParams{&keyDown, &keyChar, &keyUp}
	}

	return []*input.DispatchKeyEventParams{&keyDown, &keyUp}
}

// Encode encodes a keyDown, char, and keyUp sequence for the specified rune.
func Encode(r rune) []*input.DispatchKeyEventParams {
	// force \n -> \r
	if r == '\n' {
		r = '\r'
	}

	// if not known key, encode as unidentified
	v, ok := Keys[r]
	if !ok {
		return EncodeUnidentified(r)
	}

	// create
	keyDown := input.DispatchKeyEventParams{
		Key:                   v.Key,
		Code:                  v.Code,
		NativeVirtualKeyCode:  v.Native,
		WindowsVirtualKeyCode: v.Windows,
	}
	if runtime.GOOS == "darwin" {
		keyDown.NativeVirtualKeyCode = 0
	}
	if v.Shift {
		keyDown.Modifiers |= input.ModifierShift
	}
	keyUp := keyDown
	keyDown.Type, keyUp.Type = input.KeyDown, input.KeyUp

	// printable, so create char event
	if v.Print {
		keyChar := keyDown
		keyChar.Type = input.KeyChar
		keyChar.Text = v.Text
		keyChar.UnmodifiedText = v.Unmodified

		// the virtual key code for char events for printable characters will
		// be different than the defined keycode when not shifted...
		//
		// specifically, it always sends the ascii value as the scan code,
		// which is available as the rune.
		keyChar.NativeVirtualKeyCode = int64(r)
		keyChar.WindowsVirtualKeyCode = int64(r)

		return []*input.DispatchKeyEventParams{&keyDown, &keyChar, &keyUp}
	}

	return []*input.DispatchKeyEventParams{&keyDown, &keyUp}
}
<|endoftext|>