<commit_before>package rfid

import (
	"context"
	"fmt"
	"time"

	"github.com/ebfe/scard"
	"github.com/sirupsen/logrus"
)

var READER_POLLING_INTERVAL = 1 * time.Second
var CARD_POLLING_TIMEOUT = 1 * time.Second

// Special MSFT name to bolt plug&play onto PC/SC
// Supported by winscard and libpcsc
const MAGIC_PNP_NAME = "\\\\?PnP?\\Notification"

// APDU to retrieve a card's UID
var UID_APDU = []byte{0xFF, 0xCA, 0x00, 0x00, 0x00}

func pollSmartCard(ctx context.Context, log *logrus.Entry, callback func(string)) {
	// Establish a PC/SC context
	scard_ctx, err := scard.EstablishContext()
	if err != nil {
		log.WithError(err).Error("Error EstablishContext:")
		return
	}
	defer scard_ctx.Release()

	// Detect PnP support
	pnpReaderStates := []scard.ReaderState{
		makeReaderState(MAGIC_PNP_NAME),
	}
	scard_ctx.GetStatusChange(pnpReaderStates, 0)
	hasPnP := !is(pnpReaderStates[0].EventState, scard.StateUnknown)

	log.WithField("pnp", hasPnP).Info("Starting RFID scanner.")

	go waitForCardActivity(log, scard_ctx, hasPnP, callback)

	<-ctx.Done()
	// Cancel `GetStatusChange`
	scard_ctx.Cancel()

	log.Info("Stopping RFID scanner.")
}

func waitForCardActivity(log *logrus.Entry, scard_ctx *scard.Context, hasPnP bool, callback func(string)) {
	availableReaders := make([]string, 0)
	lastKnownState := map[string]scard.StateFlag{}

	for {
		// Retrieve available readers
		newReaders, err := scard_ctx.ListReaders()
		if err != nil {
			log.WithError(err).Error("Error listing readers.")
			return
		}
		announceReaderChanges(log, availableReaders, newReaders)
		availableReaders = newReaders

		// Wait for readers to appear
		if len(availableReaders) == 0 {
			if hasPnP {
				// `GetStatusChange` acts as a smarter sleep that finishes early
				code := scard_ctx.GetStatusChange(
					[]scard.ReaderState{makeReaderState(MAGIC_PNP_NAME)},
					READER_POLLING_INTERVAL,
				)
				if code == scard.ErrCancelled {
					return
				}
			} else {
				time.Sleep(READER_POLLING_INTERVAL)
			}

			// Restart loop to list readers
			continue
		}

		// Now there are available readers
		// Wait for card presence
		readerStates := make([]scard.ReaderState, len(availableReaders))
		for ix, readerName := range availableReaders {
			flag, ok := lastKnownState[readerName]
			if ok {
				readerStates[ix] = makeReaderState(readerName, flag)
			} else {
				readerStates[ix] = makeReaderState(readerName)
			}
		}
		// We need to timeout perodically to check for new readers
		code := scard_ctx.GetStatusChange(readerStates, CARD_POLLING_TIMEOUT)
		if code == scard.ErrCancelled {
			return
		} else if code != nil {
			continue
		}

		// One or more readers changed their status
		for _, readerState := range readerStates {

			if readerState.CurrentState == readerState.EventState {
				// This reader has not changed.
				continue
			}

			if is(readerState.EventState, scard.StateChanged) {
				// Event state becomes current state
				readerState.CurrentState = readerState.EventState
				// Keep track of last known state for next refresh cycle
				lastKnownState[readerState.Reader] = readerState.CurrentState
			} else {
				continue
			}

			if !is(readerState.CurrentState, scard.StatePresent) {
				// This reader has no card.
				continue
			}

			// Connect to the card
			card, err := scard_ctx.Connect(readerState.Reader, scard.ShareShared, scard.ProtocolAny)
			if err != nil {
				log.WithError(err).Error("Error connecting to card.")
				continue
			}

			// Request UID
			response, err := card.Transmit(UID_APDU)
			if err != nil {
				log.WithError(err).Debug("Failed while transmitting APDU.")
				continue
			}
			uid := ""
			for i := 0; i < len(response)-2; i++ {
				uid += fmt.Sprintf("%X", response[i])
			}
			if len(uid) > 0 {
				log.Info("Detected RFID token.")
				callback(uid)
			}

			card.Disconnect(scard.UnpowerCard)
		}
	}
}

// Helpers

func is(mask scard.StateFlag, flag scard.StateFlag) bool {
	return mask&flag != 0
}

func announceReaderChanges(log *logrus.Entry, previous []string, current []string) {
	for _, name := range previous {
		if !contains(current, name) {
			log.Info(fmt.Sprintf("Reader became unavailable: '%s'", name))
		}
	}
	for _, name := range current {
		if !contains(previous, name) {
			log.Info(fmt.Sprintf("Reader became available: '%s'", name))
		}
	}
}

func contains(arr []string, name string) bool {
	for _, member := range arr {
		if member == name {
			return true
		}
	}
	return false
}

func makeReaderState(name string, state ...scard.StateFlag) scard.ReaderState {
	flag := scard.StateUnaware
	if len(state) == 1 {
		flag = state[0]
	}
	return scard.ReaderState{Reader: name, CurrentState: flag}
}
<commit_msg>Add scard context creation retry with exp backoff<commit_after>package rfid

import (
	"context"
	"fmt"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/ebfe/scard"
	"github.com/sirupsen/logrus"
)

var READER_POLLING_INTERVAL = 1 * time.Second
var CARD_POLLING_TIMEOUT = 1 * time.Second

// Special MSFT name to bolt plug&play onto PC/SC
// Supported by winscard and libpcsc
const MAGIC_PNP_NAME = "\\\\?PnP?\\Notification"

// APDU to retrieve a card's UID
var UID_APDU = []byte{0xFF, 0xCA, 0x00, 0x00, 0x00}

func pollSmartCard(ctx context.Context, log *logrus.Entry, callback func(string)) {

	scardContextBackoff := backoff.NewExponentialBackOff()
	scardContextBackoff.MaxElapsedTime = 0
	scardContextBackoff.MaxInterval = 2 * time.Minute

	for {
		// Establish a PC/SC context
		scard_ctx, err := scard.EstablishContext()
		if err != nil {
			log.WithError(err).Error("Could not create smart card context.")

			select {
			case <-time.After(scardContextBackoff.NextBackOff()):
				continue
			case <-ctx.Done():
				return
			}
		}
		defer scard_ctx.Release()

		// Now we have a context
		// Detect PnP support
		pnpReaderStates := []scard.ReaderState{
			makeReaderState(MAGIC_PNP_NAME),
		}
		scard_ctx.GetStatusChange(pnpReaderStates, 0)
		hasPnP := !is(pnpReaderStates[0].EventState, scard.StateUnknown)

		log.WithField("pnp", hasPnP).Info("Starting RFID scanner.")

		go waitForCardActivity(log, scard_ctx, hasPnP, callback)

		<-ctx.Done()
		// Cancel `GetStatusChange`
		scard_ctx.Cancel()

		log.Info("Stopping RFID scanner.")
		return
	}
}

func waitForCardActivity(log *logrus.Entry, scard_ctx *scard.Context, hasPnP bool, callback func(string)) {
	availableReaders := make([]string, 0)
	lastKnownState := map[string]scard.StateFlag{}

	for {
		// Retrieve available readers
		newReaders, err := scard_ctx.ListReaders()
		if err != nil {
			// TODO With pcsclite this fails if there are no smart card readers. Too noisy.
			log.WithError(err).Debug("Error listing readers.")
		}
		announceReaderChanges(log, availableReaders, newReaders)
		availableReaders = newReaders

		// Wait for readers to appear
		if len(availableReaders) == 0 {
			if hasPnP {
				// `GetStatusChange` acts as a smarter sleep that finishes early
				code := scard_ctx.GetStatusChange(
					[]scard.ReaderState{makeReaderState(MAGIC_PNP_NAME)},
					READER_POLLING_INTERVAL,
				)
				if code == scard.ErrCancelled {
					return
				}
			} else {
				time.Sleep(READER_POLLING_INTERVAL)
			}

			// Restart loop to list readers
			continue
		}

		// Now there are available readers
		// Wait for card presence
		readerStates := make([]scard.ReaderState, len(availableReaders))
		for ix, readerName := range availableReaders {
			flag, ok := lastKnownState[readerName]
			if ok {
				readerStates[ix] = makeReaderState(readerName, flag)
			} else {
				readerStates[ix] = makeReaderState(readerName)
			}
		}
		// We need to timeout perodically to check for new readers
		code := scard_ctx.GetStatusChange(readerStates, CARD_POLLING_TIMEOUT)
		if code == scard.ErrCancelled {
			return
		} else if code != nil {
			continue
		}

		// One or more readers changed their status
		for _, readerState := range readerStates {

			if readerState.CurrentState == readerState.EventState {
				// This reader has not changed.
				continue
			}

			if is(readerState.EventState, scard.StateChanged) {
				// Event state becomes current state
				readerState.CurrentState = readerState.EventState
				// Keep track of last known state for next refresh cycle
				lastKnownState[readerState.Reader] = readerState.CurrentState
			} else {
				continue
			}

			if !is(readerState.CurrentState, scard.StatePresent) {
				// This reader has no card.
				continue
			}

			// Connect to the card
			card, err := scard_ctx.Connect(readerState.Reader, scard.ShareShared, scard.ProtocolAny)
			if err != nil {
				log.WithError(err).Error("Error connecting to card.")
				continue
			}

			// Request UID
			response, err := card.Transmit(UID_APDU)
			if err != nil {
				log.WithError(err).Debug("Failed while transmitting APDU.")
				continue
			}
			uid := ""
			for i := 0; i < len(response)-2; i++ {
				uid += fmt.Sprintf("%X", response[i])
			}
			if len(uid) > 0 {
				log.Info("Detected RFID token.")
				callback(uid)
			}

			card.Disconnect(scard.UnpowerCard)
		}
	}
}

// Helpers

func is(mask scard.StateFlag, flag scard.StateFlag) bool {
	return mask&flag != 0
}

func contains(arr []string, name string) bool {
	for _, member := range arr {
		if member == name {
			return true
		}
	}
	return false
}

func makeReaderState(name string, state ...scard.StateFlag) scard.ReaderState {
	flag := scard.StateUnaware
	if len(state) == 1 {
		flag = state[0]
	}
	return scard.ReaderState{Reader: name, CurrentState: flag}
}

func announceReaderChanges(log *logrus.Entry, previous []string, current []string) {
	for _, name := range previous {
		if !contains(current, name) {
			log.Info(fmt.Sprintf("Reader became unavailable: '%s'", name))
		}
	}
	for _, name := range current {
		if !contains(previous, name) {
			log.Info(fmt.Sprintf("Reader became available: '%s'", name))
		}
	}
}
<|endoftext|>


