<commit_before>package transmission

type (
	// TorrentCommand is the root command to interact with Transmission via RPC
	TorrentCommand struct {
		Method    string           `json:"method,omitempty"`
		Arguments TorrentArguments `json:"arguments,omitempty"`
		Result    string           `json:"result,omitempty"`
	}
	// TorrentArguments specifies the TorrentCommand in more detail
	TorrentArguments struct {
		Fields       []string              `json:"fields,omitempty"`
		Torrents     []Torrent             `json:"torrents,omitempty"`
		Ids          []int                 `json:"ids,omitempty"`
		DeleteData   bool                  `json:"delete-local-data,omitempty"`
		DownloadDir  string                `json:"download-dir,omitempty"`
		MetaInfo     string                `json:"metainfo,omitempty"`
		Filename     string                `json:"filename,omitempty"`
		TorrentAdded TorrentArgumentsAdded `json:"torrent-added"`
	}
	// TorrentArgumentsAdded specifies the torrent to get added data from
	TorrentArgumentsAdded struct {
		HashString string `json:"hashString"`
		ID         int64  `json:"id"`
		Name       string `json:"name"`
	}

	// Torrent represents a transmission torrent
	Torrent struct {
		ID            int           `json:"id"`
		Name          string        `json:"name"`
		Status        int           `json:"status"`
		Added         int           `json:"addedDate"`
		LeftUntilDone int           `json:"leftUntilDone"`
		Eta           int           `json:"eta"`
		UploadRatio   float64       `json:"uploadRatio"`
		RateDownload  int           `json:"rateDownload"`
		RateUpload    int           `json:"rateUpload"`
		DownloadDir   string        `json:"downloadDir"`
		IsFinished    bool          `json:"isFinished"`
		PercentDone   float64       `json:"percentDone"`
		SeedRatioMode int           `json:"seedRatioMode"`
		HashString    string        `json:"hashString"`
		Error         int           `json:"error"`
		ErrorString   string        `json:"errorString"`
		Files         []File        `json:"files"`
		FilesStats    []FileStat    `json:"fileStats"`
		TrackerStats  []TrackerStat `json:"trackerStats"`
		Peers         []Peer        `json:"peers"`
	}

	// ByID implements the sort Interface to sort by ID
	ByID []Torrent
	// ByName implements the sort Interface to sort by Name
	ByName []Torrent
	// ByDate implements the sort Interface to sort by Date
	ByDate []Torrent
	// ByRatio implements the sort Interface to sort by Ratio
	ByRatio []Torrent

	// File is a file contained inside a torrent
	File struct {
		BytesCompleted int64  `json:"bytesCompleted"`
		Length         int64  `json:"length"`
		Name           string `json:"name"`
	}

	// FileStat describe a file's priority & if it's wanted
	FileStat struct {
		BytesCompleted int64 `json:"bytesCompleted"`
		Priority       int   `json:"priority"`
		Wanted         bool  `json:"wanted"`
	}

	// TrackerStat has stats about the torrent's tracker
	TrackerStat struct {
		Announce              string `json:"announce"`
		AnnounceState         int    `json:"announceState"`
		DownloadCount         int    `json:"downloadCount"`
		HasAnnounced          bool   `json:"hasAnnounced"`
		HasScraped            bool   `json:"hasScraped"`
		Host                  string `json:"host"`
		ID                    int    `json:"id"`
		IsBackup              bool   `json:"isBackup"`
		LastAnnouncePeerCount int    `json:"lastAnnouncePeerCount"`
		LastAnnounceResult    string `json:"lastAnnounceResult"`
		LastAnnounceStartTime int    `json:"lastAnnounceStartTime"`
		LastAnnounceSucceeded bool   `json:"lastAnnounceSucceeded"`
		LastAnnounceTime      int    `json:"lastAnnounceTime"`
		LastAnnounceTimedOut  bool   `json:"lastAnnounceTimedOut"`
		LastScrapeResult      string `json:"lastScrapeResult"`
		LastScrapeStartTime   int    `json:"lastScrapeStartTime"`
		LastScrapeSucceeded   bool   `json:"lastScrapeSucceeded"`
		LastScrapeTime        int    `json:"lastScrapeTime"`
		LastScrapeTimedOut    int    `json:"lastScrapeTimedOut"`
		LeecherCount          int    `json:"leecherCount"`
		NextAnnounceTime      int    `json:"nextAnnounceTime"`
		NextScrapeTime        int    `json:"nextScrapeTime"`
		Scrape                string `json:"scrape"`
		ScrapeState           int    `json:"scrapeState"`
		SeederCount           int    `json:"seederCount"`
		Tier                  int    `json:"tier"`
	}

	// Peer of a torrent
	Peer struct {
		Address            string  `json:"address"`
		ClientIsChoked     bool    `json:"clientIsChoked"`
		ClientIsInterested bool    `json:"clientIsInterested"`
		ClientName         string  `json:"clientName"`
		FlagStr            string  `json:"flagStr"`
		IsDownloadingFrom  bool    `json:"isDownloadingFrom"`
		IsEncrypted        bool    `json:"isEncrypted"`
		IsIncoming         bool    `json:"isIncoming"`
		IsUTP              bool    `json:"isUTP"`
		IsUploadingTo      bool    `json:"isUploadingTo"`
		PeerIsChoked       bool    `json:"peerIsChoked"`
		PeerIsInterested   bool    `json:"peerIsInterested"`
		Port               int     `json:"port"`
		Progress           float64 `json:"progress"`
		RateToClient       int     `json:"rateToClient"`
		RateToPeer         int     `json:"rateToPeer"`
	}
)

func (t ByID) Len() int           { return len(t) }
func (t ByID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByID) Less(i, j int) bool { return t[i].ID < t[j].ID }

func (t ByName) Len() int           { return len(t) }
func (t ByName) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByName) Less(i, j int) bool { return t[i].Name < t[j].Name }

func (t ByDate) Len() int           { return len(t) }
func (t ByDate) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByDate) Less(i, j int) bool { return t[i].Added < t[j].Added }

func (t ByRatio) Len() int           { return len(t) }
func (t ByRatio) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByRatio) Less(i, j int) bool { return t[i].UploadRatio < t[j].UploadRatio }
<commit_msg>Fix int overflow on 32bit OSs<commit_after>package transmission

type (
	// TorrentCommand is the root command to interact with Transmission via RPC
	TorrentCommand struct {
		Method    string           `json:"method,omitempty"`
		Arguments TorrentArguments `json:"arguments,omitempty"`
		Result    string           `json:"result,omitempty"`
	}
	// TorrentArguments specifies the TorrentCommand in more detail
	TorrentArguments struct {
		Fields       []string              `json:"fields,omitempty"`
		Torrents     []Torrent             `json:"torrents,omitempty"`
		Ids          []int                 `json:"ids,omitempty"`
		DeleteData   bool                  `json:"delete-local-data,omitempty"`
		DownloadDir  string                `json:"download-dir,omitempty"`
		MetaInfo     string                `json:"metainfo,omitempty"`
		Filename     string                `json:"filename,omitempty"`
		TorrentAdded TorrentArgumentsAdded `json:"torrent-added"`
	}
	// TorrentArgumentsAdded specifies the torrent to get added data from
	TorrentArgumentsAdded struct {
		HashString string `json:"hashString"`
		ID         int64  `json:"id"`
		Name       string `json:"name"`
	}

	// Torrent represents a transmission torrent
	Torrent struct {
		ID            int           `json:"id"`
		Name          string        `json:"name"`
		Status        int           `json:"status"`
		Added         int           `json:"addedDate"`
		LeftUntilDone int64         `json:"leftUntilDone"`
		Eta           int           `json:"eta"`
		UploadRatio   float64       `json:"uploadRatio"`
		RateDownload  int           `json:"rateDownload"`
		RateUpload    int           `json:"rateUpload"`
		DownloadDir   string        `json:"downloadDir"`
		IsFinished    bool          `json:"isFinished"`
		PercentDone   float64       `json:"percentDone"`
		SeedRatioMode int           `json:"seedRatioMode"`
		HashString    string        `json:"hashString"`
		Error         int           `json:"error"`
		ErrorString   string        `json:"errorString"`
		Files         []File        `json:"files"`
		FilesStats    []FileStat    `json:"fileStats"`
		TrackerStats  []TrackerStat `json:"trackerStats"`
		Peers         []Peer        `json:"peers"`
	}

	// ByID implements the sort Interface to sort by ID
	ByID []Torrent
	// ByName implements the sort Interface to sort by Name
	ByName []Torrent
	// ByDate implements the sort Interface to sort by Date
	ByDate []Torrent
	// ByRatio implements the sort Interface to sort by Ratio
	ByRatio []Torrent

	// File is a file contained inside a torrent
	File struct {
		BytesCompleted int64  `json:"bytesCompleted"`
		Length         int64  `json:"length"`
		Name           string `json:"name"`
	}

	// FileStat describe a file's priority & if it's wanted
	FileStat struct {
		BytesCompleted int64 `json:"bytesCompleted"`
		Priority       int   `json:"priority"`
		Wanted         bool  `json:"wanted"`
	}

	// TrackerStat has stats about the torrent's tracker
	TrackerStat struct {
		Announce              string `json:"announce"`
		AnnounceState         int    `json:"announceState"`
		DownloadCount         int    `json:"downloadCount"`
		HasAnnounced          bool   `json:"hasAnnounced"`
		HasScraped            bool   `json:"hasScraped"`
		Host                  string `json:"host"`
		ID                    int    `json:"id"`
		IsBackup              bool   `json:"isBackup"`
		LastAnnouncePeerCount int    `json:"lastAnnouncePeerCount"`
		LastAnnounceResult    string `json:"lastAnnounceResult"`
		LastAnnounceStartTime int    `json:"lastAnnounceStartTime"`
		LastAnnounceSucceeded bool   `json:"lastAnnounceSucceeded"`
		LastAnnounceTime      int    `json:"lastAnnounceTime"`
		LastAnnounceTimedOut  bool   `json:"lastAnnounceTimedOut"`
		LastScrapeResult      string `json:"lastScrapeResult"`
		LastScrapeStartTime   int    `json:"lastScrapeStartTime"`
		LastScrapeSucceeded   bool   `json:"lastScrapeSucceeded"`
		LastScrapeTime        int    `json:"lastScrapeTime"`
		LastScrapeTimedOut    int    `json:"lastScrapeTimedOut"`
		LeecherCount          int    `json:"leecherCount"`
		NextAnnounceTime      int    `json:"nextAnnounceTime"`
		NextScrapeTime        int    `json:"nextScrapeTime"`
		Scrape                string `json:"scrape"`
		ScrapeState           int    `json:"scrapeState"`
		SeederCount           int    `json:"seederCount"`
		Tier                  int    `json:"tier"`
	}

	// Peer of a torrent
	Peer struct {
		Address            string  `json:"address"`
		ClientIsChoked     bool    `json:"clientIsChoked"`
		ClientIsInterested bool    `json:"clientIsInterested"`
		ClientName         string  `json:"clientName"`
		FlagStr            string  `json:"flagStr"`
		IsDownloadingFrom  bool    `json:"isDownloadingFrom"`
		IsEncrypted        bool    `json:"isEncrypted"`
		IsIncoming         bool    `json:"isIncoming"`
		IsUTP              bool    `json:"isUTP"`
		IsUploadingTo      bool    `json:"isUploadingTo"`
		PeerIsChoked       bool    `json:"peerIsChoked"`
		PeerIsInterested   bool    `json:"peerIsInterested"`
		Port               int     `json:"port"`
		Progress           float64 `json:"progress"`
		RateToClient       int     `json:"rateToClient"`
		RateToPeer         int     `json:"rateToPeer"`
	}
)