<commit_before>package game_engine

import (
    "fmt"
    "encoding/json"
    "errors"
    "requests"
)

type Game struct {
    terrain [][]terrain
    unitMap map[location]*unit
    players []*player
    numPlayers int
    turnOwner int
}

func NewGame(playerIds []int, worldId int) (*Game, error) {
    numPlayers := len(playerIds)
    if numPlayers > 4 || numPlayers < 1 {
        return nil, errors.New("must have between 1 and 4 players")
    }
    players := make([]*player, numPlayers)
    for i, playerId := range(playerIds) {
        players[i] = newPlayer(playerId, nation(i), team(i))
    }
    ret_game := &Game{
        terrain: [][]terrain{
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains}},
        unitMap: make(map[location]*unit),
        players: players,
        numPlayers: numPlayers,
        turnOwner: 0}
    if worldId == 0 {
        ret_game.AddUnit(newLocation(0, 0), tank(red))
    }
    return ret_game, nil
}

func (game *Game) getPlayer(playerId int) (*player, error) {
    for _, player := range(game.players) {
        if player.playerId == playerId {
            return player, nil
        }
    }
    return nil, errors.New("Player not playing")
}

func (game *Game) verifyTurnOwner(playerId int) error {
    if playerId != game.players[game.turnOwner].playerId {
        return errors.New("Not the turn owner")
    }
    return nil
}

func (game *Game) AddUnit(location location, unit *unit) error {
    fmt.Println("adding unit")
    _, ok := game.unitMap[location]; if !ok {
        game.unitMap[location] = unit
        fmt.Println("added unit")
        return nil
    } else {
        fmt.Println("failed to add unit")
        return errors.New("location already occupied")
    }
}

func (game *Game) Serialize(playerId int) ([]byte, error) {
    players := make([]*requests.PlayerStruct, len(game.players))
    for i, player := range(game.players) {
        players[i] = player.serialize()
    }
    terrainInts := make([][]int, len(game.terrain))
    for i, t := range(game.terrain) {
        thoriz := make([]int, len(t))
        for j, t_ := range(t) {
            thoriz[j] = int(t_)
        }
        terrainInts[i] = thoriz
    }
    units := make([]*requests.UnitStruct, len(game.unitMap))
    i := 0
    for location, unit := range(game.unitMap) {
        units[i] = unit.serialize(location)
        i += 1
    }
    return json.Marshal(requests.WorldStruct{
        Terrain: terrainInts,
        Units: units,
        Players: players,
        TurnOwner: game.players[game.turnOwner].playerId})
}

func (game *Game) MoveUnit(playerId int, rawLocations []requests.LocationStruct) error {
    player, err := game.getPlayer(playerId)
    if err != nil {
        return err
    }
    locations := make([]location, len(rawLocations))
    for i, location := range(rawLocations) {
        locations[i] = newLocation(location.X, location.Y)
    }
    validError := game.verifyValidMove(player, locations)
    if validError != nil {
        return validError
    }
    game.verifiedMoveUnit(locations)
    return nil
}

func (game *Game) verifyValidMove(player *player, locations []location) error {
    ownerError := game.verifyTurnOwner(player.playerId)
    if ownerError != nil {
        return ownerError
    }
    if len(locations) < 1 {
        message := "must supply more than zero  locations"
        fmt.Println(message)
        return errors.New(message)
    }

    tiles := make([]terrain, len(locations))
    for i, location := range(locations) {
        tiles[i] = game.terrain[location.x][location.y]
    }
    unit, ok := game.unitMap[locations[0]]; if ok {
        moveErr := validMove(
            unit.movement.distance,
            unit.movement, tiles, locations)
        if moveErr == nil {
            return nil
        } else {
            fmt.Println(moveErr)
            return moveErr
        }
    } else {
        message := "Invalid starting location"
        fmt.Println(message)
        return errors.New(message)
    }
}

func (game *Game) verifiedMoveUnit(locations []location) error {
    end := len(locations)
    unit := game.unitMap[newLocation(locations[0].x, locations[0].y)]
    game.unitMap[newLocation(locations[end-1].x, locations[end-1].y)] = unit
    delete(game.unitMap, newLocation(locations[0].x, locations[0].y))
    return nil
}

func (game *Game) EndTurn(playerId int) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    nextOwner := game.turnOwner + 1
    if nextOwner >= game.numPlayers {
        game.turnOwner = 0
    } else {
        game.turnOwner = nextOwner
    }
    return nil
}
<commit_msg>Ensure that the unit being moved is the player owners<commit_after>package game_engine

import (
    "fmt"
    "encoding/json"
    "errors"
    "requests"
)

type Game struct {
    terrain [][]terrain
    unitMap map[location]*unit
    players []*player
    numPlayers int
    turnOwner int
}

func NewGame(playerIds []int, worldId int) (*Game, error) {
    numPlayers := len(playerIds)
    if numPlayers > 4 || numPlayers < 1 {
        return nil, errors.New("must have between 1 and 4 players")
    }
    players := make([]*player, numPlayers)
    for i, playerId := range(playerIds) {
        players[i] = newPlayer(playerId, nation(i), team(i))
    }
    ret_game := &Game{
        terrain: [][]terrain{
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains}},
        unitMap: make(map[location]*unit),
        players: players,
        numPlayers: numPlayers,
        turnOwner: 0}
    if worldId == 0 {
        ret_game.AddUnit(newLocation(0, 0), tank(red))
    }
    return ret_game, nil
}

func (game *Game) getPlayer(playerId int) (*player, error) {
    for _, player := range(game.players) {
        if player.playerId == playerId {
            return player, nil
        }
    }
    return nil, errors.New("Player not playing")
}

func (game *Game) verifyTurnOwner(playerId int) error {
    if playerId != game.players[game.turnOwner].playerId {
        return errors.New("Not the turn owner")
    }
    return nil
}

func (game *Game) AddUnit(location location, unit *unit) error {
    fmt.Println("adding unit")
    _, ok := game.unitMap[location]; if !ok {
        game.unitMap[location] = unit
        fmt.Println("added unit")
        return nil
    } else {
        fmt.Println("failed to add unit")
        return errors.New("location already occupied")
    }
}

func (game *Game) Serialize(playerId int) ([]byte, error) {
    players := make([]*requests.PlayerStruct, len(game.players))
    for i, player := range(game.players) {
        players[i] = player.serialize()
    }
    terrainInts := make([][]int, len(game.terrain))
    for i, t := range(game.terrain) {
        thoriz := make([]int, len(t))
        for j, t_ := range(t) {
            thoriz[j] = int(t_)
        }
        terrainInts[i] = thoriz
    }
    units := make([]*requests.UnitStruct, len(game.unitMap))
    i := 0
    for location, unit := range(game.unitMap) {
        units[i] = unit.serialize(location)
        i += 1
    }
    return json.Marshal(requests.WorldStruct{
        Terrain: terrainInts,
        Units: units,
        Players: players,
        TurnOwner: game.players[game.turnOwner].playerId})
}

func (game *Game) MoveUnit(playerId int, rawLocations []requests.LocationStruct) error {
    player, err := game.getPlayer(playerId)
    if err != nil {
        return err
    }
    locations := make([]location, len(rawLocations))
    for i, location := range(rawLocations) {
        locations[i] = newLocation(location.X, location.Y)
    }
    validError := game.verifyValidMove(player, locations)
    if validError != nil {
        return validError
    }
    game.verifiedMoveUnit(locations)
    return nil
}

func (game *Game) verifyValidMove(player *player, locations []location) error {
    ownerError := game.verifyTurnOwner(player.playerId)
    if ownerError != nil {
        return ownerError
    }
    if len(locations) < 1 {
        message := "must supply more than zero  locations"
        fmt.Println(message)
        return errors.New(message)
    }

    tiles := make([]terrain, len(locations))
    for i, location := range(locations) {
        tiles[i] = game.terrain[location.x][location.y]
    }
    unit, ok := game.unitMap[locations[0]]; if ok {
        if unit.nation == player.nation {
            return errors.New("Unit is not owned by the current player")
        }
        moveErr := validMove(
            unit.movement.distance,
            unit.movement, tiles, locations)
        if moveErr == nil {
            return nil
        } else {
            fmt.Println(moveErr)
            return moveErr
        }
    } else {
        message := "Invalid starting location"
        fmt.Println(message)
        return errors.New(message)
    }
}

func (game *Game) verifiedMoveUnit(locations []location) error {
    end := len(locations)
    unit := game.unitMap[newLocation(locations[0].x, locations[0].y)]
    game.unitMap[newLocation(locations[end-1].x, locations[end-1].y)] = unit
    delete(game.unitMap, newLocation(locations[0].x, locations[0].y))
    return nil
}

func (game *Game) EndTurn(playerId int) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    nextOwner := game.turnOwner + 1
    if nextOwner >= game.numPlayers {
        game.turnOwner = 0
    } else {
        game.turnOwner = nextOwner
    }
    return nil
}
<|endoftext|>


<commit_before>package datadog

import (
	"encoding/json"
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/zorkian/go-datadog-api"
	"strconv"
	"strings"
)

func thresholdSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeMap,
		Required: true,
		ForceNew: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"ok": &schema.Schema{
					Type:     schema.TypeFloat,
					Optional: true,
				},
				"warning": &schema.Schema{
					Type:     schema.TypeFloat,
					Optional: true,
				},
				"critical": &schema.Schema{
					Type:     schema.TypeFloat,
					Required: true,
				},
			},
		},
	}
}

func getThresholds(d *schema.ResourceData) (string, datadog.ThresholdCount) {
	t := datadog.ThresholdCount{}

	var threshold string

	if r, ok := d.GetOk("thresholds.ok"); ok {
		t.Ok = json.Number(r.(string))
	}

	if r, ok := d.GetOk("thresholds.warning"); ok {
		t.Warning = json.Number(r.(string))
	}

	if r, ok := d.GetOk("thresholds.critical"); ok {
		threshold = r.(string)
		t.Critical = json.Number(r.(string))
	}

	return threshold, t
}

func resourceDatadogGenericDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return err
	}

	if err = client.DeleteMonitor(i); err != nil {
		return err
	}

	return nil
}

func resourceDatadogGenericExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
	// Exists - This is called to verify a resource still exists. It is called prior to Read,
	// and lowers the burden of Read to be able to assume the resource exists.
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return false, err
	}

	if _, err = client.GetMonitor(i); err != nil {
		if strings.Contains(err.Error(), "404 Not Found") {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func resourceDatadogGenericRead(d *schema.ResourceData, meta interface{}) error {
	// TODO: Add support for read function.
	/* Read - This is called to resync the local state with the remote state.
	Terraform guarantees that an existing ID will be set. This ID should be
	used to look up the resource. Any remote data should be updated into the
	local data. No changes to the remote resource are to be made.
	*/

	return nil
}

func monitorCreator(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
	client := meta.(*datadog.Client)

	m, err := client.CreateMonitor(m)
	if err != nil {
		return fmt.Errorf("error updating montor: %s", err.Error())
	}

	d.SetId(strconv.Itoa(m.Id))

	return nil
}

func monitorUpdater(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return err
	}

	m.Id = i

	if err = client.UpdateMonitor(m); err != nil {
		return fmt.Errorf("error updating montor: %s", err.Error())
	}

	return nil
}
<commit_msg>No need to force recreation of threshold changes.<commit_after>package datadog

import (
	"encoding/json"
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/zorkian/go-datadog-api"
	"strconv"
	"strings"
)

func thresholdSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeMap,
		Required: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"ok": &schema.Schema{
					Type:     schema.TypeFloat,
					Optional: true,
				},
				"warning": &schema.Schema{
					Type:     schema.TypeFloat,
					Optional: true,
				},
				"critical": &schema.Schema{
					Type:     schema.TypeFloat,
					Required: true,
				},
			},
		},
	}
}

func getThresholds(d *schema.ResourceData) (string, datadog.ThresholdCount) {
	t := datadog.ThresholdCount{}

	var threshold string

	if r, ok := d.GetOk("thresholds.ok"); ok {
		t.Ok = json.Number(r.(string))
	}

	if r, ok := d.GetOk("thresholds.warning"); ok {
		t.Warning = json.Number(r.(string))
	}

	if r, ok := d.GetOk("thresholds.critical"); ok {
		threshold = r.(string)
		t.Critical = json.Number(r.(string))
	}

	return threshold, t
}

func resourceDatadogGenericDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return err
	}

	if err = client.DeleteMonitor(i); err != nil {
		return err
	}

	return nil
}

func resourceDatadogGenericExists(d *schema.ResourceData, meta interface{}) (b bool, e error) {
	// Exists - This is called to verify a resource still exists. It is called prior to Read,
	// and lowers the burden of Read to be able to assume the resource exists.
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return false, err
	}

	if _, err = client.GetMonitor(i); err != nil {
		if strings.Contains(err.Error(), "404 Not Found") {
			return false, nil
		}
		return false, err
	}

	return true, nil
}

func resourceDatadogGenericRead(d *schema.ResourceData, meta interface{}) error {
	// TODO: Add support for read function.
	/* Read - This is called to resync the local state with the remote state.
	Terraform guarantees that an existing ID will be set. This ID should be
	used to look up the resource. Any remote data should be updated into the
	local data. No changes to the remote resource are to be made.
	*/

	return nil
}

func monitorCreator(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
	client := meta.(*datadog.Client)

	m, err := client.CreateMonitor(m)
	if err != nil {
		return fmt.Errorf("error updating montor: %s", err.Error())
	}

	d.SetId(strconv.Itoa(m.Id))

	return nil
}

func monitorUpdater(d *schema.ResourceData, meta interface{}, m *datadog.Monitor) error {
	client := meta.(*datadog.Client)

	i, err := strconv.Atoi(d.Id())
	if err != nil {
		return err
	}

	m.Id = i

	if err = client.UpdateMonitor(m); err != nil {
		return fmt.Errorf("error updating montor: %s", err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>package raidman

import (
	"./proto"
	"bytes"
	pb "code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"reflect"
	"sync"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	m          sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Host        string
	State       string
	Service     string
	Description string
	Float       float32
	Double      float64
	Int         int64
}

// Dial establishes a connection to a Riemann server
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if _, err = conn.Read(response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) *proto.Event {
	var e proto.Event

	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Float":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName("MetricF").Set(tmp)
			case "Int":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName("MetricSint64").Set(tmp)
			case "Double":
				tmp := reflect.ValueOf(pb.Float64(value.Float()))
				t.FieldByName("MetricD").Set(tmp)
			}
		}
	}

	return &e
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Float:       event.GetMetricF(),
			Int:         event.GetMetricSint64(),
			Double:      event.GetMetricD(),
		}
		events = append(events, e)
	}

	return events
}

// Send sends an event to to Riemann
func (c *Client) Send(event *Event) error {
	e := eventToPbEvent(event)
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.m.Lock()
	defer c.m.Unlock()
	_, err := c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.m.Lock()
	defer c.m.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.m.Lock()
	c.connection.Close()
	c.m.Unlock()
}
<commit_msg>Replacing local import<commit_after>package raidman

import (
	"bytes"
	pb "code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/amir/raidman/proto"
	"net"
	"reflect"
	"sync"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	m          sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Host        string
	State       string
	Service     string
	Description string
	Float       float32
	Double      float64
	Int         int64
}

// Dial establishes a connection to a Riemann server
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if _, err = conn.Read(response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) *proto.Event {
	var e proto.Event

	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Float":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName("MetricF").Set(tmp)
			case "Int":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName("MetricSint64").Set(tmp)
			case "Double":
				tmp := reflect.ValueOf(pb.Float64(value.Float()))
				t.FieldByName("MetricD").Set(tmp)
			}
		}
	}

	return &e
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Float:       event.GetMetricF(),
			Int:         event.GetMetricSint64(),
			Double:      event.GetMetricD(),
		}
		events = append(events, e)
	}

	return events
}

// Send sends an event to to Riemann
func (c *Client) Send(event *Event) error {
	e := eventToPbEvent(event)
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.m.Lock()
	defer c.m.Unlock()
	_, err := c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.m.Lock()
	defer c.m.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.m.Lock()
	c.connection.Close()
	c.m.Unlock()
}
<|endoftext|>


<commit_before>package load

import (
	"fmt"
	"log"

	flux "github.com/influxdb/influxdb/client"
	types "github.com/mchmarny/thingz-commons"
)

// convert translates the JSON data into a metric collection
// and then outputs each series individually
func convert(in <-chan []byte, out chan<- *flux.Series) {
	for {
		select {
		case data := <-in:
			m, err := types.ParseMetricCollection(data)
			if err != nil {
				log.Printf("Error parsing Metric Collection: %v", err)
			} else {
				for _, v := range m.Metrics {
					out <- &flux.Series{
						Name: fmt.Sprintf("src.%s.dim.%s.met.%s",
							m.Source,
							m.Dimension,
							v.Metric,
						),
						Columns: []string{"time", "value"},
						Points:  [][]interface{}{{v.Timestamp.Unix(), v.Value}},
					} // series
				} // for
			} // err
		} // select
	} // for
}
<commit_msg>Updated commons<commit_after>package load

import (
	"log"

	flux "github.com/influxdb/influxdb/client"
	"github.com/mchmarny/thingz-commons"
	"github.com/mchmarny/thingz-commons/types"
)

// convert translates the JSON data into a metric collection
// and then outputs each series individually
func convert(in <-chan []byte, out chan<- *flux.Series) {
	for {
		select {
		case data := <-in:
			m, err := types.ParseMetricCollection(data)
			if err != nil {
				log.Printf("Error parsing Metric Collection: %v", err)
			} else {
				for _, v := range m.Metrics {
					out <- &flux.Series{
						Name:    commons.FormatMetricName(m.Source, m.Dimension, v.Metric),
						Columns: []string{"time", "value"},
						Points:  [][]interface{}{{v.Timestamp.Unix(), v.Value}},
					} // series
				} // for
			} // err
		} // select
	} // for
}
<|endoftext|>


<commit_before>package postgresrunner

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strconv"
	"time"

	"github.com/BurntSushi/migration"
	"github.com/concourse/atc/db/migrations"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Port int
}