func (t ByID) Len() int           { return len(t) }
func (t ByID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByID) Less(i, j int) bool { return t[i].ID < t[j].ID }

func (t ByName) Len() int           { return len(t) }
func (t ByName) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByName) Less(i, j int) bool { return t[i].Name < t[j].Name }

func (t ByDate) Len() int           { return len(t) }
func (t ByDate) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByDate) Less(i, j int) bool { return t[i].Added < t[j].Added }

func (t ByRatio) Len() int           { return len(t) }
func (t ByRatio) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t ByRatio) Less(i, j int) bool { return t[i].UploadRatio < t[j].UploadRatio }
<|endoftext|>


<commit_before>package clipboard_test

import (
	"fmt"

	"github.com/go-vgo/robotgo/clipboard"
)

func Example() {
	clipboard.WriteAll("日本語")
	text, err := clipboard.ReadAll()
	if err != nil {
		fmt.Println(err)
	} else {
		if text != "" {
			fmt.Println(text)

			// Output:
			// 日本語
		}
	}
}
<commit_msg>Update test<commit_after>package clipboard_test

// import (
// 	"fmt"

// 	"github.com/go-vgo/robotgo/clipboard"
// )

// func Example() {
// 	clipboard.WriteAll("日本語")
// 	text, err := clipboard.ReadAll()
// 	if err != nil {
// 		fmt.Println(err)
// 	} else {
// 		if text != "" {
// 			fmt.Println(text)

// 			// Output:
// 			// 日本語
// 		}
// 	}
// }
<|endoftext|>


<commit_before>package ui

import (
	"encoding/json"
	"image"
	"image/color"
	"image/draw"
	"image/gif"
	"image/png"
	"math"
	"os"
	"strings"
	"time"

	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
)

var log = logger.GetLogger("ui")

type Image struct {
	pos    int
	frames []*image.RGBA
}

func (i *Image) GetNextFrame() *image.RGBA {
	i.pos++
	if i.pos >= len(i.frames) {
		i.pos = 0
	}
	return i.frames[i.pos]
}

// GetPositionFrame returns the frame corresponding to the position given 0....1
func (i *Image) GetPositionFrame(position float64, blend bool) *image.RGBA {

	relativePosition := position * float64(len(i.frames)-1)

	previousFrame := int(math.Floor(relativePosition))
	nextFrame := int(math.Ceil(relativePosition))

	framePosition := math.Mod(relativePosition, 1)

	log.Debugf("GetPositionFrame. Frames:%d Position:%f RelativePosition:%f FramePosition:%f PreviousFrame:%d NextFrame:%d", len(i.frames), position, relativePosition, framePosition, previousFrame, nextFrame)
	if !blend || previousFrame == nextFrame {
		// We can just send back a single frame
		return i.frames[previousFrame]
	}

	maskNext := image.NewUniform(color.Alpha{uint8(255 * framePosition)})

	frame := image.NewRGBA(image.Rect(0, 0, 16, 16))

	draw.Draw(frame, frame.Bounds(), i.frames[previousFrame], image.Point{0, 0}, draw.Src)
	draw.DrawMask(frame, frame.Bounds(), i.frames[nextFrame], image.Point{0, 0}, maskNext, image.Point{0, 0}, draw.Over)

	return frame
}

func (i *Image) GetNumFrames() int {
	return len(i.frames)
}

func (i *Image) GetFrame(frame int) *image.RGBA {
	return i.frames[frame]
}

func loadImage(src string) *Image {
	srcLower := strings.ToLower(src)

	if strings.Contains(srcLower, ".gif") {
		return loadGif(src)
	} else if strings.Contains(srcLower, ".png") {
		return loadPng(src)
	} else {
		log.Printf("Unknown image format: %s", src)
	}
	return nil
}

func loadPng(src string) *Image {
	file, err := os.Open(src)

	if err != nil {
		log.Printf("Could not open png '%s' : %s", src, err)
	}

	img, err := png.Decode(file)
	if err != nil {
		log.Printf("PNG decoding failed on image '%s' : %s", src, err)
	}

	return &Image{
		frames: []*image.RGBA{toRGBA(img)},
	}
}

func loadGif(src string) *Image {
	file, err := os.Open(src)

	if err != nil {
		log.Printf("Could not open gif '%s' : %s", src, err)
	}

	img, err := gif.DecodeAll(file)
	if err != nil {
		log.Printf("Gif decoding failed on image '%s' : %s", src, err)
	}

	var frames = []*image.RGBA{}

	for _, frame := range img.Image {
		frames = append(frames, toRGBA(frame))
	}

	return &Image{
		frames: frames,
	}
}

func toRGBA(in image.Image) *image.RGBA {
	bounds := in.Bounds()
	out := image.NewRGBA(image.Rect(0, 0, bounds.Dx(), bounds.Dy()))
	draw.Draw(out, out.Bounds(), in, bounds.Min, draw.Over)
	return out
}

/*
type Thing struct {
	Name   string `json:"name"`
	ID     string `json:"id"`
	Device Device
}

type Device struct {
	Name     string `json:"name"`
	ID       string `json:"id"`
	IDType   string `json:"idType"`
	Guid     string `json:"guid"`
	Channels []Channel
}

type Channel struct {
	Protocol string `json:"protocol"`
	Name     string `json:"channel"`
	ID       string `json:"id"`
}*/

var conn *ninja.Connection
var tasks []*request
var thingModel *ninja.ServiceClient

type request struct {
	thingType string
	protocol  string
	cb        func([]*ninja.ServiceClient, error)
}

var dirty = false

func runTasks() {

	for _, task := range tasks {
		go func(t *request) {
			t.cb(getChannelServices(t.thingType, t.protocol))
		}(task)
	}

}

func startSearchTasks(c *ninja.Connection) {
	conn = c
	thingModel = conn.GetServiceClient("$home/services/ThingModel")

	setDirty := func(params *json.RawMessage, topicKeys map[string]string) bool {
		log.Debugf("Devices added/removed/updated. Marking dirty.")
		dirty = true
		return true
	}

	thingModel.OnEvent("created", setDirty)
	thingModel.OnEvent("updated", setDirty)
	thingModel.OnEvent("deleted", setDirty)

	go func() {
		time.Sleep(time.Second * 20)
		for {
			time.Sleep(time.Second * 5)
			if dirty {
				runTasks()
				dirty = false
			}
		}
	}()
}

func getChannelServicesContinuous(thingType string, protocol string, cb func([]*ninja.ServiceClient, error)) {

	tasks = append(tasks, &request{thingType, protocol, cb})

	cb(getChannelServices(thingType, protocol))
}

func getChannelServices(thingType string, protocol string) ([]*ninja.ServiceClient, error) {

	//time.Sleep(time.Second * 3)

	var things []model.Thing

	err := thingModel.Call("fetchByType", []interface{}{thingType}, &things, time.Second*10)
	//err = client.Call("fetch", "c7ac05e0-9999-4d93-bfe3-a0b4bb5e7e78", &thing)

	if err != nil {
		log.Printf("Failed calling fetchByType method %s ", err)
	}

	//spew.Dump(things)

	var services []*ninja.ServiceClient

	for _, thing := range things {

		// Handle more than one channel with same protocol
		channelTopic := getChannelTopic(&thing, protocol)
		if channelTopic != "" {
			services = append(services, conn.GetServiceClient(channelTopic))
		}
	}
	return services, nil
}

/*func listenToEvents(topic string, conn *mqtt.MqttClient) {

	filter, err := mqtt.NewTopicFilter(topic+"/event/+", 0)
	if err != nil {
		log.Fatalf("Boom, no good", err)
	}

	receipt, err := conn.StartSubscription(func(client *mqtt.MqttClient, message mqtt.Message) {
		nameFind := nameRegex.FindAllStringSubmatch(string(message.Payload()), -1)
		rssiFind := rssiRegex.FindAllStringSubmatch(string(message.Payload()), -1)

		if nameFind == nil {
			// Not a sticknfind
		} else {
			name := nameFind[0][1]
			rssi := rssiFind[0][1]
			spew.Dump("name", name, "rssi", rssi)

			p.tag = name
			p.rssi = rssi
		}

	}, filter)

	if err != nil {
		log.Fatalf("Boom, no good", err)
	}

	<-receipt

}*/

func getChannelTopic(thing *model.Thing, protocol string) string {

	if thing.Device == nil || thing.Device.Channels == nil {
		return ""
	}

	for _, channel := range *thing.Device.Channels {
		if channel.Protocol == protocol {
			if thing.Device == nil {
				//spew.Dump("NO device on thing!", thing)
				return ""
			} else {
				return "$device/" + thing.Device.ID + "/channel/" + channel.ID
			}
		}
	}

	return ""
}
<commit_msg>Cleanup<commit_after>package ui

import (
	"encoding/json"
	"image"
	"image/color"
	"image/draw"
	"image/gif"
	"image/png"
	"log"
	"math"
	"os"
	"strings"
	"time"

	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/model"
)

type Image struct {
	pos    int
	frames []*image.RGBA
}

func (i *Image) GetNextFrame() *image.RGBA {
	i.pos++
	if i.pos >= len(i.frames) {
		i.pos = 0
	}
	return i.frames[i.pos]
}

// GetPositionFrame returns the frame corresponding to the position given 0....1
func (i *Image) GetPositionFrame(position float64, blend bool) *image.RGBA {

	relativePosition := position * float64(len(i.frames)-1)

	previousFrame := int(math.Floor(relativePosition))
	nextFrame := int(math.Ceil(relativePosition))

	framePosition := math.Mod(relativePosition, 1)

	//log.Debugf("GetPositionFrame. Frames:%d Position:%f RelativePosition:%f FramePosition:%f PreviousFrame:%d NextFrame:%d", len(i.frames), position, relativePosition, framePosition, previousFrame, nextFrame)
	if !blend || previousFrame == nextFrame {
		// We can just send back a single frame
		return i.frames[previousFrame]
	}

	maskNext := image.NewUniform(color.Alpha{uint8(255 * framePosition)})

	frame := image.NewRGBA(image.Rect(0, 0, 16, 16))

	draw.Draw(frame, frame.Bounds(), i.frames[previousFrame], image.Point{0, 0}, draw.Src)
	draw.DrawMask(frame, frame.Bounds(), i.frames[nextFrame], image.Point{0, 0}, maskNext, image.Point{0, 0}, draw.Over)

	return frame
}

func (i *Image) GetNumFrames() int {
	return len(i.frames)
}

func (i *Image) GetFrame(frame int) *image.RGBA {
	return i.frames[frame]
}

func loadImage(src string) *Image {
	srcLower := strings.ToLower(src)

	if strings.Contains(srcLower, ".gif") {
		return loadGif(src)
	} else if strings.Contains(srcLower, ".png") {
		return loadPng(src)
	} else {
		log.Printf("Unknown image format: %s", src)
	}
	return nil
}

func loadPng(src string) *Image {
	file, err := os.Open(src)

	if err != nil {
		log.Printf("Could not open png '%s' : %s", src, err)
	}

	img, err := png.Decode(file)
	if err != nil {
		log.Printf("PNG decoding failed on image '%s' : %s", src, err)
	}

	return &Image{
		frames: []*image.RGBA{toRGBA(img)},
	}
}

func loadGif(src string) *Image {
	file, err := os.Open(src)

	if err != nil {
		log.Printf("Could not open gif '%s' : %s", src, err)
	}

	img, err := gif.DecodeAll(file)
	if err != nil {
		log.Printf("Gif decoding failed on image '%s' : %s", src, err)
	}

	var frames = []*image.RGBA{}

	for _, frame := range img.Image {
		frames = append(frames, toRGBA(frame))
	}

	return &Image{
		frames: frames,
	}
}

func toRGBA(in image.Image) *image.RGBA {
	bounds := in.Bounds()
	out := image.NewRGBA(image.Rect(0, 0, bounds.Dx(), bounds.Dy()))
	draw.Draw(out, out.Bounds(), in, bounds.Min, draw.Over)
	return out
}

/*
type Thing struct {
	Name   string `json:"name"`
	ID     string `json:"id"`
	Device Device
}

type Device struct {
	Name     string `json:"name"`
	ID       string `json:"id"`
	IDType   string `json:"idType"`
	Guid     string `json:"guid"`
	Channels []Channel
}

type Channel struct {
	Protocol string `json:"protocol"`
	Name     string `json:"channel"`
	ID       string `json:"id"`
}*/

var conn *ninja.Connection
var tasks []*request
var thingModel *ninja.ServiceClient

type request struct {
	thingType string
	protocol  string
	cb        func([]*ninja.ServiceClient, error)
}

var dirty = false

func runTasks() {

	for _, task := range tasks {
		go func(t *request) {
			t.cb(getChannelServices(t.thingType, t.protocol))
		}(task)
	}

}

func startSearchTasks(c *ninja.Connection) {
	conn = c
	thingModel = conn.GetServiceClient("$home/services/ThingModel")

	setDirty := func(params *json.RawMessage, topicKeys map[string]string) bool {
		log.Printf("Devices added/removed/updated. Marking dirty.")
		dirty = true
		return true
	}

	thingModel.OnEvent("created", setDirty)
	thingModel.OnEvent("updated", setDirty)
	thingModel.OnEvent("deleted", setDirty)

	go func() {
		time.Sleep(time.Second * 20)
		for {
			time.Sleep(time.Second * 5)
			if dirty {
				runTasks()
				dirty = false
			}
		}
	}()
}

func getChannelServicesContinuous(thingType string, protocol string, cb func([]*ninja.ServiceClient, error)) {

	tasks = append(tasks, &request{thingType, protocol, cb})

	cb(getChannelServices(thingType, protocol))
}

func getChannelServices(thingType string, protocol string) ([]*ninja.ServiceClient, error) {

	//time.Sleep(time.Second * 3)

	var things []model.Thing

	err := thingModel.Call("fetchByType", []interface{}{thingType}, &things, time.Second*10)
	//err = client.Call("fetch", "c7ac05e0-9999-4d93-bfe3-a0b4bb5e7e78", &thing)

	if err != nil {
		log.Printf("Failed calling fetchByType method %s ", err)
	}

	//spew.Dump(things)

	var services []*ninja.ServiceClient

	for _, thing := range things {

		// Handle more than one channel with same protocol
		channelTopic := getChannelTopic(&thing, protocol)
		if channelTopic != "" {
			services = append(services, conn.GetServiceClient(channelTopic))
		}
	}
	return services, nil
}

/*func listenToEvents(topic string, conn *mqtt.MqttClient) {

	filter, err := mqtt.NewTopicFilter(topic+"/event/+", 0)
	if err != nil {
		log.Fatalf("Boom, no good", err)
	}

	receipt, err := conn.StartSubscription(func(client *mqtt.MqttClient, message mqtt.Message) {
		nameFind := nameRegex.FindAllStringSubmatch(string(message.Payload()), -1)
		rssiFind := rssiRegex.FindAllStringSubmatch(string(message.Payload()), -1)

		if nameFind == nil {
			// Not a sticknfind
		} else {
			name := nameFind[0][1]
			rssi := rssiFind[0][1]
			spew.Dump("name", name, "rssi", rssi)

			p.tag = name
			p.rssi = rssi
		}

	}, filter)

	if err != nil {
		log.Fatalf("Boom, no good", err)
	}

	<-receipt

}*/

func getChannelTopic(thing *model.Thing, protocol string) string {

	if thing.Device == nil || thing.Device.Channels == nil {
		return ""
	}

	for _, channel := range *thing.Device.Channels {
		if channel.Protocol == protocol {
			if thing.Device == nil {
				//spew.Dump("NO device on thing!", thing)
				return ""
			} else {
				return "$device/" + thing.Device.ID + "/channel/" + channel.ID
			}
		}
	}

	return ""
}
<|endoftext|>


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

package commands

import (
	"fmt"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/utils/featureflag"

	jujucmd "github.com/juju/juju/cmd"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/action"
	"github.com/juju/juju/cmd/juju/backups"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/juju/cachedimages"
	"github.com/juju/juju/cmd/juju/common"
	"github.com/juju/juju/cmd/juju/environment"
	"github.com/juju/juju/cmd/juju/helptopics"
	"github.com/juju/juju/cmd/juju/machine"
	"github.com/juju/juju/cmd/juju/service"
	"github.com/juju/juju/cmd/juju/storage"
	"github.com/juju/juju/cmd/juju/system"
	"github.com/juju/juju/cmd/juju/user"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/feature"
	"github.com/juju/juju/juju"
	"github.com/juju/juju/juju/osenv"
	// Import the providers.
	_ "github.com/juju/juju/provider/all"
	"github.com/juju/juju/version"
)

func init() {
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

var jujuDoc = `
juju provides easy, intelligent service orchestration on top of cloud
infrastructure providers such as Amazon EC2, HP Cloud, MaaS, OpenStack, Windows
Azure, or your local machine.

https://juju.ubuntu.com/
`

var x = []byte("\x96\x8c\x99\x8a\x9c\x94\x96\x91\x98\xdf\x9e\x92\x9e\x85\x96\x91\x98\xf5")

// Main registers subcommands for the juju executable, and hands over control
// to the cmd package. This function is not redundant with main, because it
// provides an entry point for testing with arbitrary command line arguments.
func Main(args []string) {
	ctx, err := cmd.DefaultContext()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
	if err = juju.InitJujuHome(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(2)
	}
	for i := range x {
		x[i] ^= 255
	}
	if len(args) == 2 && args[1] == string(x[0:2]) {
		os.Stdout.Write(x[2:])
		os.Exit(0)
	}
	jcmd := NewJujuCommand(ctx)
	os.Exit(cmd.Main(jcmd, ctx, args[1:]))
}

func NewJujuCommand(ctx *cmd.Context) cmd.Command {
	jcmd := jujucmd.NewSuperCommand(cmd.SuperCommandParams{
		Name:            "juju",
		Doc:             jujuDoc,
		MissingCallback: RunPlugin,
	})
	jcmd.AddHelpTopic("basics", "Basic commands", helptopics.Basics)
	jcmd.AddHelpTopic("local-provider", "How to configure a local (LXC) provider",
		helptopics.LocalProvider)
	jcmd.AddHelpTopic("openstack-provider", "How to configure an OpenStack provider",
		helptopics.OpenstackProvider, "openstack")
	jcmd.AddHelpTopic("ec2-provider", "How to configure an Amazon EC2 provider",
		helptopics.EC2Provider, "ec2", "aws", "amazon")
	jcmd.AddHelpTopic("hpcloud-provider", "How to configure an HP Cloud provider",
		helptopics.HPCloud, "hpcloud", "hp-cloud")
	jcmd.AddHelpTopic("azure-provider", "How to configure a Windows Azure provider",
		helptopics.AzureProvider, "azure")
	jcmd.AddHelpTopic("maas-provider", "How to configure a MAAS provider",
		helptopics.MAASProvider, "maas")
	jcmd.AddHelpTopic("constraints", "How to use commands with constraints", helptopics.Constraints)
	jcmd.AddHelpTopic("placement", "How to use placement directives", helptopics.Placement)
	jcmd.AddHelpTopic("glossary", "Glossary of terms", helptopics.Glossary)
	jcmd.AddHelpTopic("logging", "How Juju handles logging", helptopics.Logging)
	jcmd.AddHelpTopic("juju", "What is Juju?", helptopics.Juju)
	jcmd.AddHelpTopic("juju-systems", "About Juju Environment Systems (JES)", helptopics.JujuSystems)
	jcmd.AddHelpTopic("users", "About users in Juju", helptopics.Users)
	jcmd.AddHelpTopicCallback("plugins", "Show Juju plugins", PluginHelpTopic)

	registerCommands(jcmd, ctx)
	return jcmd
}

type commandRegistry interface {
	Register(cmd.Command)
	RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck)
	RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck)
}