func (runner Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	tmpdir, err := ioutil.TempDir("", "postgres")
	Ω(err).ShouldNot(HaveOccurred())

	currentUser, err := user.Current()
	Ω(err).ShouldNot(HaveOccurred())

	var initCmd, startCmd *exec.Cmd

	initdbPath, err := exec.LookPath("initdb")
	Ω(err).ShouldNot(HaveOccurred())

	postgresPath, err := exec.LookPath("postgres")
	Ω(err).ShouldNot(HaveOccurred())

	initdb := initdbPath + " -U postgres -D " + tmpdir
	postgres := fmt.Sprintf("%s -d 2 -D %s -h 127.0.0.1 -p %d", postgresPath, tmpdir, runner.Port)

	if currentUser.Uid == "0" {
		pgUser, err := user.Lookup("postgres")
		Ω(err).ShouldNot(HaveOccurred())

		uid, err := strconv.Atoi(pgUser.Uid)
		Ω(err).ShouldNot(HaveOccurred())

		gid, err := strconv.Atoi(pgUser.Gid)
		Ω(err).ShouldNot(HaveOccurred())

		err = os.Chown(tmpdir, uid, gid)
		Ω(err).ShouldNot(HaveOccurred())

		initCmd = exec.Command("su", "postgres", "-c", initdb)
		startCmd = exec.Command("su", "postgres", "-c", postgres)
	} else {
		initCmd = exec.Command("bash", "-c", initdb)
		startCmd = exec.Command("bash", "-c", postgres)
	}

	session, err := gexec.Start(
		initCmd,
		gexec.NewPrefixedWriter("[o][initdb] ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("[e][initdb] ", ginkgo.GinkgoWriter),
	)
	Ω(err).ShouldNot(HaveOccurred())

	Eventually(session, 60*time.Second).Should(gexec.Exit(0))

	ginkgoRunner := &ginkgomon.Runner{
		Name:          "postgres",
		Command:       startCmd,
		AnsiColorCode: "90m",
		StartCheck:    "database system is ready to accept connections",
		Cleanup: func() {
			os.RemoveAll(tmpdir)
		},
	}

	return ginkgoRunner.Run(signals, ready)
}

func (runner *Runner) Open() *sql.DB {
	dbConn, err := migration.Open(
		"postgres",
		runner.DataSourceName(),
		migrations.Migrations,
	)
	Ω(err).ShouldNot(HaveOccurred())

	return dbConn
}

func (runner *Runner) DataSourceName() string {
	return fmt.Sprintf("user=postgres dbname=testdb sslmode=disable port=%d", runner.Port)
}

func (runner *Runner) CreateTestDB() {
	createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	createS, err := gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	Eventually(createS, 10*time.Second).Should(gexec.Exit(0))
}

func (runner *Runner) DropTestDB() {
	dropdb := exec.Command("dropdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	dropS, err := gexec.Start(dropdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	Eventually(dropS, 10*time.Second).Should(gexec.Exit(0))
}
<commit_msg>fail better in when postgresql is not installed<commit_after>package postgresrunner

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strconv"
	"time"

	"github.com/BurntSushi/migration"
	"github.com/concourse/atc/db/migrations"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit/ginkgomon"
)

type Runner struct {
	Port int
}

func (runner Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	defer ginkgo.GinkgoRecover()

	tmpdir, err := ioutil.TempDir("", "postgres")
	Ω(err).ShouldNot(HaveOccurred())

	currentUser, err := user.Current()
	Ω(err).ShouldNot(HaveOccurred())

	var initCmd, startCmd *exec.Cmd

	initdbPath, err := exec.LookPath("initdb")
	Ω(err).ShouldNot(HaveOccurred())

	postgresPath, err := exec.LookPath("postgres")
	Ω(err).ShouldNot(HaveOccurred())

	initdb := initdbPath + " -U postgres -D " + tmpdir
	postgres := fmt.Sprintf("%s -d 2 -D %s -h 127.0.0.1 -p %d", postgresPath, tmpdir, runner.Port)

	if currentUser.Uid == "0" {
		pgUser, err := user.Lookup("postgres")
		Ω(err).ShouldNot(HaveOccurred())

		uid, err := strconv.Atoi(pgUser.Uid)
		Ω(err).ShouldNot(HaveOccurred())

		gid, err := strconv.Atoi(pgUser.Gid)
		Ω(err).ShouldNot(HaveOccurred())

		err = os.Chown(tmpdir, uid, gid)
		Ω(err).ShouldNot(HaveOccurred())

		initCmd = exec.Command("su", "postgres", "-c", initdb)
		startCmd = exec.Command("su", "postgres", "-c", postgres)
	} else {
		initCmd = exec.Command("bash", "-c", initdb)
		startCmd = exec.Command("bash", "-c", postgres)
	}

	session, err := gexec.Start(
		initCmd,
		gexec.NewPrefixedWriter("[o][initdb] ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("[e][initdb] ", ginkgo.GinkgoWriter),
	)
	Ω(err).ShouldNot(HaveOccurred())

	Eventually(session, 60*time.Second).Should(gexec.Exit(0))

	ginkgoRunner := &ginkgomon.Runner{
		Name:          "postgres",
		Command:       startCmd,
		AnsiColorCode: "90m",
		StartCheck:    "database system is ready to accept connections",
		Cleanup: func() {
			os.RemoveAll(tmpdir)
		},
	}

	return ginkgoRunner.Run(signals, ready)
}

func (runner *Runner) Open() *sql.DB {
	dbConn, err := migration.Open(
		"postgres",
		runner.DataSourceName(),
		migrations.Migrations,
	)
	Ω(err).ShouldNot(HaveOccurred())

	return dbConn
}

func (runner *Runner) DataSourceName() string {
	return fmt.Sprintf("user=postgres dbname=testdb sslmode=disable port=%d", runner.Port)
}

func (runner *Runner) CreateTestDB() {
	createdb := exec.Command("createdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	createS, err := gexec.Start(createdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	Eventually(createS, 10*time.Second).Should(gexec.Exit(0))
}

func (runner *Runner) DropTestDB() {
	dropdb := exec.Command("dropdb", "-U", "postgres", "-p", strconv.Itoa(runner.Port), "testdb")
	dropS, err := gexec.Start(dropdb, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
	Ω(err).ShouldNot(HaveOccurred())
	Eventually(dropS, 10*time.Second).Should(gexec.Exit(0))
}
<|endoftext|>


<commit_before>package device

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/validate"
)

// usbDevPath is the path where USB devices can be enumerated.
const usbDevPath = "/sys/bus/usb/devices"

// usbIsOurDevice indicates whether the USB device event qualifies as part of our device.
// This function is not defined against the usb struct type so that it can be used in event
// callbacks without needing to keep a reference to the usb device struct.
func usbIsOurDevice(config deviceConfig.Device, usb *USBEvent) bool {
	// Check if event matches criteria for this device, if not return.
	if (config["vendorid"] != "" && config["vendorid"] != usb.Vendor) || (config["productid"] != "" && config["productid"] != usb.Product) {
		return false
	}

	return true
}

type usb struct {
	deviceCommon
}

// isRequired indicates whether the device config requires this device to start OK.
func (d *usb) isRequired() bool {
	// Defaults to not required.
	if shared.IsTrue(d.config["required"]) {
		return true
	}

	return false
}

// validateConfig checks the supplied config for correctness.
func (d *usb) validateConfig(instConf instance.ConfigReader) error {
	if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) {
		return ErrUnsupportedDevType
	}

	rules := map[string]func(string) error{
		"vendorid":  validate.Optional(validate.IsDeviceID),
		"productid": validate.Optional(validate.IsDeviceID),
		"uid":       unixValidUserID,
		"gid":       unixValidUserID,
		"mode":      unixValidOctalFileMode,
		"required":  validate.Optional(validate.IsBool),
	}

	err := d.config.Validate(rules)
	if err != nil {
		return err
	}

	return nil
}

// Register is run after the device is started or when LXD starts.
func (d *usb) Register() error {
	// Extract variables needed to run the event hook so that the reference to this device
	// struct is not needed to be kept in memory.
	devicesPath := d.inst.DevicesPath()
	devConfig := d.config
	deviceName := d.name
	state := d.state

	// Handler for when a USB event occurs.
	f := func(e USBEvent) (*deviceConfig.RunConfig, error) {
		if !usbIsOurDevice(devConfig, &e) {
			return nil, nil
		}

		runConf := deviceConfig.RunConfig{}

		if e.Action == "add" {
			err := unixDeviceSetupCharNum(state, devicesPath, "unix", deviceName, devConfig, e.Major, e.Minor, e.Path, false, &runConf)
			if err != nil {
				return nil, err
			}
		} else if e.Action == "remove" {
			relativeTargetPath := strings.TrimPrefix(e.Path, "/")
			err := unixDeviceRemove(devicesPath, "unix", deviceName, relativeTargetPath, &runConf)
			if err != nil {
				return nil, err
			}

			// Add a post hook function to remove the specific USB device file after unmount.
			runConf.PostHooks = []func() error{func() error {
				err := unixDeviceDeleteFiles(state, devicesPath, "unix", deviceName, relativeTargetPath)
				if err != nil {
					return fmt.Errorf("Failed to delete files for device '%s': %v", deviceName, err)
				}

				return nil
			}}
		}

		runConf.Uevents = append(runConf.Uevents, e.UeventParts)

		return &runConf, nil
	}

	usbRegisterHandler(d.inst, d.name, f)

	return nil
}

// Start is run when the device is added to the instance.
func (d *usb) Start() (*deviceConfig.RunConfig, error) {
	usbs, err := d.loadUsb()
	if err != nil {
		return nil, err
	}

	runConf := deviceConfig.RunConfig{}
	runConf.PostHooks = []func() error{d.Register}

	for _, usb := range usbs {
		if !usbIsOurDevice(d.config, &usb) {
			continue
		}

		err := unixDeviceSetupCharNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, usb.Major, usb.Minor, usb.Path, false, &runConf)
		if err != nil {
			return nil, err
		}
	}

	if d.isRequired() && len(runConf.Mounts) <= 0 {
		return nil, fmt.Errorf("Required USB device not found")
	}

	return &runConf, nil
}

// Stop is run when the device is removed from the instance.
func (d *usb) Stop() (*deviceConfig.RunConfig, error) {
	// Unregister any USB event handlers for this device.
	usbUnregisterHandler(d.inst, d.name)

	runConf := deviceConfig.RunConfig{
		PostHooks: []func() error{d.postStop},
	}

	err := unixDeviceRemove(d.inst.DevicesPath(), "unix", d.name, "", &runConf)
	if err != nil {
		return nil, err
	}

	return &runConf, nil
}

// postStop is run after the device is removed from the instance.
func (d *usb) postStop() error {
	// Remove host files for this device.
	err := unixDeviceDeleteFiles(d.state, d.inst.DevicesPath(), "unix", d.name, "")
	if err != nil {
		return fmt.Errorf("Failed to delete files for device '%s': %v", d.name, err)
	}

	return nil
}

// loadUsb scans the host machine for USB devices.
func (d *usb) loadUsb() ([]USBEvent, error) {
	result := []USBEvent{}

	ents, err := ioutil.ReadDir(usbDevPath)
	if err != nil {
		/* if there are no USB devices, let's render an empty list,
		 * i.e. no usb devices */
		if os.IsNotExist(err) {
			return result, nil
		}
		return nil, err
	}

	for _, ent := range ents {
		values, err := d.loadRawValues(path.Join(usbDevPath, ent.Name()))
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}

			return []USBEvent{}, err
		}

		parts := strings.Split(values["dev"], ":")
		if len(parts) != 2 {
			return []USBEvent{}, fmt.Errorf("invalid device value %s", values["dev"])
		}

		usb, err := USBNewEvent(
			"add",
			values["idVendor"],
			values["idProduct"],
			parts[0],
			parts[1],
			values["busnum"],
			values["devnum"],
			values["devname"],
			[]string{},
			0,
		)
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return nil, err
		}

		result = append(result, usb)
	}

	return result, nil
}

func (d *usb) loadRawValues(p string) (map[string]string, error) {
	values := map[string]string{
		"idVendor":  "",
		"idProduct": "",
		"dev":       "",
		"busnum":    "",
		"devnum":    "",
	}

	for k := range values {
		v, err := ioutil.ReadFile(path.Join(p, k))
		if err != nil {
			return nil, err
		}

		values[k] = strings.TrimSpace(string(v))
	}

	return values, nil
}
<commit_msg>lxd/device: Handle USB devices for VMs<commit_after>package device

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/validate"
)

// usbDevPath is the path where USB devices can be enumerated.
const usbDevPath = "/sys/bus/usb/devices"

// usbIsOurDevice indicates whether the USB device event qualifies as part of our device.
// This function is not defined against the usb struct type so that it can be used in event
// callbacks without needing to keep a reference to the usb device struct.
func usbIsOurDevice(config deviceConfig.Device, usb *USBEvent) bool {
	// Check if event matches criteria for this device, if not return.
	if (config["vendorid"] != "" && config["vendorid"] != usb.Vendor) || (config["productid"] != "" && config["productid"] != usb.Product) {
		return false
	}

	return true
}

type usb struct {
	deviceCommon
}

// isRequired indicates whether the device config requires this device to start OK.
func (d *usb) isRequired() bool {
	// Defaults to not required.
	if shared.IsTrue(d.config["required"]) {
		return true
	}

	return false
}

// validateConfig checks the supplied config for correctness.
func (d *usb) validateConfig(instConf instance.ConfigReader) error {
	if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) {
		return ErrUnsupportedDevType
	}

	rules := map[string]func(string) error{
		"vendorid":  validate.Optional(validate.IsDeviceID),
		"productid": validate.Optional(validate.IsDeviceID),
		"uid":       unixValidUserID,
		"gid":       unixValidUserID,
		"mode":      unixValidOctalFileMode,
		"required":  validate.Optional(validate.IsBool),
	}

	err := d.config.Validate(rules)
	if err != nil {
		return err
	}

	return nil
}