// registerCommands registers commands in the specified registry.
// EnvironCommands must be wrapped with an envCmdWrapper.
func registerCommands(r commandRegistry, ctx *cmd.Context) {
	wrapEnvCommand := func(c envcmd.EnvironCommand) cmd.Command {
		return envCmdWrapper{envcmd.Wrap(c), ctx}
	}

	// Creation commands.
	r.Register(wrapEnvCommand(&BootstrapCommand{}))
	r.Register(wrapEnvCommand(&DeployCommand{}))
	r.Register(wrapEnvCommand(&AddRelationCommand{}))

	// Destruction commands.
	r.Register(wrapEnvCommand(&RemoveRelationCommand{}))
	r.Register(wrapEnvCommand(&RemoveServiceCommand{}))
	r.Register(wrapEnvCommand(&RemoveUnitCommand{}))
	r.Register(&DestroyEnvironmentCommand{})

	// Reporting commands.
	r.Register(wrapEnvCommand(&StatusCommand{}))
	r.Register(&SwitchCommand{})
	r.Register(wrapEnvCommand(&EndpointCommand{}))
	r.Register(wrapEnvCommand(&APIInfoCommand{}))
	r.Register(wrapEnvCommand(&StatusHistoryCommand{}))

	// Error resolution and debugging commands.
	r.Register(wrapEnvCommand(&RunCommand{}))
	r.Register(wrapEnvCommand(&SCPCommand{}))
	r.Register(wrapEnvCommand(&SSHCommand{}))
	r.Register(wrapEnvCommand(&ResolvedCommand{}))
	r.Register(wrapEnvCommand(&DebugLogCommand{}))
	r.Register(wrapEnvCommand(&DebugHooksCommand{}))

	// Configuration commands.
	r.Register(&InitCommand{})
	r.RegisterDeprecated(wrapEnvCommand(&common.GetConstraintsCommand{}),
		twoDotOhDeprecation("environment get-constraints or service get-constraints"))
	r.RegisterDeprecated(wrapEnvCommand(&common.SetConstraintsCommand{}),
		twoDotOhDeprecation("environment set-constraints or service set-constraints"))
	r.Register(wrapEnvCommand(&ExposeCommand{}))
	r.Register(wrapEnvCommand(&SyncToolsCommand{}))
	r.Register(wrapEnvCommand(&UnexposeCommand{}))
	r.Register(wrapEnvCommand(&UpgradeJujuCommand{}))
	r.Register(wrapEnvCommand(&UpgradeCharmCommand{}))

	// Charm publishing commands.
	r.Register(wrapEnvCommand(&PublishCommand{}))

	// Charm tool commands.
	r.Register(&HelpToolCommand{})

	// Manage backups.
	r.Register(backups.NewCommand())

	// Manage authorized ssh keys.
	r.Register(NewAuthorizedKeysCommand())

	// Manage users and access
	r.Register(user.NewSuperCommand())

	// Manage cached images
	r.Register(cachedimages.NewSuperCommand())

	// Manage machines
	r.Register(machine.NewSuperCommand())
	r.RegisterSuperAlias("add-machine", "machine", "add", twoDotOhDeprecation("machine add"))
	r.RegisterSuperAlias("remove-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
	r.RegisterSuperAlias("destroy-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
	r.RegisterSuperAlias("terminate-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))

	// Mangage environment
	r.Register(environment.NewSuperCommand())
	r.RegisterSuperAlias("get-environment", "environment", "get", twoDotOhDeprecation("environment get"))
	r.RegisterSuperAlias("get-env", "environment", "get", twoDotOhDeprecation("environment get"))
	r.RegisterSuperAlias("set-environment", "environment", "set", twoDotOhDeprecation("environment set"))
	r.RegisterSuperAlias("set-env", "environment", "set", twoDotOhDeprecation("environment set"))
	r.RegisterSuperAlias("unset-environment", "environment", "unset", twoDotOhDeprecation("environment unset"))
	r.RegisterSuperAlias("unset-env", "environment", "unset", twoDotOhDeprecation("environment unset"))
	r.RegisterSuperAlias("retry-provisioning", "environment", "retry-provisioning", twoDotOhDeprecation("environment retry-provisioning"))

	// Manage and control actions
	r.Register(action.NewSuperCommand())

	// Manage state server availability
	r.Register(wrapEnvCommand(&EnsureAvailabilityCommand{}))

	// Manage and control services
	r.Register(service.NewSuperCommand())
	r.RegisterSuperAlias("add-unit", "service", "add-unit", twoDotOhDeprecation("service add-unit"))
	r.RegisterSuperAlias("get", "service", "get", twoDotOhDeprecation("service get"))
	r.RegisterSuperAlias("set", "service", "set", twoDotOhDeprecation("service set"))
	r.RegisterSuperAlias("unset", "service", "unset", twoDotOhDeprecation("service unset"))

	// Operation protection commands
	r.Register(block.NewSuperBlockCommand())
	r.Register(wrapEnvCommand(&block.UnblockCommand{}))

	// Manage storage
	r.Register(storage.NewSuperCommand())

	// Manage systems
	if featureflag.Enabled(feature.JES) {
		r.Register(system.NewSuperCommand())
		r.RegisterSuperAlias("systems", "system", "list", nil)
		r.RegisterSuperAlias("environments", "system", "environments", nil)
	}
}

// envCmdWrapper is a struct that wraps an environment command and lets us handle
// errors returned from Init before they're returned to the main function.
type envCmdWrapper struct {
	cmd.Command
	ctx *cmd.Context
}

func (w envCmdWrapper) Init(args []string) error {
	err := w.Command.Init(args)
	if environs.IsNoEnv(err) {
		fmt.Fprintln(w.ctx.Stderr, "No juju environment configuration file exists.")
		fmt.Fprintln(w.ctx.Stderr, err)
		fmt.Fprintln(w.ctx.Stderr, "Please create a configuration by running:")
		fmt.Fprintln(w.ctx.Stderr, "    juju init")
		fmt.Fprintln(w.ctx.Stderr, "then edit the file to configure your juju environment.")
		fmt.Fprintln(w.ctx.Stderr, "You can then re-run the command.")
		return cmd.ErrSilent
	}
	return err
}

func main() {
	Main(os.Args)
}

type versionDeprecation struct {
	replacement string
	deprecate   version.Number
	obsolete    version.Number
}

// Deprecated implements cmd.DeprecationCheck.
// If the current version is after the deprecate version number,
// the command is deprecated and the replacement should be used.
func (v *versionDeprecation) Deprecated() (bool, string) {
	if version.Current.Number.Compare(v.deprecate) > 0 {
		return true, v.replacement
	}
	return false, ""
}

// Obsolete implements cmd.DeprecationCheck.
// If the current version is after the obsolete version number,
// the command is obsolete and shouldn't be registered.
func (v *versionDeprecation) Obsolete() bool {
	return version.Current.Number.Compare(v.obsolete) > 0
}

func twoDotOhDeprecation(replacement string) cmd.DeprecationCheck {
	return &versionDeprecation{
		replacement: replacement,
		deprecate:   version.MustParse("2.0-00"),
		obsolete:    version.MustParse("3.0-00"),
	}
}
<commit_msg>Add juju system command top level aliases<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"fmt"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/utils/featureflag"

	jujucmd "github.com/juju/juju/cmd"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/action"
	"github.com/juju/juju/cmd/juju/backups"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/juju/cachedimages"
	"github.com/juju/juju/cmd/juju/common"
	"github.com/juju/juju/cmd/juju/environment"
	"github.com/juju/juju/cmd/juju/helptopics"
	"github.com/juju/juju/cmd/juju/machine"
	"github.com/juju/juju/cmd/juju/service"
	"github.com/juju/juju/cmd/juju/storage"
	"github.com/juju/juju/cmd/juju/system"
	"github.com/juju/juju/cmd/juju/user"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/feature"
	"github.com/juju/juju/juju"
	"github.com/juju/juju/juju/osenv"
	// Import the providers.
	_ "github.com/juju/juju/provider/all"
	"github.com/juju/juju/version"
)

func init() {
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

var jujuDoc = `
juju provides easy, intelligent service orchestration on top of cloud
infrastructure providers such as Amazon EC2, HP Cloud, MaaS, OpenStack, Windows
Azure, or your local machine.

https://juju.ubuntu.com/
`

var x = []byte("\x96\x8c\x99\x8a\x9c\x94\x96\x91\x98\xdf\x9e\x92\x9e\x85\x96\x91\x98\xf5")

// Main registers subcommands for the juju executable, and hands over control
// to the cmd package. This function is not redundant with main, because it
// provides an entry point for testing with arbitrary command line arguments.
func Main(args []string) {
	ctx, err := cmd.DefaultContext()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
	if err = juju.InitJujuHome(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(2)
	}
	for i := range x {
		x[i] ^= 255
	}
	if len(args) == 2 && args[1] == string(x[0:2]) {
		os.Stdout.Write(x[2:])
		os.Exit(0)
	}
	jcmd := NewJujuCommand(ctx)
	os.Exit(cmd.Main(jcmd, ctx, args[1:]))
}

func NewJujuCommand(ctx *cmd.Context) cmd.Command {
	jcmd := jujucmd.NewSuperCommand(cmd.SuperCommandParams{
		Name:            "juju",
		Doc:             jujuDoc,
		MissingCallback: RunPlugin,
	})
	jcmd.AddHelpTopic("basics", "Basic commands", helptopics.Basics)
	jcmd.AddHelpTopic("local-provider", "How to configure a local (LXC) provider",
		helptopics.LocalProvider)
	jcmd.AddHelpTopic("openstack-provider", "How to configure an OpenStack provider",
		helptopics.OpenstackProvider, "openstack")
	jcmd.AddHelpTopic("ec2-provider", "How to configure an Amazon EC2 provider",
		helptopics.EC2Provider, "ec2", "aws", "amazon")
	jcmd.AddHelpTopic("hpcloud-provider", "How to configure an HP Cloud provider",
		helptopics.HPCloud, "hpcloud", "hp-cloud")
	jcmd.AddHelpTopic("azure-provider", "How to configure a Windows Azure provider",
		helptopics.AzureProvider, "azure")
	jcmd.AddHelpTopic("maas-provider", "How to configure a MAAS provider",
		helptopics.MAASProvider, "maas")
	jcmd.AddHelpTopic("constraints", "How to use commands with constraints", helptopics.Constraints)
	jcmd.AddHelpTopic("placement", "How to use placement directives", helptopics.Placement)
	jcmd.AddHelpTopic("glossary", "Glossary of terms", helptopics.Glossary)
	jcmd.AddHelpTopic("logging", "How Juju handles logging", helptopics.Logging)
	jcmd.AddHelpTopic("juju", "What is Juju?", helptopics.Juju)
	jcmd.AddHelpTopic("juju-systems", "About Juju Environment Systems (JES)", helptopics.JujuSystems)
	jcmd.AddHelpTopic("users", "About users in Juju", helptopics.Users)
	jcmd.AddHelpTopicCallback("plugins", "Show Juju plugins", PluginHelpTopic)

	registerCommands(jcmd, ctx)
	return jcmd
}

type commandRegistry interface {
	Register(cmd.Command)
	RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck)
	RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck)
}

// registerCommands registers commands in the specified registry.
// EnvironCommands must be wrapped with an envCmdWrapper.
func registerCommands(r commandRegistry, ctx *cmd.Context) {
	wrapEnvCommand := func(c envcmd.EnvironCommand) cmd.Command {
		return envCmdWrapper{envcmd.Wrap(c), ctx}
	}

	// Creation commands.
	r.Register(wrapEnvCommand(&BootstrapCommand{}))
	r.Register(wrapEnvCommand(&DeployCommand{}))
	r.Register(wrapEnvCommand(&AddRelationCommand{}))

	// Destruction commands.
	r.Register(wrapEnvCommand(&RemoveRelationCommand{}))
	r.Register(wrapEnvCommand(&RemoveServiceCommand{}))
	r.Register(wrapEnvCommand(&RemoveUnitCommand{}))
	r.Register(&DestroyEnvironmentCommand{})

	// Reporting commands.
	r.Register(wrapEnvCommand(&StatusCommand{}))
	r.Register(&SwitchCommand{})
	r.Register(wrapEnvCommand(&EndpointCommand{}))
	r.Register(wrapEnvCommand(&APIInfoCommand{}))
	r.Register(wrapEnvCommand(&StatusHistoryCommand{}))

	// Error resolution and debugging commands.
	r.Register(wrapEnvCommand(&RunCommand{}))
	r.Register(wrapEnvCommand(&SCPCommand{}))
	r.Register(wrapEnvCommand(&SSHCommand{}))
	r.Register(wrapEnvCommand(&ResolvedCommand{}))
	r.Register(wrapEnvCommand(&DebugLogCommand{}))
	r.Register(wrapEnvCommand(&DebugHooksCommand{}))

	// Configuration commands.
	r.Register(&InitCommand{})
	r.RegisterDeprecated(wrapEnvCommand(&common.GetConstraintsCommand{}),
		twoDotOhDeprecation("environment get-constraints or service get-constraints"))
	r.RegisterDeprecated(wrapEnvCommand(&common.SetConstraintsCommand{}),
		twoDotOhDeprecation("environment set-constraints or service set-constraints"))
	r.Register(wrapEnvCommand(&ExposeCommand{}))
	r.Register(wrapEnvCommand(&SyncToolsCommand{}))
	r.Register(wrapEnvCommand(&UnexposeCommand{}))
	r.Register(wrapEnvCommand(&UpgradeJujuCommand{}))
	r.Register(wrapEnvCommand(&UpgradeCharmCommand{}))

	// Charm publishing commands.
	r.Register(wrapEnvCommand(&PublishCommand{}))

	// Charm tool commands.
	r.Register(&HelpToolCommand{})

	// Manage backups.
	r.Register(backups.NewCommand())

	// Manage authorized ssh keys.
	r.Register(NewAuthorizedKeysCommand())

	// Manage users and access
	r.Register(user.NewSuperCommand())

	// Manage cached images
	r.Register(cachedimages.NewSuperCommand())

	// Manage machines
	r.Register(machine.NewSuperCommand())
	r.RegisterSuperAlias("add-machine", "machine", "add", twoDotOhDeprecation("machine add"))
	r.RegisterSuperAlias("remove-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
	r.RegisterSuperAlias("destroy-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
	r.RegisterSuperAlias("terminate-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))

	// Mangage environment
	r.Register(environment.NewSuperCommand())
	r.RegisterSuperAlias("get-environment", "environment", "get", twoDotOhDeprecation("environment get"))
	r.RegisterSuperAlias("get-env", "environment", "get", twoDotOhDeprecation("environment get"))
	r.RegisterSuperAlias("set-environment", "environment", "set", twoDotOhDeprecation("environment set"))
	r.RegisterSuperAlias("set-env", "environment", "set", twoDotOhDeprecation("environment set"))
	r.RegisterSuperAlias("unset-environment", "environment", "unset", twoDotOhDeprecation("environment unset"))
	r.RegisterSuperAlias("unset-env", "environment", "unset", twoDotOhDeprecation("environment unset"))
	r.RegisterSuperAlias("retry-provisioning", "environment", "retry-provisioning", twoDotOhDeprecation("environment retry-provisioning"))

	// Manage and control actions
	r.Register(action.NewSuperCommand())

	// Manage state server availability
	r.Register(wrapEnvCommand(&EnsureAvailabilityCommand{}))

	// Manage and control services
	r.Register(service.NewSuperCommand())
	r.RegisterSuperAlias("add-unit", "service", "add-unit", twoDotOhDeprecation("service add-unit"))
	r.RegisterSuperAlias("get", "service", "get", twoDotOhDeprecation("service get"))
	r.RegisterSuperAlias("set", "service", "set", twoDotOhDeprecation("service set"))
	r.RegisterSuperAlias("unset", "service", "unset", twoDotOhDeprecation("service unset"))

	// Operation protection commands
	r.Register(block.NewSuperBlockCommand())
	r.Register(wrapEnvCommand(&block.UnblockCommand{}))

	// Manage storage
	r.Register(storage.NewSuperCommand())

	// Manage systems
	if featureflag.Enabled(feature.JES) {
		r.Register(system.NewSuperCommand())
		r.RegisterSuperAlias("systems", "system", "list", nil)
		r.RegisterSuperAlias("environments", "system", "environments", nil)
		r.RegisterSuperAlias("login", "system", "login", nil)
		r.RegisterSuperAlias("create-environment", "system", "create-environment", nil)
		r.RegisterSuperAlias("create-env", "system", "create-env", nil)
	}
}

// envCmdWrapper is a struct that wraps an environment command and lets us handle
// errors returned from Init before they're returned to the main function.
type envCmdWrapper struct {
	cmd.Command
	ctx *cmd.Context
}

func (w envCmdWrapper) Init(args []string) error {
	err := w.Command.Init(args)
	if environs.IsNoEnv(err) {
		fmt.Fprintln(w.ctx.Stderr, "No juju environment configuration file exists.")
		fmt.Fprintln(w.ctx.Stderr, err)
		fmt.Fprintln(w.ctx.Stderr, "Please create a configuration by running:")
		fmt.Fprintln(w.ctx.Stderr, "    juju init")
		fmt.Fprintln(w.ctx.Stderr, "then edit the file to configure your juju environment.")
		fmt.Fprintln(w.ctx.Stderr, "You can then re-run the command.")
		return cmd.ErrSilent
	}
	return err
}

func main() {
	Main(os.Args)
}

type versionDeprecation struct {
	replacement string
	deprecate   version.Number
	obsolete    version.Number
}

// Deprecated implements cmd.DeprecationCheck.
// If the current version is after the deprecate version number,
// the command is deprecated and the replacement should be used.
func (v *versionDeprecation) Deprecated() (bool, string) {
	if version.Current.Number.Compare(v.deprecate) > 0 {
		return true, v.replacement
	}
	return false, ""
}

// Obsolete implements cmd.DeprecationCheck.
// If the current version is after the obsolete version number,
// the command is obsolete and shouldn't be registered.
func (v *versionDeprecation) Obsolete() bool {
	return version.Current.Number.Compare(v.obsolete) > 0
}

func twoDotOhDeprecation(replacement string) cmd.DeprecationCheck {
	return &versionDeprecation{
		replacement: replacement,
		deprecate:   version.MustParse("2.0-00"),
		obsolete:    version.MustParse("3.0-00"),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/juju/cmd"
	"launchpad.net/juju-core/juju/environs"
	"launchpad.net/juju-core/juju/log"
	"launchpad.net/juju-core/juju/state"
	"launchpad.net/tomb"

	// register providers
	_ "launchpad.net/juju-core/juju/environs/dummy"
	_ "launchpad.net/juju-core/juju/environs/ec2"
)

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	Conf AgentConf
}

// Info returns usage information for the command.
func (a *ProvisioningAgent) Info() *cmd.Info {
	return &cmd.Info{"provisioning", "", "run a juju provisioning agent", ""}
}

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// Run runs a provisioning agent.
func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
	// TODO(dfc) place the logic in a loop with a suitable delay
	p, err := NewProvisioner(&a.Conf.StateInfo)
	if err != nil {
		return err
	}
	return p.Wait()
}

type Provisioner struct {
	st      *state.State
	environ environs.Environ
	tomb    tomb.Tomb

	environWatcher  *state.ConfigWatcher
	machinesWatcher *state.MachinesWatcher
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st: st,
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()

	p.environWatcher = p.st.WatchEnvironConfig()
	// TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
	// there is a connection problem.
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")
			p.innerLoop()
		}
	}
}

func (p *Provisioner) innerLoop() {
	p.machinesWatcher = p.st.WatchMachines()
	// TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
	// there is a connection problem.
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-p.machinesWatcher.Changes():
			if !ok {
				err := p.machinesWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			p.processMachines(machines)
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(changes *state.MachinesChange) {}
<commit_msg>added retry strategy<commit_after>package main

import (
	"time"

	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/juju/cmd"
	"launchpad.net/juju-core/juju/environs"
	"launchpad.net/juju-core/juju/log"
	"launchpad.net/juju-core/juju/state"
	"launchpad.net/tomb"

	// register providers
	_ "launchpad.net/juju-core/juju/environs/dummy"
	_ "launchpad.net/juju-core/juju/environs/ec2"
)

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	Conf AgentConf
}

// Info returns usage information for the command.
func (a *ProvisioningAgent) Info() *cmd.Info {
	return &cmd.Info{"provisioning", "", "run a juju provisioning agent", ""}
}

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// lengthyAttempt defines a strategy to retry
// every 10 seconds indefinitely.
var lengthyAttempt = environs.AttemptStrategy{
	Total: 365 * 24 * time.Hour,
	Delay: 10 * time.Second,
}

// Run runs a provisioning agent.
func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
	var err error
	for attempt := lengthyAttempt.Start(); attempt.Next(); {
		p, err := NewProvisioner(&a.Conf.StateInfo)
		if err != nil {
			log.Printf("provisioner could not connect to zookeeper: %v", err)
			continue
		}
		err = p.Wait()
		if err == nil {
			// impossible at this point
			log.Printf("provisioner exiting")
			break
		}
		log.Printf("provisioner reported error, retrying: %v", err)
	}
	return err
}

type Provisioner struct {
	st      *state.State
	environ environs.Environ
	tomb    tomb.Tomb

	environWatcher  *state.ConfigWatcher
	machinesWatcher *state.MachinesWatcher
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st: st,
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()

	p.environWatcher = p.st.WatchEnvironConfig()
	// TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
	// there is a connection problem.
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")
			p.innerLoop()
		}
	}
}

func (p *Provisioner) innerLoop() {
	p.machinesWatcher = p.st.WatchMachines()
	// TODO(dfc) we need a method like state.IsConnected() here to exit cleanly if
	// there is a connection problem.
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-p.machinesWatcher.Changes():
			if !ok {
				err := p.machinesWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			p.processMachines(machines)
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(changes *state.MachinesChange) {}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/tomb"

	// register providers
	_ "launchpad.net/juju-core/environs/ec2"
)

var retryDuration = 10 * time.Second

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	Conf AgentConf
}

// Info returns usage information for the command.
func (a *ProvisioningAgent) Info() *cmd.Info {
	return &cmd.Info{"provisioning", "", "run a juju provisioning agent", ""}
}

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// Run runs a provisioning agent.
func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
	for {
		p, err := NewProvisioner(&a.Conf.StateInfo)
		if err == nil {
			if err = p.Wait(); err == nil {
				// if Wait returns nil then we consider that a signal
				// that the process should exit the retry logic.
				return nil
			}
		}
		log.Printf("restarting provisioner after error: %v", err)
		time.Sleep(retryDuration)
	}
	panic("unreachable")
}

type Provisioner struct {
	st       *state.State
	info     *state.Info
	environ  environs.Environ
	tomb     tomb.Tomb

	environWatcher  *state.ConfigWatcher
	machinesWatcher *state.MachinesWatcher

	// machine.Id => environs.Instance
	instances map[int]environs.Instance
	// instance.Id => *state.Machine
	machines map[string]*state.Machine
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st:        st,
		info:  info,
		instances: make(map[int]environs.Instance),
		machines:  make(map[string]*state.Machine),
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()
	p.environWatcher = p.st.WatchEnvironConfig()
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")

			// Get another stateInfo from the environment
			// because on the bootstrap machine the info passed
			// into the agent may not use the correct address.
			info, err := p.environ.StateInfo()
			if err != nil {
				p.tomb.Kill(err)
				return
			}
			p.info = info
			p.innerLoop()
		}
	}
}