// Register is run after the device is started or when LXD starts.
func (d *usb) Register() error {
	// Extract variables needed to run the event hook so that the reference to this device
	// struct is not needed to be kept in memory.
	devicesPath := d.inst.DevicesPath()
	devConfig := d.config
	deviceName := d.name
	state := d.state

	// Handler for when a USB event occurs.
	f := func(e USBEvent) (*deviceConfig.RunConfig, error) {
		if !usbIsOurDevice(devConfig, &e) {
			return nil, nil
		}

		runConf := deviceConfig.RunConfig{}

		if e.Action == "add" {
			err := unixDeviceSetupCharNum(state, devicesPath, "unix", deviceName, devConfig, e.Major, e.Minor, e.Path, false, &runConf)
			if err != nil {
				return nil, err
			}
		} else if e.Action == "remove" {
			relativeTargetPath := strings.TrimPrefix(e.Path, "/")
			err := unixDeviceRemove(devicesPath, "unix", deviceName, relativeTargetPath, &runConf)
			if err != nil {
				return nil, err
			}

			// Add a post hook function to remove the specific USB device file after unmount.
			runConf.PostHooks = []func() error{func() error {
				err := unixDeviceDeleteFiles(state, devicesPath, "unix", deviceName, relativeTargetPath)
				if err != nil {
					return fmt.Errorf("Failed to delete files for device '%s': %v", deviceName, err)
				}

				return nil
			}}
		}

		runConf.Uevents = append(runConf.Uevents, e.UeventParts)

		return &runConf, nil
	}

	usbRegisterHandler(d.inst, d.name, f)

	return nil
}

// Start is run when the device is added to the instance.
func (d *usb) Start() (*deviceConfig.RunConfig, error) {
	if d.inst.Type() == instancetype.VM {
		return d.startVM()
	}

	return d.startContainer()
}

func (d *usb) startContainer() (*deviceConfig.RunConfig, error) {
	usbs, err := d.loadUsb()
	if err != nil {
		return nil, err
	}

	runConf := deviceConfig.RunConfig{}
	runConf.PostHooks = []func() error{d.Register}

	for _, usb := range usbs {
		if !usbIsOurDevice(d.config, &usb) {
			continue
		}

		err := unixDeviceSetupCharNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, usb.Major, usb.Minor, usb.Path, false, &runConf)
		if err != nil {
			return nil, err
		}
	}

	if d.isRequired() && len(runConf.Mounts) <= 0 {
		return nil, fmt.Errorf("Required USB device not found")
	}

	return &runConf, nil
}

func (d *usb) startVM() (*deviceConfig.RunConfig, error) {
	usbs, err := d.loadUsb()
	if err != nil {
		return nil, err
	}

	runConf := deviceConfig.RunConfig{}
	runConf.PostHooks = []func() error{d.Register}

	for _, usb := range usbs {
		if !usbIsOurDevice(d.config, &usb) {
			continue
		}

		runConf.USBDevice = append(runConf.USBDevice, []deviceConfig.RunConfigItem{
			{Key: "devName", Value: d.name},
			{Key: "hostDevice", Value: fmt.Sprintf("/dev/bus/usb/%03d/%03d", usb.BusNum, usb.DevNum)},
		}...)
	}

	if d.isRequired() && len(runConf.Mounts) <= 0 {
		return nil, fmt.Errorf("Required USB device not found")
	}

	return &runConf, nil
}

// Stop is run when the device is removed from the instance.
func (d *usb) Stop() (*deviceConfig.RunConfig, error) {
	runConf := deviceConfig.RunConfig{
		PostHooks: []func() error{d.postStop},
	}

	if d.inst.Type() == instancetype.Container {
		// Unregister any USB event handlers for this device.
		usbUnregisterHandler(d.inst, d.name)

		err := unixDeviceRemove(d.inst.DevicesPath(), "unix", d.name, "", &runConf)
		if err != nil {
			return nil, err
		}
	}

	return &runConf, nil
}

// postStop is run after the device is removed from the instance.
func (d *usb) postStop() error {
	// Remove host files for this device.
	err := unixDeviceDeleteFiles(d.state, d.inst.DevicesPath(), "unix", d.name, "")
	if err != nil {
		return fmt.Errorf("Failed to delete files for device '%s': %v", d.name, err)
	}

	return nil
}

// loadUsb scans the host machine for USB devices.
func (d *usb) loadUsb() ([]USBEvent, error) {
	result := []USBEvent{}

	ents, err := ioutil.ReadDir(usbDevPath)
	if err != nil {
		/* if there are no USB devices, let's render an empty list,
		 * i.e. no usb devices */
		if os.IsNotExist(err) {
			return result, nil
		}
		return nil, err
	}

	for _, ent := range ents {
		values, err := d.loadRawValues(path.Join(usbDevPath, ent.Name()))
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}

			return []USBEvent{}, err
		}

		parts := strings.Split(values["dev"], ":")
		if len(parts) != 2 {
			return []USBEvent{}, fmt.Errorf("invalid device value %s", values["dev"])
		}

		usb, err := USBNewEvent(
			"add",
			values["idVendor"],
			values["idProduct"],
			parts[0],
			parts[1],
			values["busnum"],
			values["devnum"],
			values["devname"],
			[]string{},
			0,
		)
		if err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return nil, err
		}

		result = append(result, usb)
	}

	return result, nil
}

func (d *usb) loadRawValues(p string) (map[string]string, error) {
	values := map[string]string{
		"idVendor":  "",
		"idProduct": "",
		"dev":       "",
		"busnum":    "",
		"devnum":    "",
	}

	for k := range values {
		v, err := ioutil.ReadFile(path.Join(p, k))
		if err != nil {
			return nil, err
		}

		values[k] = strings.TrimSpace(string(v))
	}

	return values, nil
}
<|endoftext|>


<commit_before>package lynx

import (
	"encoding/json"
	"reflect"
	"testing"
)

func TestJSONUnmarshalEJ(t *testing.T) {
	ej := EncryptedJSON{}
	err := json.Unmarshal([]byte(`{"foo":"bar"}`), &ej)
	if err != nil {
		t.Errorf("unexpected error unmarshalling value: %s", err)
		return
	}
	if ej.String() != `{"foo":"bar"}` {
		t.Errorf("unexpected string value: %s", ej.String())
		return
	}
}

func TestJSONMarshalEJ(t *testing.T) {
	ej := NewEncryptedJSON(`{"foo":"bar"}`)
	m, err := json.Marshal(ej)
	if err != nil {
		t.Errorf("unexpected error marshalling value: %s", err)
		return
	}

	if !reflect.DeepEqual(m, []byte(`{"foo":"bar"}`)) {
		t.Errorf("unexpected marshalled value: %s", string(m))
		return
	}
}

func TestUpdatingStringPointerEJ(t *testing.T) {
	ej := NewEncryptedJSON(`{"foo":"bar"}`)
	s := ej.EncryptableString()
	*s = `{"foo":"bar"}`
	if ej.String() != `{"foo":"bar"}` {
		t.Errorf("unexpected string value: %s", ej.String())
		return
	}
}

func TestScanEJ(t *testing.T) {
	for _, e := range []struct {
		Type   string
		Value  interface{}
		Valid  bool
		Output string
	}{
		{"string", `{"foo":"bar"}`, true, `{"foo":"bar"}`},
		{"[]byte", []byte(`{"foo":"bar"}`), true, `{"foo":"bar"}`},
	} {
		ej := EncryptedJSON{}
		err := ej.Scan(e.Value)
		if e.Valid && err != nil {
			t.Errorf("Failed to scan %s: %s", e.Type, err)
			continue
		} else if !e.Valid && err == nil {
			t.Errorf("Failed to not scan %s", e.Type)
			continue
		}

		if !e.Valid {
			continue
		}
	}
}
<commit_msg>Added more tests<commit_after>package lynx

import (
	"encoding/json"
	"reflect"
	"testing"
)

func TestJSONUnmarshalEJ(t *testing.T) {
	ej := EncryptedJSON{}
	err := json.Unmarshal([]byte(`{"foo":"bar"}`), &ej)
	if err != nil {
		t.Errorf("unexpected error unmarshalling value: %s", err)
		return
	}
	if ej.String() != `{"foo":"bar"}` {
		t.Errorf("unexpected string value: %s", ej.String())
		return
	}
}

func TestJSONUnmarshalJSONEJ(t *testing.T) {
	ej := NewEncryptedJSON(``)
	err := ej.UnmarshalJSON([]byte(nil))

	if err == nil {
		t.Error("Expected error: EncryptedJSON: UnmarshalJSON on nil data")
		return
	}
}

func TestJSONMarshalEJ(t *testing.T) {
	ej := NewEncryptedJSON(`{"foo":"bar"}`)
	m, err := json.Marshal(ej)
	if err != nil {
		t.Errorf("unexpected error marshalling value: %s", err)
		return
	}

	if !reflect.DeepEqual(m, []byte(`{"foo":"bar"}`)) {
		t.Errorf("unexpected marshalled value: %s", string(m))
		return
	}
}

func TestUpdatingStringPointerEJ(t *testing.T) {
	ej := NewEncryptedJSON(`{"foo":"bar"}`)
	s := ej.EncryptableString()
	*s = `{"foo":"bar"}`
	if ej.String() != `{"foo":"bar"}` {
		t.Errorf("unexpected string value: %s", ej.String())
		return
	}
}

func TestScanEJ(t *testing.T) {
	for _, e := range []struct {
		Type   string
		Value  interface{}
		Valid  bool
		Output string
	}{
		{"string", `{"foo":"bar"}`, true, `{"foo":"bar"}`},
		{"[]byte", []byte(`{"foo":"bar"}`), true, `{"foo":"bar"}`},
		{"nil", nil, true, ""},
	} {
		ej := EncryptedJSON{}
		err := ej.Scan(e.Value)
		if e.Valid && err != nil {
			t.Errorf("Failed to scan %s: %s", e.Type, err)
			continue
		} else if !e.Valid && err == nil {
			t.Errorf("Failed to not scan %s", e.Type)
			continue
		}

		if !e.Valid {
			continue
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context_test

import (
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/process"
	"github.com/juju/juju/process/context"
)

type registerSuite struct {
	commandSuite

	registerCmd *context.RegisterCommand
}

var _ = gc.Suite(&registerSuite{})

func (s *registerSuite) SetUpTest(c *gc.C) {
	s.commandSuite.SetUpTest(c)

	s.registerCmd = context.NewRegisterCommand(s.Ctx.Context)
	s.setCommand(c, "register", s.registerCmd)
}

func (s *registerSuite) init(c *gc.C, name, id, status string) {
	s.registerCmd.Init([]string{s.proc.Name, "abc123"})
	//s.registerCmd.Details = ...
	//s.registerCmd.Space = ...
	//s.registerCmd.Env = ...
}

func (s *registerSuite) TestCommandRegistered(c *gc.C) {
	s.checkCommandRegistered(c)
}

func (s *registerSuite) TestHelp(c *gc.C) {
	s.checkHelp(c, `
usage: register [options] <name> <id> [<details>]
purpose: register a workload process

options:
--env  (= )
    environment variables
--space (= "")
    network space

"register" is used while a hook is running to let Juju know that
a workload process has been manually started. The information used
to start the process must be provided when "register" is run.

The process name must correspond to one of the processes defined in
the charm's metadata.yaml.
`[1:])
}

func (s *registerSuite) TestInitAllArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"}`,
	})
	c.Assert(err, jc.ErrorIsNil)

	c.Check(s.registerCmd.Name, gc.Equals, s.proc.Name)
	c.Check(s.registerCmd.Id, gc.Equals, "abc123")
	c.Check(s.registerCmd.Details, jc.DeepEquals, process.LaunchDetails{
		UniqueID: "abc123",
		Status:   "okay",
	})
	c.Check(s.registerCmd.Space, gc.Equals, "")
	c.Check(s.registerCmd.Env, gc.HasLen, 0)
}