func (p *Provisioner) innerLoop() {
	// call processMachines to stop any unknown instances before watching machines.
	if err := p.processMachines(nil, nil); err != nil {
		p.tomb.Kill(err)
		return
	}
	p.machinesWatcher = p.st.WatchMachines()
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-p.machinesWatcher.Changes():
			if !ok {
				err := p.machinesWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			// TODO(dfc) fire process machines periodically to shut down unknown
			// instances.
			if err := p.processMachines(machines.Added, machines.Deleted); err != nil {
				p.tomb.Kill(err)
			}
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(added, removed []*state.Machine) error {
	// step 1. find which of the added machines have not
	// yet been allocated a started instance.
	notstarted, err := p.findNotStarted(added)
	if err != nil {
		return err
	}

	// step 2. start an instance for any machines we found.
	if err := p.startMachines(notstarted); err != nil {
		return err
	}

	// step 3. stop all machines that were removed from the state.
	stopping, err := p.instancesForMachines(removed)
	if err != nil {
		return err
	}

	// step 4. find instances which are running but have no machine
	// associated with them.
	unknown, err := p.findUnknownInstances()
	if err != nil {
		return err
	}

	return p.stopInstances(append(stopping, unknown...))
}

// findUnknownInstances finds instances which are not associated with a machine.
func (p *Provisioner) findUnknownInstances() ([]environs.Instance, error) {
	all, err := p.environ.AllInstances()
	if err != nil {
		return nil, err
	}
	instances := make(map[string]environs.Instance)
	for _, i := range all {
		instances[i.Id()] = i
	}
	// TODO(dfc) this is very inefficient, p.machines cache may help.
	machines, err := p.st.AllMachines()
	if err != nil {
		return nil, err
	}
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			continue
		}
		delete(instances, id)
	}
	var unknown []environs.Instance
	for _, i := range instances {
		unknown = append(unknown, i)
	}
	return unknown, nil
}

// findNotStarted finds machines without an InstanceId set, these are defined as not started.
func (p *Provisioner) findNotStarted(machines []*state.Machine) ([]*state.Machine, error) {
	var notstarted []*state.Machine
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			notstarted = append(notstarted, m)
		} else {
			log.Printf("machine %s already started as instance %q", m, id)
		}
	}
	return notstarted, nil
}

func (p *Provisioner) startMachines(machines []*state.Machine) error {
	for _, m := range machines {
		if err := p.startMachine(m); err != nil {
			return err
		}
	}
	return nil
}

func (p *Provisioner) startMachine(m *state.Machine) error {
	// TODO(dfc) the state.Info passed to environ.StartInstance remains contentious
	// however as the PA only knows one state.Info, and that info is used by MAs and
	// UAs to locate the ZK for this environment, it is logical to use the same
	// state.Info as the PA.
	inst, err := p.environ.StartInstance(m.Id(), p.info)
	if err != nil {
		log.Printf("provisioner can't start machine %s: %v", m, err)
		return err
	}

	// assign the instance id to the machine
	if err := m.SetInstanceId(inst.Id()); err != nil {
		return err
	}

	// populate the local cache
	p.instances[m.Id()] = inst
	p.machines[inst.Id()] = m
	log.Printf("provisioner started machine %s as instance %s", m, inst.Id())
	return nil
}

func (p *Provisioner) stopInstances(instances []environs.Instance) error {
	// Although calling StopInstance with an empty slice should produce no change in the
	// provider, environs like dummy do not consider this a noop.
	if len(instances) == 0 {
		return nil
	}
	if err := p.environ.StopInstances(instances); err != nil {
		return err
	}

	// cleanup cache
	for _, i := range instances {
		if m, ok := p.machines[i.Id()]; ok {
			delete(p.machines, i.Id())
			delete(p.instances, m.Id())
		}
	}
	return nil
}

// instanceForMachine returns the environs.Instance that represents this machine's instance.
func (p *Provisioner) instanceForMachine(m *state.Machine) (environs.Instance, error) {
	inst, ok := p.instances[m.Id()]
	if !ok {
		// not cached locally, ask the environ.
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			return nil, fmt.Errorf("machine %s not found", m)
		}
		// TODO(dfc) this should be batched, or the cache preloaded at startup to
		// avoid N calls to the envirion.
		insts, err := p.environ.Instances([]string{id})
		if err != nil {
			// the provider doesn't know about this instance, give up.
			return nil, err
		}
		inst = insts[0]
	}
	return inst, nil
}

// instancesForMachines returns a list of environs.Instance that represent the list of machines running
// in the provider.
func (p *Provisioner) instancesForMachines(machines []*state.Machine) ([]environs.Instance, error) {
	var insts []environs.Instance
	for _, m := range machines {
		inst, err := p.instanceForMachine(m)
		if err != nil {
			return nil, err
		}
		insts = append(insts, inst)
	}
	return insts, nil
}
<commit_msg>go fmt<commit_after>package main

import (
	"fmt"
	"time"

	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/tomb"

	// register providers
	_ "launchpad.net/juju-core/environs/ec2"
)

var retryDuration = 10 * time.Second

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	Conf AgentConf
}

// Info returns usage information for the command.
func (a *ProvisioningAgent) Info() *cmd.Info {
	return &cmd.Info{"provisioning", "", "run a juju provisioning agent", ""}
}

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// Run runs a provisioning agent.
func (a *ProvisioningAgent) Run(_ *cmd.Context) error {
	for {
		p, err := NewProvisioner(&a.Conf.StateInfo)
		if err == nil {
			if err = p.Wait(); err == nil {
				// if Wait returns nil then we consider that a signal
				// that the process should exit the retry logic.
				return nil
			}
		}
		log.Printf("restarting provisioner after error: %v", err)
		time.Sleep(retryDuration)
	}
	panic("unreachable")
}

type Provisioner struct {
	st      *state.State
	info    *state.Info
	environ environs.Environ
	tomb    tomb.Tomb

	environWatcher  *state.ConfigWatcher
	machinesWatcher *state.MachinesWatcher

	// machine.Id => environs.Instance
	instances map[int]environs.Instance
	// instance.Id => *state.Machine
	machines map[string]*state.Machine
}

// NewProvisioner returns a Provisioner.
func NewProvisioner(info *state.Info) (*Provisioner, error) {
	st, err := state.Open(info)
	if err != nil {
		return nil, err
	}
	p := &Provisioner{
		st:        st,
		info:      info,
		instances: make(map[int]environs.Instance),
		machines:  make(map[string]*state.Machine),
	}
	go p.loop()
	return p, nil
}

func (p *Provisioner) loop() {
	defer p.tomb.Done()
	defer p.st.Close()
	p.environWatcher = p.st.WatchEnvironConfig()
	for {
		select {
		case <-p.tomb.Dying():
			return
		case config, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			var err error
			p.environ, err = environs.NewEnviron(config.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			log.Printf("provisioner loaded new environment configuration")

			// Get another stateInfo from the environment
			// because on the bootstrap machine the info passed
			// into the agent may not use the correct address.
			info, err := p.environ.StateInfo()
			if err != nil {
				p.tomb.Kill(err)
				return
			}
			p.info = info
			p.innerLoop()
		}
	}
}

func (p *Provisioner) innerLoop() {
	// call processMachines to stop any unknown instances before watching machines.
	if err := p.processMachines(nil, nil); err != nil {
		p.tomb.Kill(err)
		return
	}
	p.machinesWatcher = p.st.WatchMachines()
	for {
		select {
		case <-p.tomb.Dying():
			return
		case change, ok := <-p.environWatcher.Changes():
			if !ok {
				err := p.environWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			config, err := environs.NewConfig(change.Map())
			if err != nil {
				log.Printf("provisioner loaded invalid environment configuration: %v", err)
				continue
			}
			p.environ.SetConfig(config)
			log.Printf("provisioner loaded new environment configuration")
		case machines, ok := <-p.machinesWatcher.Changes():
			if !ok {
				err := p.machinesWatcher.Stop()
				if err != nil {
					p.tomb.Kill(err)
				}
				return
			}
			// TODO(dfc) fire process machines periodically to shut down unknown
			// instances.
			if err := p.processMachines(machines.Added, machines.Deleted); err != nil {
				p.tomb.Kill(err)
			}
		}
	}
}

// Wait waits for the Provisioner to exit.
func (p *Provisioner) Wait() error {
	return p.tomb.Wait()
}

// Stop stops the Provisioner and returns any error encountered while
// provisioning.
func (p *Provisioner) Stop() error {
	p.tomb.Kill(nil)
	return p.tomb.Wait()
}

func (p *Provisioner) processMachines(added, removed []*state.Machine) error {
	// step 1. find which of the added machines have not
	// yet been allocated a started instance.
	notstarted, err := p.findNotStarted(added)
	if err != nil {
		return err
	}

	// step 2. start an instance for any machines we found.
	if err := p.startMachines(notstarted); err != nil {
		return err
	}

	// step 3. stop all machines that were removed from the state.
	stopping, err := p.instancesForMachines(removed)
	if err != nil {
		return err
	}

	// step 4. find instances which are running but have no machine
	// associated with them.
	unknown, err := p.findUnknownInstances()
	if err != nil {
		return err
	}

	return p.stopInstances(append(stopping, unknown...))
}

// findUnknownInstances finds instances which are not associated with a machine.
func (p *Provisioner) findUnknownInstances() ([]environs.Instance, error) {
	all, err := p.environ.AllInstances()
	if err != nil {
		return nil, err
	}
	instances := make(map[string]environs.Instance)
	for _, i := range all {
		instances[i.Id()] = i
	}
	// TODO(dfc) this is very inefficient, p.machines cache may help.
	machines, err := p.st.AllMachines()
	if err != nil {
		return nil, err
	}
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			continue
		}
		delete(instances, id)
	}
	var unknown []environs.Instance
	for _, i := range instances {
		unknown = append(unknown, i)
	}
	return unknown, nil
}

// findNotStarted finds machines without an InstanceId set, these are defined as not started.
func (p *Provisioner) findNotStarted(machines []*state.Machine) ([]*state.Machine, error) {
	var notstarted []*state.Machine
	for _, m := range machines {
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			notstarted = append(notstarted, m)
		} else {
			log.Printf("machine %s already started as instance %q", m, id)
		}
	}
	return notstarted, nil
}

func (p *Provisioner) startMachines(machines []*state.Machine) error {
	for _, m := range machines {
		if err := p.startMachine(m); err != nil {
			return err
		}
	}
	return nil
}

func (p *Provisioner) startMachine(m *state.Machine) error {
	// TODO(dfc) the state.Info passed to environ.StartInstance remains contentious
	// however as the PA only knows one state.Info, and that info is used by MAs and
	// UAs to locate the ZK for this environment, it is logical to use the same
	// state.Info as the PA.
	inst, err := p.environ.StartInstance(m.Id(), p.info)
	if err != nil {
		log.Printf("provisioner can't start machine %s: %v", m, err)
		return err
	}

	// assign the instance id to the machine
	if err := m.SetInstanceId(inst.Id()); err != nil {
		return err
	}

	// populate the local cache
	p.instances[m.Id()] = inst
	p.machines[inst.Id()] = m
	log.Printf("provisioner started machine %s as instance %s", m, inst.Id())
	return nil
}

func (p *Provisioner) stopInstances(instances []environs.Instance) error {
	// Although calling StopInstance with an empty slice should produce no change in the
	// provider, environs like dummy do not consider this a noop.
	if len(instances) == 0 {
		return nil
	}
	if err := p.environ.StopInstances(instances); err != nil {
		return err
	}

	// cleanup cache
	for _, i := range instances {
		if m, ok := p.machines[i.Id()]; ok {
			delete(p.machines, i.Id())
			delete(p.instances, m.Id())
		}
	}
	return nil
}

// instanceForMachine returns the environs.Instance that represents this machine's instance.
func (p *Provisioner) instanceForMachine(m *state.Machine) (environs.Instance, error) {
	inst, ok := p.instances[m.Id()]
	if !ok {
		// not cached locally, ask the environ.
		id, err := m.InstanceId()
		if err != nil {
			return nil, err
		}
		if id == "" {
			// TODO(dfc) InstanceId should return an error if the id isn't set.
			return nil, fmt.Errorf("machine %s not found", m)
		}
		// TODO(dfc) this should be batched, or the cache preloaded at startup to
		// avoid N calls to the envirion.
		insts, err := p.environ.Instances([]string{id})
		if err != nil {
			// the provider doesn't know about this instance, give up.
			return nil, err
		}
		inst = insts[0]
	}
	return inst, nil
}