func (s *registerSuite) TestInitMinArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
	})
	c.Assert(err, jc.ErrorIsNil)

	c.Check(s.registerCmd.Name, gc.Equals, s.proc.Name)
	c.Check(s.registerCmd.Id, gc.Equals, "abc123")
	c.Check(s.registerCmd.Details, jc.DeepEquals, process.LaunchDetails{})
	c.Check(s.registerCmd.Space, gc.Equals, "")
	c.Check(s.registerCmd.Env, gc.HasLen, 0)
}

func (s *registerSuite) TestInitTooFewArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{})
	c.Check(err, gc.ErrorMatches, "expected at least 2 args, got: .*")

	err = s.registerCmd.Init([]string{s.proc.Name})
	c.Check(err, gc.ErrorMatches, "expected at least 2 args, got: .*")
}

func (s *registerSuite) TestInitTooManyArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"}`,
		"other",
	})

	c.Check(err, gc.ErrorMatches, "expected at most 3 args, got: .*")
}

func (s *registerSuite) TestInitEmptyName(c *gc.C) {
	err := s.registerCmd.Init([]string{
		"",
		"abc123",
	})

	c.Check(err, gc.ErrorMatches, "got empty name")
}

func (s *registerSuite) TestInitEmptyId(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"",
	})

	c.Check(err, gc.ErrorMatches, "got empty id")
}

func (s *registerSuite) TestInitMissingDetailsId(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"status":"okay"}`,
	})

	c.Check(err, gc.ErrorMatches, "UniqueID must be set")
}

func (s *registerSuite) TestInitMissingDetailsStatus(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123"}`,
	})

	c.Check(err, gc.ErrorMatches, "Status must be set")
}

func (s *registerSuite) TestInitBadJSON(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"`,
	})

	c.Check(err, gc.ErrorMatches, "unexpected end of JSON input")
}

func (s *registerSuite) TestRun(c *gc.C) {
	s.init(c, s.proc.Name, "abc123", "running")

	s.checkRun(c, "", "")
	s.Stub.CheckCallNames(c, "Set")
}
<commit_msg>Add tests for the --space option.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package context_test

import (
	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/process"
	"github.com/juju/juju/process/context"
)

type registerSuite struct {
	commandSuite

	registerCmd *context.RegisterCommand
}

var _ = gc.Suite(&registerSuite{})

func (s *registerSuite) SetUpTest(c *gc.C) {
	s.commandSuite.SetUpTest(c)

	s.registerCmd = context.NewRegisterCommand(s.Ctx.Context)
	s.setCommand(c, "register", s.registerCmd)
}

func (s *registerSuite) init(c *gc.C, name, id, status string) {
	s.registerCmd.Init([]string{s.proc.Name, "abc123"})
	//s.registerCmd.Details = ...
	//s.registerCmd.Space = ...
	//s.registerCmd.Env = ...
}

func (s *registerSuite) TestCommandRegistered(c *gc.C) {
	s.checkCommandRegistered(c)
}

func (s *registerSuite) TestHelp(c *gc.C) {
	s.checkHelp(c, `
usage: register [options] <name> <id> [<details>]
purpose: register a workload process

options:
--env  (= )
    environment variables
--space (= "")
    network space

"register" is used while a hook is running to let Juju know that
a workload process has been manually started. The information used
to start the process must be provided when "register" is run.

The process name must correspond to one of the processes defined in
the charm's metadata.yaml.
`[1:])
}

func (s *registerSuite) TestInitAllArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"}`,
	})
	c.Assert(err, jc.ErrorIsNil)

	c.Check(s.registerCmd.Name, gc.Equals, s.proc.Name)
	c.Check(s.registerCmd.Id, gc.Equals, "abc123")
	c.Check(s.registerCmd.Details, jc.DeepEquals, process.LaunchDetails{
		UniqueID: "abc123",
		Status:   "okay",
	})
	c.Check(s.registerCmd.Space, gc.Equals, "")
	c.Check(s.registerCmd.Env, gc.HasLen, 0)
}

func (s *registerSuite) TestInitMinArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
	})
	c.Assert(err, jc.ErrorIsNil)

	c.Check(s.registerCmd.Name, gc.Equals, s.proc.Name)
	c.Check(s.registerCmd.Id, gc.Equals, "abc123")
	c.Check(s.registerCmd.Details, jc.DeepEquals, process.LaunchDetails{})
	c.Check(s.registerCmd.Space, gc.Equals, "")
	c.Check(s.registerCmd.Env, gc.HasLen, 0)
}

func (s *registerSuite) TestInitTooFewArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{})
	c.Check(err, gc.ErrorMatches, "expected at least 2 args, got: .*")

	err = s.registerCmd.Init([]string{s.proc.Name})
	c.Check(err, gc.ErrorMatches, "expected at least 2 args, got: .*")
}

func (s *registerSuite) TestInitTooManyArgs(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"}`,
		"other",
	})

	c.Check(err, gc.ErrorMatches, "expected at most 3 args, got: .*")
}

func (s *registerSuite) TestInitEmptyName(c *gc.C) {
	err := s.registerCmd.Init([]string{
		"",
		"abc123",
	})

	c.Check(err, gc.ErrorMatches, "got empty name")
}

func (s *registerSuite) TestInitEmptyId(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"",
	})

	c.Check(err, gc.ErrorMatches, "got empty id")
}

func (s *registerSuite) TestInitMissingDetailsId(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"status":"okay"}`,
	})

	c.Check(err, gc.ErrorMatches, "UniqueID must be set")
}

func (s *registerSuite) TestInitMissingDetailsStatus(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123"}`,
	})

	c.Check(err, gc.ErrorMatches, "Status must be set")
}

func (s *registerSuite) TestInitBadJSON(c *gc.C) {
	err := s.registerCmd.Init([]string{
		s.proc.Name,
		"abc123",
		`{"id":"abc123", "status":"okay"`,
	})

	c.Check(err, gc.ErrorMatches, "unexpected end of JSON input")
}

func (s *registerSuite) TestInitSpaceKnown(c *gc.C) {
	s.registerCmd.Space = "a space"

	err := s.registerCmd.Init([]string{s.proc.Name, "abc123"})

	c.Check(err, jc.Satisfies, errors.IsNotImplemented)
}

func (s *registerSuite) TestInitSpaceUnknown(c *gc.C) {
	s.registerCmd.Space = "a space"

	err := s.registerCmd.Init([]string{s.proc.Name, "abc123"})

	c.Check(err, jc.Satisfies, errors.IsNotImplemented)
}

func (s *registerSuite) TestRun(c *gc.C) {
	s.init(c, s.proc.Name, "abc123", "running")

	s.checkRun(c, "", "")
	s.Stub.CheckCallNames(c, "Set")
}
<|endoftext|>


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

// Package flatpack implements a mechanism to convert arbitrary Go
// data, possibly including unexported fields and shared and/or cyclic
// substructure, into and back from a purely tree-structured
// datastructure without unexported fields that can be serialised
// using encoding.json or the like.
//
// There are two parts to this mechanism: the Flatpack type, the
// serialization-friendly container which stores the converted data
// (and whose Pack and Unpack methods do the necessary conversion),
// and an package-internal type registry used to locate the correct
// type when deserializing and unpacking Flatpacks.  This type
// registry must be pre-populated with all the (named) types that
// might be encountered; it will be convenient to do so by calling
// RegisterType and/or RegisterTypeOf from an init() func in each
// package whose types will be serialized.

// BUG(cpcallen): does not handle interior pointers (pointers to array
// or struct element) correctly.
//
// BUG(cpcallen): does not handle shared backing arrays for slices (or
// strings) correctly.
//
// BUG(cpcallen): does not preserve spare capacity (or the values of
// elements in the underlying array between len and cap).
package flatpack

import (
	"fmt"
	"reflect"
)

// A Flatpack is an easily-serializable representation of a collection
// of arbitrary Go values.  It will preserve relationships, including
// cycles and shared substructure, between stored values while being
// guaranteed not to actually contain either.  Nor will it contain any
// private struct fields[1], nil pointers[2] or maps with non-string
// keys.  It also ensures all interface types have an accompanying tag
// to allow the correct concrete type to be found when unmarshalling.
//
// [1] Except for private fields used internally for packing and
// unpacking the flatpack, which do not need to be (de)serialised.
//
// [2] In fact, it has no pointers except the not-user-accessible ones
// the compiler uses to implement interface values too large to fit in
// a machine word.
type Flatpack struct {
	// FIXME: types?

	// Labels is the table of contents, maping the label of a value to
	// the index within Values it is stored at.  It should not be
	// accessed directly; instead, use the Pack and Unpack methods.
	Labels map[string]ref

	// Values is a slice of tagged, flattened values.  It is exported
	// only to allow serialisation.  The contents should not be
	// accessed directly; instead, use the Pack and Unpack methods.
	Values []tagged

	// ptr2ref is a map of (pointer) values to their corresponding ref
	// (index of flattened value).  Used during packing.
	ptr2ref map[interface{}]ref

	// ref2ptr is a slice mapping refs to (the reflect.Value
	// representation of) their corresponding pointer values.  Used
	// during unpacking.
	ref2ptr []reflect.Value
}

// New creates and initializes a new flatpack.
func New() *Flatpack {
	return &Flatpack{
		Labels:  make(map[string]ref),
		ptr2ref: make(map[interface{}]ref),
	}
}