// instancesForMachines returns a list of environs.Instance that represent the list of machines running
// in the provider.
func (p *Provisioner) instancesForMachines(machines []*state.Machine) ([]environs.Instance, error) {
	var insts []environs.Instance
	for _, m := range machines {
		inst, err := p.instanceForMachine(m)
		if err != nil {
			return nil, err
		}
		insts = append(insts, inst)
	}
	return insts, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package mop

import (
	`sort`
	`strings`
	`strconv`
)

type Sortable []Stock
func (list Sortable) Len() int { return len(list) }
func (list Sortable) Swap(i, j int) { list[i], list[j] = list[j], list[i] }

type ByTickerAsc       struct { Sortable }
type ByLastTradeAsc    struct { Sortable }
type ByChangeAsc       struct { Sortable }
type ByChangePctAsc    struct { Sortable }
type ByOpenAsc         struct { Sortable }
type ByLowAsc          struct { Sortable }
type ByHighAsc         struct { Sortable }
type ByLow52Asc        struct { Sortable }
type ByHigh52Asc       struct { Sortable }
type ByVolumeAsc       struct { Sortable }
type ByAvgVolumeAsc    struct { Sortable }
type ByPeRatioAsc      struct { Sortable }
type ByDividendAsc     struct { Sortable }
type ByYieldAsc        struct { Sortable }
type ByMarketCapAsc    struct { Sortable }

type ByTickerDesc      struct { Sortable }
type ByLastTradeDesc   struct { Sortable }
type ByChangeDesc      struct { Sortable }
type ByChangePctDesc   struct { Sortable }
type ByOpenDesc        struct { Sortable }
type ByLowDesc         struct { Sortable }
type ByHighDesc        struct { Sortable }
type ByLow52Desc       struct { Sortable }
type ByHigh52Desc      struct { Sortable }
type ByVolumeDesc      struct { Sortable }
type ByAvgVolumeDesc   struct { Sortable }
type ByPeRatioDesc     struct { Sortable }
type ByDividendDesc    struct { Sortable }
type ByYieldDesc       struct { Sortable }
type ByMarketCapDesc   struct { Sortable }

func (list ByTickerAsc)       Less(i, j int) bool { return list.Sortable[i].Ticker        < list.Sortable[j].Ticker }
func (list ByLastTradeAsc)    Less(i, j int) bool { return list.Sortable[i].LastTrade     < list.Sortable[j].LastTrade }
func (list ByChangeAsc)       Less(i, j int) bool { return c(list.Sortable[i].Change)     < c(list.Sortable[j].Change) }
func (list ByChangePctAsc)    Less(i, j int) bool { return c(list.Sortable[i].ChangePct)  < c(list.Sortable[j].ChangePct) }
func (list ByOpenAsc)         Less(i, j int) bool { return list.Sortable[i].Open          < list.Sortable[j].Open }
func (list ByLowAsc)          Less(i, j int) bool { return list.Sortable[i].Low           < list.Sortable[j].Low }
func (list ByHighAsc)         Less(i, j int) bool { return list.Sortable[i].High          < list.Sortable[j].High }
func (list ByLow52Asc)        Less(i, j int) bool { return list.Sortable[i].Low52         < list.Sortable[j].Low52 }
func (list ByHigh52Asc)       Less(i, j int) bool { return list.Sortable[i].High52        < list.Sortable[j].High52 }
func (list ByVolumeAsc)       Less(i, j int) bool { return list.Sortable[i].Volume        < list.Sortable[j].Volume }
func (list ByAvgVolumeAsc)    Less(i, j int) bool { return list.Sortable[i].AvgVolume     < list.Sortable[j].AvgVolume }
func (list ByPeRatioAsc)      Less(i, j int) bool { return list.Sortable[i].PeRatio       < list.Sortable[j].PeRatio }
func (list ByDividendAsc)     Less(i, j int) bool { return list.Sortable[i].Dividend      < list.Sortable[j].Dividend }
func (list ByYieldAsc)        Less(i, j int) bool { return list.Sortable[i].Yield         < list.Sortable[j].Yield }
func (list ByMarketCapAsc)    Less(i, j int) bool { return m(list.Sortable[i].MarketCap)  < m(list.Sortable[j].MarketCap) }

func (list ByTickerDesc)      Less(i, j int) bool { return list.Sortable[j].Ticker        < list.Sortable[i].Ticker }
func (list ByLastTradeDesc)   Less(i, j int) bool { return list.Sortable[j].LastTrade     < list.Sortable[i].LastTrade }
func (list ByChangeDesc)      Less(i, j int) bool { return c(list.Sortable[j].ChangePct)  < c(list.Sortable[i].ChangePct) }
func (list ByChangePctDesc)   Less(i, j int) bool { return c(list.Sortable[j].ChangePct)  < c(list.Sortable[i].ChangePct) }
func (list ByOpenDesc)        Less(i, j int) bool { return list.Sortable[j].Open          < list.Sortable[i].Open }
func (list ByLowDesc)         Less(i, j int) bool { return list.Sortable[j].Low           < list.Sortable[i].Low }
func (list ByHighDesc)        Less(i, j int) bool { return list.Sortable[j].High          < list.Sortable[i].High }
func (list ByLow52Desc)       Less(i, j int) bool { return list.Sortable[j].Low52         < list.Sortable[i].Low52 }
func (list ByHigh52Desc)      Less(i, j int) bool { return list.Sortable[j].High52        < list.Sortable[i].High52 }
func (list ByVolumeDesc)      Less(i, j int) bool { return list.Sortable[j].Volume        < list.Sortable[i].Volume }
func (list ByAvgVolumeDesc)   Less(i, j int) bool { return list.Sortable[j].AvgVolume     < list.Sortable[i].AvgVolume }
func (list ByPeRatioDesc)     Less(i, j int) bool { return list.Sortable[j].PeRatio       < list.Sortable[i].PeRatio }
func (list ByDividendDesc)    Less(i, j int) bool { return list.Sortable[j].Dividend      < list.Sortable[i].Dividend }
func (list ByYieldDesc)       Less(i, j int) bool { return list.Sortable[j].Yield         < list.Sortable[i].Yield }
func (list ByMarketCapDesc)   Less(i, j int) bool { return m(list.Sortable[j].MarketCap)  < m(list.Sortable[i].MarketCap) }

type Sorter struct {
	profile  *Profile
}

func (self *Sorter) Initialize(profile *Profile) *Sorter {
	self.profile = profile

	return self
}

func (self *Sorter) SortByCurrentColumn(stocks []Stock) *Sorter {
	var interfaces []sort.Interface

	if self.profile.Ascending {
		interfaces = []sort.Interface{
			ByTickerAsc       { stocks },
			ByLastTradeAsc    { stocks },
			ByChangeAsc       { stocks },
			ByChangePctAsc    { stocks },
			ByOpenAsc         { stocks },
			ByLowAsc          { stocks },
			ByHighAsc         { stocks },
			ByLow52Asc        { stocks },
			ByHigh52Asc       { stocks },
			ByVolumeAsc       { stocks },
			ByAvgVolumeAsc    { stocks },
			ByPeRatioAsc      { stocks },
			ByDividendAsc     { stocks },
			ByYieldAsc        { stocks },
			ByMarketCapAsc    { stocks },
		}
	} else {
		interfaces = []sort.Interface{
			ByTickerDesc      { stocks },
			ByLastTradeDesc   { stocks },
			ByChangeDesc      { stocks },
			ByChangePctDesc   { stocks },
			ByOpenDesc        { stocks },
			ByLowDesc         { stocks },
			ByHighDesc        { stocks },
			ByLow52Desc       { stocks },
			ByHigh52Desc      { stocks },
			ByVolumeDesc      { stocks },
			ByAvgVolumeDesc   { stocks },
			ByPeRatioDesc     { stocks },
			ByDividendDesc    { stocks },
			ByYieldDesc       { stocks },
			ByMarketCapDesc   { stocks },
		}
	}

	sort.Sort(interfaces[self.profile.SortColumn])

	return self
}

// The same exact method is used to sort by Change and Change%. In both cases
// we sort by the value of Change% so that $0.00 change gets sorted proferly.
func c(str string) float32 {
	trimmed := strings.Replace(strings.Trim(str, ` %`), `$`, ``, 1)
	value, _ := strconv.ParseFloat(trimmed, 32)
	return float32(value)
}

func m(str string) float32 {
	multiplier := 1.0
	switch str[len(str)-1:len(str)] {
	case `B`:
		multiplier = 1000000000.0
	case `M`:
		multiplier = 1000000.0
	case `K`:
		multiplier = 1000.0
	}
	trimmed := strings.Trim(str, ` $BMK`)
	value, _ := strconv.ParseFloat(trimmed, 32)
	return float32(value * multiplier)
}
<commit_msg>Made sortable types private<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//-----------------------------------------------------------------------------

package mop

import (
	`sort`
	`strings`
	`strconv`
)

type sortable []Stock
func (list sortable) Len() int { return len(list) }
func (list sortable) Swap(i, j int) { list[i], list[j] = list[j], list[i] }

type byTickerAsc       struct { sortable }
type byLastTradeAsc    struct { sortable }
type byChangeAsc       struct { sortable }
type byChangePctAsc    struct { sortable }
type byOpenAsc         struct { sortable }
type byLowAsc          struct { sortable }
type byHighAsc         struct { sortable }
type byLow52Asc        struct { sortable }
type byHigh52Asc       struct { sortable }
type byVolumeAsc       struct { sortable }
type byAvgVolumeAsc    struct { sortable }
type byPeRatioAsc      struct { sortable }
type byDividendAsc     struct { sortable }
type byYieldAsc        struct { sortable }
type byMarketCapAsc    struct { sortable }

type byTickerDesc      struct { sortable }
type byLastTradeDesc   struct { sortable }
type byChangeDesc      struct { sortable }
type byChangePctDesc   struct { sortable }
type byOpenDesc        struct { sortable }
type byLowDesc         struct { sortable }
type byHighDesc        struct { sortable }
type byLow52Desc       struct { sortable }
type byHigh52Desc      struct { sortable }
type byVolumeDesc      struct { sortable }
type byAvgVolumeDesc   struct { sortable }
type byPeRatioDesc     struct { sortable }
type byDividendDesc    struct { sortable }
type byYieldDesc       struct { sortable }
type byMarketCapDesc   struct { sortable }

func (list byTickerAsc)       Less(i, j int) bool { return list.sortable[i].Ticker        < list.sortable[j].Ticker }
func (list byLastTradeAsc)    Less(i, j int) bool { return list.sortable[i].LastTrade     < list.sortable[j].LastTrade }
func (list byChangeAsc)       Less(i, j int) bool { return c(list.sortable[i].Change)     < c(list.sortable[j].Change) }
func (list byChangePctAsc)    Less(i, j int) bool { return c(list.sortable[i].ChangePct)  < c(list.sortable[j].ChangePct) }
func (list byOpenAsc)         Less(i, j int) bool { return list.sortable[i].Open          < list.sortable[j].Open }
func (list byLowAsc)          Less(i, j int) bool { return list.sortable[i].Low           < list.sortable[j].Low }
func (list byHighAsc)         Less(i, j int) bool { return list.sortable[i].High          < list.sortable[j].High }
func (list byLow52Asc)        Less(i, j int) bool { return list.sortable[i].Low52         < list.sortable[j].Low52 }
func (list byHigh52Asc)       Less(i, j int) bool { return list.sortable[i].High52        < list.sortable[j].High52 }
func (list byVolumeAsc)       Less(i, j int) bool { return list.sortable[i].Volume        < list.sortable[j].Volume }
func (list byAvgVolumeAsc)    Less(i, j int) bool { return list.sortable[i].AvgVolume     < list.sortable[j].AvgVolume }
func (list byPeRatioAsc)      Less(i, j int) bool { return list.sortable[i].PeRatio       < list.sortable[j].PeRatio }
func (list byDividendAsc)     Less(i, j int) bool { return list.sortable[i].Dividend      < list.sortable[j].Dividend }
func (list byYieldAsc)        Less(i, j int) bool { return list.sortable[i].Yield         < list.sortable[j].Yield }
func (list byMarketCapAsc)    Less(i, j int) bool { return m(list.sortable[i].MarketCap)  < m(list.sortable[j].MarketCap) }

func (list byTickerDesc)      Less(i, j int) bool { return list.sortable[j].Ticker        < list.sortable[i].Ticker }
func (list byLastTradeDesc)   Less(i, j int) bool { return list.sortable[j].LastTrade     < list.sortable[i].LastTrade }
func (list byChangeDesc)      Less(i, j int) bool { return c(list.sortable[j].ChangePct)  < c(list.sortable[i].ChangePct) }
func (list byChangePctDesc)   Less(i, j int) bool { return c(list.sortable[j].ChangePct)  < c(list.sortable[i].ChangePct) }
func (list byOpenDesc)        Less(i, j int) bool { return list.sortable[j].Open          < list.sortable[i].Open }
func (list byLowDesc)         Less(i, j int) bool { return list.sortable[j].Low           < list.sortable[i].Low }
func (list byHighDesc)        Less(i, j int) bool { return list.sortable[j].High          < list.sortable[i].High }
func (list byLow52Desc)       Less(i, j int) bool { return list.sortable[j].Low52         < list.sortable[i].Low52 }
func (list byHigh52Desc)      Less(i, j int) bool { return list.sortable[j].High52        < list.sortable[i].High52 }
func (list byVolumeDesc)      Less(i, j int) bool { return list.sortable[j].Volume        < list.sortable[i].Volume }
func (list byAvgVolumeDesc)   Less(i, j int) bool { return list.sortable[j].AvgVolume     < list.sortable[i].AvgVolume }
func (list byPeRatioDesc)     Less(i, j int) bool { return list.sortable[j].PeRatio       < list.sortable[i].PeRatio }
func (list byDividendDesc)    Less(i, j int) bool { return list.sortable[j].Dividend      < list.sortable[i].Dividend }
func (list byYieldDesc)       Less(i, j int) bool { return list.sortable[j].Yield         < list.sortable[i].Yield }
func (list byMarketCapDesc)   Less(i, j int) bool { return m(list.sortable[j].MarketCap)  < m(list.sortable[i].MarketCap) }

type Sorter struct {
	profile  *Profile
}

func (self *Sorter) Initialize(profile *Profile) *Sorter {
	self.profile = profile

	return self
}

func (self *Sorter) SortByCurrentColumn(stocks []Stock) *Sorter {
	var interfaces []sort.Interface

	if self.profile.Ascending {
		interfaces = []sort.Interface{
			byTickerAsc       { stocks },
			byLastTradeAsc    { stocks },
			byChangeAsc       { stocks },
			byChangePctAsc    { stocks },
			byOpenAsc         { stocks },
			byLowAsc          { stocks },
			byHighAsc         { stocks },
			byLow52Asc        { stocks },
			byHigh52Asc       { stocks },
			byVolumeAsc       { stocks },
			byAvgVolumeAsc    { stocks },
			byPeRatioAsc      { stocks },
			byDividendAsc     { stocks },
			byYieldAsc        { stocks },
			byMarketCapAsc    { stocks },
		}
	} else {
		interfaces = []sort.Interface{
			byTickerDesc      { stocks },
			byLastTradeDesc   { stocks },
			byChangeDesc      { stocks },
			byChangePctDesc   { stocks },
			byOpenDesc        { stocks },
			byLowDesc         { stocks },
			byHighDesc        { stocks },
			byLow52Desc       { stocks },
			byHigh52Desc      { stocks },
			byVolumeDesc      { stocks },
			byAvgVolumeDesc   { stocks },
			byPeRatioDesc     { stocks },
			byDividendDesc    { stocks },
			byYieldDesc       { stocks },
			byMarketCapDesc   { stocks },
		}
	}

	sort.Sort(interfaces[self.profile.SortColumn])

	return self
}

// The same exact method is used to sort by Change and Change%. In both cases
// we sort by the value of Change% so that $0.00 change gets sorted proferly.
func c(str string) float32 {
	trimmed := strings.Replace(strings.Trim(str, ` %`), `$`, ``, 1)
	value, _ := strconv.ParseFloat(trimmed, 32)
	return float32(value)
}

func m(str string) float32 {
	multiplier := 1.0
	switch str[len(str)-1:len(str)] {
	case `B`:
		multiplier = 1000000000.0
	case `M`:
		multiplier = 1000000.0
	case `K`:
		multiplier = 1000.0
	}
	trimmed := strings.Trim(str, ` $BMK`)
	value, _ := strconv.ParseFloat(trimmed, 32)
	return float32(value * multiplier)
}
<|endoftext|>