// Pack adds an arbitrary Go value to the flatpack, giving it the
// specified label.  It is an error to reuse a label within the same
// Flatpack, or to call Pack after Seal.
//
// FIXME: warn (or even panic) if unregistered types are encountered?
func (f *Flatpack) Pack(label string, value interface{}) {
	if f.ptr2ref == nil {
		panic("Flatpack is already sealed")
	}
	if _, exists := f.Labels[label]; exists {
		panic(fmt.Errorf("Duplicate label %s", label))
	}
	idx := len(f.Values)
	f.Values = append(f.Values, tagged{})
	v := reflect.ValueOf(value)
	fv := f.flatten(v)
	f.Values[idx] = tagged{tIDOf(v.Type()), fv.Interface()}
	f.Labels[label] = ref(idx)
}

// Unpack retrieves the value associated with the given label from the
// Flatpack and returns it.
func (f *Flatpack) Unpack(label string) interface{} {
	panic("Not implemented")
}

// Seal removes the index used when flattening pointer values.  This
// ensures the Flatpack will not cause inadvertent retention of the
// original (non-flat) objects if they would otherwise be eligible for
// garbage collection.
//
// After a Flatpack is sealed it cannot have additional values added to it.
func (f *Flatpack) Seal() {
	f.ptr2ref = nil
}

// ref replaces all pointer types in flattened values.  It is just the
// numerical index of the packed, flattened representation of the
// target object within the flatpack's .Values slice, or -1 if the
// pointer is a nil pointer.
type ref int

// tagged replaces all interface types in flattened values.
type tagged struct {
	T tID
	V interface{}
}

// flatten takes an ordinary reflect.Value and returns it in flattened
// form.  In particular, the type of the result will be the flatType
// of the type of the argument:
//
//     f.flatten(v).Type() == flatType(v.Type())
//
// Iff given a pointer to a value then then the flattened value will
// be appended to f.Values (if the pointed-to value has not not
// already been added), and the return value will be a ref containing
// the index of the packed, flattened object.  The caller is otherwise
// responsible for storing the flattened value in the flatpack.
func (f *Flatpack) flatten(v reflect.Value) reflect.Value {
	typ := v.Type()
	// FIXME: use type registry?
	ftyp := flatType(typ)

	switch typ.Kind() {
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
		return v
	case reflect.Array:
		r := reflect.New(ftyp).Elem()
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.flatten(v.Index(i)))
		}
		return r
	case reflect.Interface:
		if v.IsNil() {
			return reflect.ValueOf(tagged{T: tIDOf(nil), V: nil})
		}
		return reflect.ValueOf(tagged{
			T: tIDOf(v.Elem().Type()),
			V: f.flatten(v.Elem()).Interface(),
		})
	case reflect.Map:
		var r reflect.Value
		if ftyp.Kind() == reflect.Map {
			r = reflect.MakeMap(ftyp)
			for _, k := range v.MapKeys() {
				r.SetMapIndex(k, f.flatten(v.MapIndex(k)))
			}
		} else {
			r = reflect.MakeSlice(ftyp, v.Len(), v.Len())
			for i, k := range v.MapKeys() {
				pair := reflect.New(ftyp.Elem()).Elem()
				pair.Field(0).Set(f.flatten(k))
				pair.Field(1).Set(f.flatten(v.MapIndex(k)))
				r.Index(i).Set(pair)
			}
		}
		return r
	case reflect.Ptr:
		// Check for nil pointer.
		if v.IsNil() {
			return reflect.ValueOf(ref(-1))
		}
		// Check to see if we have already flattened thing pointed to.
		if r, ok := f.ptr2ref[v.Interface()]; ok {
			return reflect.ValueOf(r)
		}
		// Allocate a space in the flatpack for the (flattened
		// version) of the thing v points at, and record in f.index:
		idx := len(f.Values)
		f.Values = append(f.Values, tagged{T: tIDOf(v.Elem().Type())})
		f.ptr2ref[v.Interface()] = ref(idx)
		// Flatten and save result in earlier-allocated spot in f.Values:
		f.Values[idx].V = f.flatten(v.Elem()).Interface()
		//	Return newly-allocated index idx as ref:
		return reflect.ValueOf(ref(idx))
	case reflect.Slice:
		// Won't need to append to r before seralizing, and any spare
		// capacity will not be preserved when deserializing, so trim
		// our flattened version now (i.e., cap == len).
		r := reflect.MakeSlice(ftyp, v.Len(), v.Len())
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.flatten(v.Index(i)))
		}
		return r
	case reflect.Struct:
		// To (usefully) read unexported fields (using unsafe) we need
		// to be able to get pointers to them, so make an addressable
		// copy of v, if it is not already addressable:
		if !v.CanAddr() {
			vv := reflect.New(typ).Elem()
			vv.Set(v)
			v = vv
		}
		r := reflect.New(ftyp).Elem()
		for i := 0; i < ftyp.NumField(); i++ {
			r.Field(i).Set(f.flatten(defeat(v.Field(i))))
		}
		return r
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
		panic(fmt.Errorf("Flattening of %s not implemented", typ.Kind()))
	default:
		panic(fmt.Errorf("Invalid Kind %s", typ.Kind()))
	}
}

// unflatten takes a (non-flat) tID and a value of that type's
// corresponding flattened type and converts it back to its original
// pre-flattened form.  In particular, if it succeeds then the the tID
// of the type of result will be the same as the tID value given as
// the first argument, the flatType of the argument will be the type
//
//     tIDOf(f.unflatten(t, v).Type()) == t && flatType(t) == v.Type()
//
func (f *Flatpack) unflatten(typ reflect.Type, v reflect.Value) reflect.Value {
	ftyp := flatType(typ)
	if v.Type() != ftyp {
		panic(fmt.Errorf("Type mismatch unflattening a %s: expected %s but got %s", typ, ftyp, v.Type()))
	}
	switch typ.Kind() {
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
		return v
	case reflect.Array:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))

	case reflect.Interface:
		tid := v.Field(0).Interface().(tID)
		if tid == "" { // Special case: {"", nil} -> nil
			if !v.Field(1).IsNil() {
				panic("Non-nil vlaue with no type??")
			}
			return reflect.Zero(typ)
		}
		ttyp, _ := typesForTID(tid)
		return f.unflatten(ttyp, v.Field(1).Elem()).Convert(typ)
	case reflect.Map:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))

	case reflect.Ptr:
		idx := int(v.Interface().(ref))
		switch {
		case idx == -1:
			return reflect.Zero(typ)
		case idx < -1, idx > len(f.Values):
			panic("ref out of range")
		case f.ref2ptr == nil: // First time unflattening any pointer?
			f.ref2ptr = make([]reflect.Value, len(f.Values))
			fallthrough
		case f.ref2ptr[idx] == reflect.Value{}:
			if tIDOf(typ.Elem()) != f.Values[idx].T {
				// FIXME: better error handling
				panic("type mismatch")
			}
			f.ref2ptr[idx] = reflect.New(typ.Elem())
			ttyp, _ := typesForTID(f.Values[idx].T)
			tval := reflect.ValueOf(f.Values[idx].V)
			f.ref2ptr[idx].Elem().Set(f.unflatten(ttyp, tval))
			fallthrough
		default:
			return f.ref2ptr[idx]
		}
	case reflect.Slice:
		// No info re: spare capacity survives (de)serialisation, so
		// assume cap == len.
		r := reflect.MakeSlice(typ, v.Len(), v.Len())
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.unflatten(typ.Elem(), v.Index(i)))
		}
		return r
	case reflect.Struct:
		r := reflect.New(typ).Elem()
		for i := 0; i < typ.NumField(); i++ {
			src := v.Field(i)
			dst := defeat(r.Field(i))
			dst.Set(f.unflatten(dst.Type(), src))
		}
		return r
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))
	default:
		panic(fmt.Errorf("Invalid Kind %s", typ.Kind()))
	}
}

// FIXME: remove this once unlattening pointers fixed
func makeAddressable(v reflect.Value) reflect.Value {
	if v.CanAddr() {
		return v
	}
	vv := reflect.New(v.Type()).Elem()
	vv.Set(v)
	return vv
}
<commit_msg>Improve invariant tests for unflatten<commit_after>/* Copyright 2017 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package flatpack implements a mechanism to convert arbitrary Go
// data, possibly including unexported fields and shared and/or cyclic
// substructure, into and back from a purely tree-structured
// datastructure without unexported fields that can be serialised
// using encoding.json or the like.
//
// There are two parts to this mechanism: the Flatpack type, the
// serialization-friendly container which stores the converted data
// (and whose Pack and Unpack methods do the necessary conversion),
// and an package-internal type registry used to locate the correct
// type when deserializing and unpacking Flatpacks.  This type
// registry must be pre-populated with all the (named) types that
// might be encountered; it will be convenient to do so by calling
// RegisterType and/or RegisterTypeOf from an init() func in each
// package whose types will be serialized.

// BUG(cpcallen): does not handle interior pointers (pointers to array
// or struct element) correctly.
//
// BUG(cpcallen): does not handle shared backing arrays for slices (or
// strings) correctly.
//
// BUG(cpcallen): does not preserve spare capacity (or the values of
// elements in the underlying array between len and cap).
package flatpack

import (
	"fmt"
	"reflect"
)

// A Flatpack is an easily-serializable representation of a collection
// of arbitrary Go values.  It will preserve relationships, including
// cycles and shared substructure, between stored values while being
// guaranteed not to actually contain either.  Nor will it contain any
// private struct fields[1], nil pointers[2] or maps with non-string
// keys.  It also ensures all interface types have an accompanying tag
// to allow the correct concrete type to be found when unmarshalling.
//
// [1] Except for private fields used internally for packing and
// unpacking the flatpack, which do not need to be (de)serialised.
//
// [2] In fact, it has no pointers except the not-user-accessible ones
// the compiler uses to implement interface values too large to fit in
// a machine word.
type Flatpack struct {
	// FIXME: types?

	// Labels is the table of contents, maping the label of a value to
	// the index within Values it is stored at.  It should not be
	// accessed directly; instead, use the Pack and Unpack methods.
	Labels map[string]ref

	// Values is a slice of tagged, flattened values.  It is exported
	// only to allow serialisation.  The contents should not be
	// accessed directly; instead, use the Pack and Unpack methods.
	Values []tagged

	// ptr2ref is a map of (pointer) values to their corresponding ref
	// (index of flattened value).  Used during packing.
	ptr2ref map[interface{}]ref

	// ref2ptr is a slice mapping refs to (the reflect.Value
	// representation of) their corresponding pointer values.  Used
	// during unpacking.
	ref2ptr []reflect.Value
}

// New creates and initializes a new flatpack.
func New() *Flatpack {
	return &Flatpack{
		Labels:  make(map[string]ref),
		ptr2ref: make(map[interface{}]ref),
	}
}

// Pack adds an arbitrary Go value to the flatpack, giving it the
// specified label.  It is an error to reuse a label within the same
// Flatpack, or to call Pack after Seal.
//
// FIXME: warn (or even panic) if unregistered types are encountered?
func (f *Flatpack) Pack(label string, value interface{}) {
	if f.ptr2ref == nil {
		panic("Flatpack is already sealed")
	}
	if _, exists := f.Labels[label]; exists {
		panic(fmt.Errorf("Duplicate label %s", label))
	}
	idx := len(f.Values)
	f.Values = append(f.Values, tagged{})
	v := reflect.ValueOf(value)
	fv := f.flatten(v)
	f.Values[idx] = tagged{tIDOf(v.Type()), fv.Interface()}
	f.Labels[label] = ref(idx)
}

// Unpack retrieves the value associated with the given label from the
// Flatpack and returns it.
func (f *Flatpack) Unpack(label string) interface{} {
	panic("Not implemented")
}

// Seal removes the index used when flattening pointer values.  This
// ensures the Flatpack will not cause inadvertent retention of the
// original (non-flat) objects if they would otherwise be eligible for
// garbage collection.
//
// After a Flatpack is sealed it cannot have additional values added to it.
func (f *Flatpack) Seal() {
	f.ptr2ref = nil
}

// ref replaces all pointer types in flattened values.  It is just the
// numerical index of the packed, flattened representation of the
// target object within the flatpack's .Values slice, or -1 if the
// pointer is a nil pointer.
type ref int

// tagged replaces all interface types in flattened values.
type tagged struct {
	T tID
	V interface{}
}

// flatten takes an ordinary reflect.Value and returns it in flattened
// form.  In particular, the type of the result will be the flatType
// of the type of the argument:
//
//     f.flatten(v).Type() == flatType(v.Type())
//
// Iff given a pointer to a value then then the flattened value will
// be appended to f.Values (if the pointed-to value has not not
// already been added), and the return value will be a ref containing
// the index of the packed, flattened object.  The caller is otherwise
// responsible for storing the flattened value in the flatpack.
func (f *Flatpack) flatten(v reflect.Value) reflect.Value {
	typ := v.Type()
	// FIXME: use type registry?
	ftyp := flatType(typ)

	switch typ.Kind() {
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
		return v
	case reflect.Array:
		r := reflect.New(ftyp).Elem()
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.flatten(v.Index(i)))
		}
		return r
	case reflect.Interface:
		if v.IsNil() {
			return reflect.ValueOf(tagged{T: tIDOf(nil), V: nil})
		}
		return reflect.ValueOf(tagged{
			T: tIDOf(v.Elem().Type()),
			V: f.flatten(v.Elem()).Interface(),
		})
	case reflect.Map:
		var r reflect.Value
		if ftyp.Kind() == reflect.Map {
			r = reflect.MakeMap(ftyp)
			for _, k := range v.MapKeys() {
				r.SetMapIndex(k, f.flatten(v.MapIndex(k)))
			}
		} else {
			r = reflect.MakeSlice(ftyp, v.Len(), v.Len())
			for i, k := range v.MapKeys() {
				pair := reflect.New(ftyp.Elem()).Elem()
				pair.Field(0).Set(f.flatten(k))
				pair.Field(1).Set(f.flatten(v.MapIndex(k)))
				r.Index(i).Set(pair)
			}
		}
		return r
	case reflect.Ptr:
		// Check for nil pointer.
		if v.IsNil() {
			return reflect.ValueOf(ref(-1))
		}
		// Check to see if we have already flattened thing pointed to.
		if r, ok := f.ptr2ref[v.Interface()]; ok {
			return reflect.ValueOf(r)
		}
		// Allocate a space in the flatpack for the (flattened
		// version) of the thing v points at, and record in f.index:
		idx := len(f.Values)
		f.Values = append(f.Values, tagged{T: tIDOf(v.Elem().Type())})
		f.ptr2ref[v.Interface()] = ref(idx)
		// Flatten and save result in earlier-allocated spot in f.Values:
		f.Values[idx].V = f.flatten(v.Elem()).Interface()
		//	Return newly-allocated index idx as ref:
		return reflect.ValueOf(ref(idx))
	case reflect.Slice:
		// Won't need to append to r before seralizing, and any spare
		// capacity will not be preserved when deserializing, so trim
		// our flattened version now (i.e., cap == len).
		r := reflect.MakeSlice(ftyp, v.Len(), v.Len())
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.flatten(v.Index(i)))
		}
		return r
	case reflect.Struct:
		// To (usefully) read unexported fields (using unsafe) we need
		// to be able to get pointers to them, so make an addressable
		// copy of v, if it is not already addressable:
		if !v.CanAddr() {
			vv := reflect.New(typ).Elem()
			vv.Set(v)
			v = vv
		}
		r := reflect.New(ftyp).Elem()
		for i := 0; i < ftyp.NumField(); i++ {
			r.Field(i).Set(f.flatten(defeat(v.Field(i))))
		}
		return r
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
		panic(fmt.Errorf("Flattening of %s not implemented", typ.Kind()))
	default:
		panic(fmt.Errorf("Invalid Kind %s", typ.Kind()))
	}
}

// unflatten takes a (non-flat) tID and a value of that type's
// corresponding flattened type and converts it back to its original
// pre-flattened form.  In particular, if it succeeds then the the tID
// of the type of result will be the same as the tID value given as
// the first argument, the flatType of the argument will be the type
//
//     tIDOf(f.unflatten(t, v).Type()) == t && flatType(t) == v.Type()
//
func (f *Flatpack) unflatten(typ reflect.Type, v reflect.Value) (ret reflect.Value) {
	// FIXME: perhaps replace these runtime assertions with good tests?
	if ftyp := flatType(typ); v.Type() != ftyp {
		panic(fmt.Errorf("Type mismatch unflattening a %s: expected %s but got %s", typ, ftyp, v.Type()))
	}
	defer func() {
		if ret.Type() != typ {
			panic(fmt.Errorf("Incorrect return type %s (expected %s)", ret.Type(), typ))
		}
	}()

	switch typ.Kind() {
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
		return v
	case reflect.Array:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))

	case reflect.Interface:
		tid := v.Field(0).Interface().(tID)
		if tid == "" { // Special case: {"", nil} -> nil
			if !v.Field(1).IsNil() {
				panic("Non-nil vlaue with no type??")
			}
			return reflect.Zero(typ)
		}
		ttyp, _ := typesForTID(tid)
		return f.unflatten(ttyp, v.Field(1).Elem()).Convert(typ)
	case reflect.Map:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))

	case reflect.Ptr:
		idx := int(v.Interface().(ref))
		switch {
		case idx == -1:
			return reflect.Zero(typ)
		case idx < -1, idx > len(f.Values):
			panic("ref out of range")
		case f.ref2ptr == nil: // First time unflattening any pointer?
			f.ref2ptr = make([]reflect.Value, len(f.Values))
			fallthrough
		case f.ref2ptr[idx] == reflect.Value{}:
			if tIDOf(typ.Elem()) != f.Values[idx].T {
				// FIXME: better error handling
				panic("type mismatch")
			}
			f.ref2ptr[idx] = reflect.New(typ.Elem())
			ttyp, _ := typesForTID(f.Values[idx].T)
			tval := reflect.ValueOf(f.Values[idx].V)
			f.ref2ptr[idx].Elem().Set(f.unflatten(ttyp, tval))
			fallthrough
		default:
			return f.ref2ptr[idx]
		}
	case reflect.Slice:
		// No info re: spare capacity survives (de)serialisation, so
		// assume cap == len.
		r := reflect.MakeSlice(typ, v.Len(), v.Len())
		for i := 0; i < v.Len(); i++ {
			r.Index(i).Set(f.unflatten(typ.Elem(), v.Index(i)))
		}
		return r
	case reflect.Struct:
		r := reflect.New(typ).Elem()
		for i := 0; i < typ.NumField(); i++ {
			src := v.Field(i)
			dst := defeat(r.Field(i))
			dst.Set(f.unflatten(dst.Type(), src))
		}
		return r
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
		panic(fmt.Errorf("Unflattening of %s not implemented", typ.Kind()))
	default:
		panic(fmt.Errorf("Invalid Kind %s", typ.Kind()))
	}
}

// FIXME: remove this once unlattening pointers fixed
func makeAddressable(v reflect.Value) reflect.Value {
	if v.CanAddr() {
		return v
	}
	vv := reflect.New(v.Type()).Elem()
	vv.Set(v)
	return vv
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

type NodeId int
type EdgeId int

func (id NodeId) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("%d", id)), nil
}

type Graph struct {
	Nodes map[NodeId]Node
	Edges map[EdgeId]Edge
}

func NewGraph() *Graph {
	return &Graph{
		Nodes: make(map[NodeId]Node),
		Edges: make(map[EdgeId]Edge),
	}
}

func (g *Graph) AddNode(node Node) bool {
	if _, exits := g.Nodes[node.Id]; exits {
		return false
	} else {
		g.Nodes[node.Id] = node
		return true
	}
	return false
}

func (g *Graph) GetNode(nodeId NodeId) Node {
	return g.Nodes[nodeId]
}

func (g *Graph) AddEdge(edge Edge) bool {
	if _, exits := g.Edges[edge.Id]; exits {
		return false
	} else {
		g.Edges[edge.Id] = edge
		return true
	}
	return false
}

func (g *Graph) String() string {
	return fmt.Sprintf("%+v\n %+v", g.Nodes, g.Edges)
}

type Node struct {
	Id NodeId
}

type Edge struct {
	Id   EdgeId
	Head NodeId
	Tail NodeId
}
<commit_msg>Json plz<commit_after>package main

import (
	"fmt"
	"strconv"
)

type NodeId int
type EdgeId int

type Graph struct {
	Nodes map[string]Node
	Edges map[string]Edge
}

func NewGraph() *Graph {
	return &Graph{
		Nodes: make(map[string]Node),
		Edges: make(map[string]Edge),
	}
}

func (g *Graph) AddNode(node Node) bool {
	if _, exits := g.Nodes[strconv.Itoa(int(node.Id))]; exits {
		return false
	} else {
		g.Nodes[strconv.Itoa(int(node.Id))] = node
		return true
	}
	return false
}

func (g *Graph) GetNode(nodeId NodeId) Node {
	return g.Nodes[strconv.Itoa(int(nodeId))]
}

func (g *Graph) AddEdge(edge Edge) bool {
	if _, exits := g.Edges[strconv.Itoa(int(edge.Id))]; exits {
		return false
	} else {
		g.Edges[strconv.Itoa(int(edge.Id))] = edge
		return true
	}
	return false
}

func (g *Graph) String() string {
	return fmt.Sprintf("%+v\n %+v", g.Nodes, g.Edges)
}

type Node struct {
	Id NodeId
}

type Edge struct {
	Id   EdgeId
	Head NodeId
	Tail NodeId
}
<|endoftext|>