<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"

	"golang.org/x/net/html"
	"golang.org/x/net/html/charset"
)

var (
	encoding    string
	contType    string
	lang        string
	prefix      = "Заголовок"
	link        string
	showHeaders bool
)

func init() {
	flag.StringVar(&encoding, "oe", "utf8", "Output Encoding")
	flag.StringVar(&lang, "lang", "ru", "Language to output in")
	flag.BoolVar(&showHeaders, "headers", false, "Show HTTP Headers")
	flag.Parse()
}

func main() {
	if lang != "ru" {
		prefix = "Title"
	}
	if len(flag.Args()) > 0 && len(flag.Arg(0)) > 0 {
		link = flag.Arg(0)
	}
	if len(link) <= 4 || link[0:4] != "http" {
		usage(lang)
		return
	}
	if headers, err := http.Head(link); err == nil {
		contType = headers.Header.Get("Content-Type")
		if showHeaders || len(contType) >= 9 && contType[0:9] != "text/html" {
			for k, v := range headers.Header {
				if showHeaders || (k == "Content-Type" || k == "Content-Length") {
					fmt.Printf("\n%s: %s", k, v)
				}
			}
			return
		}
	}
	res, err := http.Get(link)
	if err != nil {
		log.Fatal(err)
	}
	var title string
	if text, err := charset.NewReader(res.Body, contType); err == nil {
		title, _ = getTag(text, "title")
	}
	title = strings.Trim(title, "\n ")
	if len(title) > 0 {
		fmt.Print(prefix + ": " + title)
	}
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
}

// getTag gets data (textToken) from requested html-tag.
func getTag(r io.Reader, tag string) (data string, err error) {
	d := html.NewTokenizer(r)
	var currTag html.Token
	for {
		// token type
		tokenType := d.Next()
		if tokenType == html.ErrorToken {
			return "", errors.New("Token Error!")
		}
		token := d.Token()
		switch tokenType {
		case html.StartTagToken: // <tag>
			// type Token struct {
			//     Type     TokenType
			//     DataAtom atom.Atom
			//     Data     string
			//     Attr     []Attribute
			// }
			//
			// type Attribute struct {
			//     Namespace, Key, Val string
			// }

			if token.Data == tag {
				currTag = token
			}
		case html.TextToken: // text between start and end tag
			if currTag.Data == tag {
				return token.Data, nil
			}
		case html.EndTagToken: // </tag>
			if token.Data == tag {
				currTag = token
			}
		case html.SelfClosingTagToken: // <tag/>
		}
	}
}

func usage(lang string) {
	if lang != "ru" {
		fmt.Println("gettitle [-lang=ru|en] [-oe=utf8] [-headers] <http(s)://www.server.com/>")
	} else {
		fmt.Println("gettitle [-lang=ru|en] [-oe=utf8] [-headers] <http(s)://сервер.рф/>")
	}
}
<commit_msg>FIX gettitle: prefix http-header output.<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"

	"golang.org/x/net/html"
	"golang.org/x/net/html/charset"
)

var (
	encoding    string
	contType    string
	lang        string
	link        string
	showHeaders bool
	prefix      = "Заголовок"
	unkPrefix   = "HTTP заголовок"
)

func init() {
	flag.StringVar(&encoding, "oe", "utf8", "Output Encoding")
	flag.StringVar(&lang, "lang", "ru", "Language to output in")
	flag.BoolVar(&showHeaders, "headers", false, "Show HTTP Headers")
	flag.Parse()
}

func main() {
	if lang != "ru" {
		prefix = "Title"
		unkPrefix = "HTTP Header"
	}
	if len(flag.Args()) > 0 && len(flag.Arg(0)) > 0 {
		link = flag.Arg(0)
	}
	if len(link) <= 4 || link[0:4] != "http" {
		usage(lang)
		return
	}
	if headers, err := http.Head(link); err == nil {
		contType = headers.Header.Get("Content-Type")
		if showHeaders || len(contType) >= 9 && contType[0:9] != "text/html" {
			fmt.Print(unkPrefix + ":")
			for k, v := range headers.Header {
				if showHeaders || (k == "Content-Type" || k == "Content-Length") {
					fmt.Printf("\n%s: %s", k, v)
				}
			}
			return
		}
	}
	res, err := http.Get(link)
	if err != nil {
		log.Fatal(err)
	}
	var title string
	if text, err := charset.NewReader(res.Body, contType); err == nil {
		title, _ = getTag(text, "title")
	}
	title = strings.Trim(title, "\n ")
	if len(title) > 0 {
		fmt.Print(prefix + ": " + title)
	}
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
}

// getTag gets data (textToken) from requested html-tag.
func getTag(r io.Reader, tag string) (data string, err error) {
	d := html.NewTokenizer(r)
	var currTag html.Token
	for {
		// token type
		tokenType := d.Next()
		if tokenType == html.ErrorToken {
			return "", errors.New("Token Error!")
		}
		token := d.Token()
		switch tokenType {
		case html.StartTagToken: // <tag>
			// type Token struct {
			//     Type     TokenType
			//     DataAtom atom.Atom
			//     Data     string
			//     Attr     []Attribute
			// }
			//
			// type Attribute struct {
			//     Namespace, Key, Val string
			// }

			if token.Data == tag {
				currTag = token
			}
		case html.TextToken: // text between start and end tag
			if currTag.Data == tag {
				return token.Data, nil
			}
		case html.EndTagToken: // </tag>
			if token.Data == tag {
				currTag = token
			}
		case html.SelfClosingTagToken: // <tag/>
		}
	}
}

func usage(lang string) {
	if lang != "ru" {
		fmt.Println("gettitle [-lang=ru|en] [-oe=utf8] [-headers] <http(s)://www.server.com/>")
	} else {
		fmt.Println("gettitle [-lang=ru|en] [-oe=utf8] [-headers] <http(s)://сервер.рф/>")
	}
}
<|endoftext|>


<commit_before>package app

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/crazy-max/WindowsSpyBlocker/app/utils/config"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/file"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/netu"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/print"
	"github.com/crazy-max/WindowsSpyBlocker/app/whois"
)

// DownloadLib download an external library
func DownloadLib(lib config.Lib) error {
	if lib.OutputPath != "" {
		if _, err := os.Stat(lib.OutputPath); os.IsNotExist(err) {
			fmt.Printf("Creating folder %s... ", lib.OutputPath)
			if err := file.CreateSubfolder(lib.OutputPath); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()
		}
		if _, err := os.Stat(lib.Checkfile); err != nil {
			fmt.Printf("Downloading %s...", lib.Url)
			if err := netu.DownloadFile(lib.Dest, lib.Url, lib.Checksum); err != nil {
				fmt.Print(" ")
				print.Error(err)
				return err
			}
			fmt.Print(" ")
			print.Ok()

			fmt.Printf("Unzipping %s... ", lib.Dest)
			if err := file.Unzip(lib.Dest, lib.OutputPath); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()

			fmt.Printf("Seeking checkfile %s... ", lib.Checkfile)
			if _, err := os.Stat(lib.Checkfile); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()
		}
	} else {
		fmt.Printf("Downloading %s...", lib.Url)
		if err := netu.DownloadFile(lib.Dest, lib.Url, lib.Checksum); err != nil {
			fmt.Print(" ")
			print.Error(err)
			return err
		}
		fmt.Print(" ")
		print.Ok()
	}

	return nil
}

// GetFilteredIpOrDomain get an ip address or domain filtered by excluded values in app.conf
func GetFilteredIpOrDomain(ipOrDomain string) string {
	ipOrDomain = strings.ToLower(ipOrDomain)

	if netu.IsValidIPv4(ipOrDomain) {
		for _, exp := range config.App.Exclude.Ips {
			if isIpExcluded(ipOrDomain, exp) {
				return ""
			}
		}
	} else {
		for _, exp := range config.App.Exclude.Hosts {
			if isDomainExcluded(ipOrDomain, exp) {
				return ""
			}
		}
	}

	whoisRes := whois.GetWhois(ipOrDomain)
	if whoisRes != (whois.Whois{}) {
		for _, exp := range config.App.Exclude.Orgs {
			if isOrgExcluded(whoisRes.Org, exp) {
				return ""
			}
		}
	}

	return ipOrDomain
}

func isIpExcluded(ipStr string, exp string) bool {
	ip := net.ParseIP(ipStr)
	if ip.To4() == nil {
		return true
	}

	if strings.Contains(exp, "-") {
		ipRange := strings.SplitN(exp, "-", 2)
		if len(ipRange) != 2 {
			return false
		}
		ipRange0 := net.ParseIP(ipRange[0])
		ipRange1 := net.ParseIP(ipRange[1])
		if ipRange0.To4() == nil || ipRange1.To4() == nil {
			return false
		}
		if bytes.Compare(ip, ipRange0) >= 0 && bytes.Compare(ip, ipRange1) <= 0 {
			//fmt.Println(host + " in range of " + ipEx)
			return true
		}
	} else if !netu.IsValidIPv4(exp) {
		return false
	} else if exp == ipStr {
		//fmt.Println(host + " = " + ipEx)
		return true
	}

	return false
}

func isDomainExcluded(host string, exp string) bool {
	re := regexp.MustCompile(`(?i)^` + strings.Replace(exp, "*", "(.*?)", -1) + "$")
	matches := re.FindAllString(host, -1)
	if len(matches) == 1 {
		return true
	}
	return false
}

func isOrgExcluded(org string, exp string) bool {
	re := regexp.MustCompile(`(?i)^` + strings.Replace(exp, "*", "(.*?)", -1) + "$")
	matches := re.FindAllString(org, -1)
	if len(matches) == 1 {
		return true
	}
	return false
}

// GetLatestVersion returns the latest version from github
func GetLatestVersion() (string, error) {
	probeUrl := "https://raw.githubusercontent.com/wiki/crazy-max/WindowsSpyBlocker/latest"

	client := &http.Client{Timeout: 2 * time.Second}
	response, err := client.Get(probeUrl)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()

	if response.StatusCode == 200 {
		bodyBytes, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		return string(bodyBytes), nil
	}

	return "", fmt.Errorf("Status code %d", response.StatusCode)
}
<commit_msg>Improve exclude filter<commit_after>package app

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/crazy-max/WindowsSpyBlocker/app/utils/config"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/file"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/netu"
	"github.com/crazy-max/WindowsSpyBlocker/app/utils/print"
	"github.com/crazy-max/WindowsSpyBlocker/app/whois"
)

// DownloadLib download an external library
func DownloadLib(lib config.Lib) error {
	if lib.OutputPath != "" {
		if _, err := os.Stat(lib.OutputPath); os.IsNotExist(err) {
			fmt.Printf("Creating folder %s... ", lib.OutputPath)
			if err := file.CreateSubfolder(lib.OutputPath); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()
		}
		if _, err := os.Stat(lib.Checkfile); err != nil {
			fmt.Printf("Downloading %s...", lib.Url)
			if err := netu.DownloadFile(lib.Dest, lib.Url, lib.Checksum); err != nil {
				fmt.Print(" ")
				print.Error(err)
				return err
			}
			fmt.Print(" ")
			print.Ok()

			fmt.Printf("Unzipping %s... ", lib.Dest)
			if err := file.Unzip(lib.Dest, lib.OutputPath); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()

			fmt.Printf("Seeking checkfile %s... ", lib.Checkfile)
			if _, err := os.Stat(lib.Checkfile); err != nil {
				print.Error(err)
				return err
			}
			print.Ok()
		}
	} else {
		fmt.Printf("Downloading %s...", lib.Url)
		if err := netu.DownloadFile(lib.Dest, lib.Url, lib.Checksum); err != nil {
			fmt.Print(" ")
			print.Error(err)
			return err
		}
		fmt.Print(" ")
		print.Ok()
	}

	return nil
}

// GetFilteredIpOrDomain get an ip address or domain filtered by excluded values in app.conf
func GetFilteredIpOrDomain(ipOrDomain string) string {
	ipOrDomain = strings.ToLower(ipOrDomain)

	if netu.IsValidIPv4(ipOrDomain) {
		for _, exp := range config.App.Exclude.Ips {
			if isIpExcluded(ipOrDomain, exp) {
				return ""
			}
		}
	} else {
		for _, exp := range config.App.Exclude.Hosts {
			if isDomainExcluded(ipOrDomain, exp) {
				return ""
			}
		}
	}

	whoisRes := whois.GetWhois(ipOrDomain)
	if whoisRes != (whois.Whois{}) {
		for _, exp := range config.App.Exclude.Orgs {
			if isOrgExcluded(whoisRes.Org, exp) {
				return ""
			}
		}
	}

	return ipOrDomain
}

func isIpExcluded(ipStr string, exp string) bool {
	ip := net.ParseIP(ipStr)
	if ip.To4() == nil {
		return true
	}

	if strings.Contains(exp, "-") {
		ipRange := strings.SplitN(exp, "-", 2)
		if len(ipRange) != 2 {
			return false
		}
		ipRange0 := net.ParseIP(ipRange[0])
		ipRange1 := net.ParseIP(ipRange[1])
		if ipRange0.To4() == nil || ipRange1.To4() == nil {
			return false
		}
		if bytes.Compare(ip, ipRange0) >= 0 && bytes.Compare(ip, ipRange1) <= 0 {
			//fmt.Println(host + " in range of " + ipEx)
			return true
		}
	} else if !netu.IsValidIPv4(exp) {
		return false
	} else if exp == ipStr {
		//fmt.Println(host + " = " + ipEx)
		return true
	}

	return false
}

func isDomainExcluded(host string, exp string) bool {
	re := regexp.MustCompile(`(?i)^` + strings.Replace(exp, "*", `([^"]+)`, -1) + "$")
	matches := re.FindAllString(host, -1)
	if len(matches) == 1 {
		return true
	}
	return false
}

func isOrgExcluded(org string, exp string) bool {
	re := regexp.MustCompile(`(?i)^` + strings.Replace(exp, "*", `([^"]+)`, -1) + "$")
	matches := re.FindAllString(org, -1)
	if len(matches) == 1 {
		return true
	}
	return false
}

// GetLatestVersion returns the latest version from github
func GetLatestVersion() (string, error) {
	probeUrl := "https://raw.githubusercontent.com/wiki/crazy-max/WindowsSpyBlocker/latest"

	client := &http.Client{Timeout: 2 * time.Second}
	response, err := client.Get(probeUrl)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()

	if response.StatusCode == 200 {
		bodyBytes, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return "", err
		}
		return string(bodyBytes), nil
	}

	return "", fmt.Errorf("Status code %d", response.StatusCode)
}
<|endoftext|>


<commit_before>package web

import (
	"encoding/json"
	"net/http"
)

func status(w http.ResponseWriter, r *http.Request) {
	var returnMap map[string]interface{}
	encoder := json.NewEncoder(w)
	if encoder == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	returnMap["status"] = audioManager.Status()
	encoder.Encode(returnMap)
}
<commit_msg>Clean up status handler<commit_after>package web

import (
	"encoding/json"
	"net/http"
)

func status(w http.ResponseWriter, r *http.Request) {
	encoder := json.NewEncoder(w)
	if encoder == nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	encoder.Encode(audioManager.Status())
}

func preachers(w http.ResponseWriter, r *http.Request) {
	encoder := json.NewEncoder(w)
}
<|endoftext|>


<commit_before>package web

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"
)

type indexHandler struct{ App }

func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := ih.App.GetClient(r)
	if id != "" {
		log.Printf("Client '%s' loaded index from %s", id, r.RemoteAddr)
	} else {
		log.Printf("User loaded index from %s", r.RemoteAddr)
	}

	// Web address to use in template
	addr := fmt.Sprintf("%s%s", r.Host, ih.App.Address)

	// Show welcome page by default
	defaultUrl := fmt.Sprintf("http://%s/welcome?client=%s", addr, id)

	// Get URLs from database
	urls, err := ih.App.Database.FetchUrls()
	if err != nil {
		log.Println(err)
		return
	}

	// Load template, parse vars, write to client
	t, err := template.New("index").Parse(indexTemplate)
	if err != nil {
		log.Println(err)
		return
	}
	t.Execute(w, struct {
		Address    template.URL
		DefaultUrl template.URL
		Client     string
		URLs       []string
	}{
		template.URL(addr),
		template.URL(defaultUrl),
		id,
		urls,
	})
}

type welcomeHandler struct{ App }

func (wh *welcomeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := wh.App.GetClient(r)

	// Load template, parse vars, write to client
	t, _ := template.New("welcome").Parse(welcomeTemplate)
	t.Execute(w, struct {
		Client     string
		RemoteAddr string
	}{
		id,
		r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")],
	})
}

type consoleHandler struct{ App }

func (ah *consoleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := ah.App.GetClient(r)

	// Web address to use in template
	addr := fmt.Sprintf("%s%s", r.Host, ah.App.Address)

	// Load template, parse vars, write to client
	t, _ := template.New("console").Parse(consoleTemplate)
	t.Execute(w, struct {
		Address    template.URL
		Client     string
		RemoteAddr string
	}{
		template.URL(addr),
		id,
		r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")],
	})
}

type websocketHandler struct{ App }

func (wh *websocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
	}

	// track whether this is a "registered" client or not
	var generic bool

	id := wh.App.GetClient(r)
	if id == "" {
		generic = true

		id = fmt.Sprintf("User (%d)", time.Now().UnixNano())
		log.Printf("%s connected to websocket from %s", id, r.RemoteAddr)
	} else {
		generic = false

		log.Printf("Client '%s' connected to websocket from %s", id, r.RemoteAddr)
	}

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	c := &websocketClient{
		Id:        id,
		Generic:   generic,
		IpAddress: r.RemoteAddr,
		send:      make(chan *websocketMessage),
		ws:        ws,
	}

	hub.register <- c
	go c.writePump()
	c.readPump(wh.App.Database)
}
<commit_msg>Fix printed IP address on welcome page for IPv6<commit_after>package web

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
	"time"
)

type indexHandler struct{ App }

func (ih *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := ih.App.GetClient(r)
	if id != "" {
		log.Printf("Client '%s' loaded index from %s", id, r.RemoteAddr)
	} else {
		log.Printf("User loaded index from %s", r.RemoteAddr)
	}

	// Web address to use in template
	addr := fmt.Sprintf("%s%s", r.Host, ih.App.Address)

	// Show welcome page by default
	defaultUrl := fmt.Sprintf("http://%s/welcome?client=%s", addr, id)

	// Get URLs from database
	urls, err := ih.App.Database.FetchUrls()
	if err != nil {
		log.Println(err)
		return
	}

	// Load template, parse vars, write to client
	t, err := template.New("index").Parse(indexTemplate)
	if err != nil {
		log.Println(err)
		return
	}
	t.Execute(w, struct {
		Address    template.URL
		DefaultUrl template.URL
		Client     string
		URLs       []string
	}{
		template.URL(addr),
		template.URL(defaultUrl),
		id,
		urls,
	})
}

type welcomeHandler struct{ App }

func (wh *welcomeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := wh.App.GetClient(r)

	// Load template, parse vars, write to client
	t, _ := template.New("welcome").Parse(welcomeTemplate)
	t.Execute(w, struct {
		Client     string
		RemoteAddr string
	}{
		id,
		r.RemoteAddr[:strings.LastIndex(r.RemoteAddr, ":")],
	})
}

type consoleHandler struct{ App }

func (ah *consoleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id := ah.App.GetClient(r)

	// Web address to use in template
	addr := fmt.Sprintf("%s%s", r.Host, ah.App.Address)

	// Load template, parse vars, write to client
	t, _ := template.New("console").Parse(consoleTemplate)
	t.Execute(w, struct {
		Address    template.URL
		Client     string
		RemoteAddr string
	}{
		template.URL(addr),
		id,
		r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")],
	})
}

type websocketHandler struct{ App }

func (wh *websocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
	}

	// track whether this is a "registered" client or not
	var generic bool

	id := wh.App.GetClient(r)
	if id == "" {
		generic = true

		id = fmt.Sprintf("User (%d)", time.Now().UnixNano())
		log.Printf("%s connected to websocket from %s", id, r.RemoteAddr)
	} else {
		generic = false

		log.Printf("Client '%s' connected to websocket from %s", id, r.RemoteAddr)
	}

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}

	c := &websocketClient{
		Id:        id,
		Generic:   generic,
		IpAddress: r.RemoteAddr,
		send:      make(chan *websocketMessage),
		ws:        ws,
	}

	hub.register <- c
	go c.writePump()
	c.readPump(wh.App.Database)
}
<|endoftext|>


<commit_before>package logredis

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
)

// RedisHook to sends logs to Redis server
type RedisHook struct {
	RedisPool *redis.Pool
	RedisHost string
	RedisKey  string
	RedisPort int
}

// Message holds information which is sent to REDIS
type Message struct {
	Level      string
	Type       string
	Message    string
	Sourcehost string
	Timestamp  time.Time
}

// NewHook creates a hook to be added to an instance of logger
func NewHook(host string, port int, key string) (*RedisHook, error) {
	pool := newRedisConnectionPool(host, port)

	// test if connection with REDIS can be established
	conn := pool.Get()
	defer conn.Close()

	// check connection
	_, err := conn.Do("PING")
	if err != nil {
		return nil, fmt.Errorf("unable to connect to REDIS: %s", err)
	}

	return &RedisHook{
		RedisHost: host,
		RedisPool: pool,
		RedisKey:  key,
	}, nil
}

// Fire is called when a log event is fired.
func (hook *RedisHook) Fire(entry *logrus.Entry) error {
	msg := createMessage(entry)

	js, err := json.Marshal(msg)
	if err != nil {
		return fmt.Errorf("error creating message for REDIS: %s", err)
	}

	conn := hook.RedisPool.Get()
	defer conn.Close()

	_, err = conn.Do("RPUSH", hook.RedisKey, js)
	if err != nil {
		return fmt.Errorf("error sending message to REDIS: %s", err)
	}
	return nil
}

// Levels returns the available logging levels.
func (hook *RedisHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.DebugLevel,
		logrus.InfoLevel,
		logrus.WarnLevel,
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	}
}

func createMessage(entry *logrus.Entry) Message {
	m := Message{
		Level:      entry.Level.String(),
		Type:       "type hier",
		Message:    entry.Message,
		Sourcehost: reportHostname(),
		Timestamp:  time.Now().UTC(),
	}
	return m
}

func newRedisConnectionPool(server string, port int) *redis.Pool {
	hostPort := fmt.Sprintf("%s:%d", server, port)
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", hostPort)
			if err != nil {
				return nil, err
			}

			// if password != "" {
			// 	if _, err := c.Do("AUTH", password); err != nil {
			// 		c.Close()
			// 		return nil, err
			// 	}
			// }
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func reportHostname() string {
	h, err := os.Hostname()
	if err != nil {
		return "unknown"
	}
	return h
}
<commit_msg>Change message<commit_after>package logredis

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
)

// RedisHook to sends logs to Redis server
type RedisHook struct {
	RedisPool *redis.Pool
	RedisHost string
	RedisKey  string
	RedisPort int
}

// Message holds information which is sent to REDIS
type Message struct {
	Type       string `json:"@type,omitempty"`
	Timestamp  string `json:"@timestamp"`
	Sourcehost string `json:"host"`
	Message    string `json:"message"`
}

// NewHook creates a hook to be added to an instance of logger
func NewHook(host string, port int, key string) (*RedisHook, error) {
	pool := newRedisConnectionPool(host, port)

	// test if connection with REDIS can be established
	conn := pool.Get()
	defer conn.Close()

	// check connection
	_, err := conn.Do("PING")
	if err != nil {
		return nil, fmt.Errorf("unable to connect to REDIS: %s", err)
	}

	return &RedisHook{
		RedisHost: host,
		RedisPool: pool,
		RedisKey:  key,
	}, nil
}

// Fire is called when a log event is fired.
func (hook *RedisHook) Fire(entry *logrus.Entry) error {
	msg := createMessage(entry)

	js, err := json.Marshal(msg)
	if err != nil {
		return fmt.Errorf("error creating message for REDIS: %s", err)
	}

	conn := hook.RedisPool.Get()
	defer conn.Close()

	_, err = conn.Do("RPUSH", hook.RedisKey, js)
	if err != nil {
		return fmt.Errorf("error sending message to REDIS: %s", err)
	}
	return nil
}

// Levels returns the available logging levels.
func (hook *RedisHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.DebugLevel,
		logrus.InfoLevel,
		logrus.WarnLevel,
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	}
}

func createMessage(entry *logrus.Entry) Message {
	m := Message{
		Type:       "type hier",
		Timestamp:  entry.Time.UTC().Format(time.RFC3339Nano),
		Sourcehost: reportHostname(),
		Message:    entry.Message,
	}
	return m
}

func newRedisConnectionPool(server string, port int) *redis.Pool {
	hostPort := fmt.Sprintf("%s:%d", server, port)
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", hostPort)
			if err != nil {
				return nil, err
			}

			// if password != "" {
			// 	if _, err := c.Do("AUTH", password); err != nil {
			// 		c.Close()
			// 		return nil, err
			// 	}
			// }

			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func reportHostname() string {
	h, err := os.Hostname()
	if err != nil {
		return "unknown"
	}
	return h
}
<|endoftext|>


<commit_before>package docker

import (
	"os"
	"os/exec"
	"regexp"
	"strconv"

	"github.com/docker-exec/dexec/util"
)

// DockerVersion shells out the command 'docker -v', returning the version
// information if the command is successful, and panicking if not.
var DockerVersion = func() string {
	out, err := exec.Command("docker", "-v").Output()
	if err != nil {
		panic(err.Error())
	} else {
		return string(out)
	}
}

// DockerInfo shells out the command 'docker -info', returning the information
// if the command is successful and panicking if not.
var DockerInfo = func() string {
	out, err := exec.Command("docker", "info").Output()
	if err != nil {
		panic(err.Error())
	} else {
		return string(out)
	}
}

// DockerPull shells out the command 'docker pull {{image}}' where image is
// the name of a Docker image to retrieve from the remote Docker repository.
var DockerPull = func(image string) {
	out := exec.Command("docker", "pull", image)
	out.Stdin = os.Stdin
	out.Stdout = os.Stderr
	out.Stderr = os.Stderr
	out.Run()
}

// ExtractDockerVersion takes a Docker version string in the format:
// 'Docker version 1.0.0, build abcdef0', extracts the major, minor and patch
// versions and returns these as a tuple. If the string does not match, panic.
func ExtractDockerVersion(version string) (int, int, int) {
	dockerVersionPattern := regexp.MustCompile(`^Docker version (\d+)\.(\d+)\.(\d+), build [a-z0-9]{7}`)

	if dockerVersionPattern.MatchString(version) {
		match := dockerVersionPattern.FindStringSubmatch(version)
		major, _ := strconv.Atoi(match[1])
		minor, _ := strconv.Atoi(match[2])
		patch, _ := strconv.Atoi(match[3])
		return major, minor, patch
	}
	panic("Did not match Docker version string")
}

// IsDockerPresent tests for the presence of Docker by invoking DockerVersion
// to get the version of Docker if available, and then attempting to parse the
// version with ExtractDocker version. This function will return true only
// if neither of these functions panics.
func IsDockerPresent() (present bool) {
	present = true
	defer func() {
		if r := recover(); r != nil {
			present = false
		}
	}()
	ExtractDockerVersion(DockerVersion())
	return
}

// IsDockerRunning tests whether Docker is running by invoking DockerInfo
// which will only return information if Docker is up. This function will
// return true if DockerInfo does not panic.
func IsDockerRunning() (running bool) {
	running = true
	defer func() {
		if r := recover(); r != nil {
			running = false
		}
	}()
	DockerInfo()
	return
}

// RunAnonymousContainer shells out the command:
// 'docker run --rm {{extraDockerArgs}} -t {{image}} {{entrypointArgs}}'.
// This will run an anonymouse Docker container with the specified image, with
// any extra arguments to pass to Docker, for example directories to mount,
// as well as arguments to pass to the image's entrypoint.
func RunAnonymousContainer(image string, extraDockerArgs []string, entrypointArgs []string) {
	baseDockerArgs := []string{"run", "--rm"}
	imageDockerArgs := []string{"-t", image}
	out := exec.Command(
		"docker",
		util.JoinStringSlices(
			baseDockerArgs,
			extraDockerArgs,
			imageDockerArgs,
			entrypointArgs,
		)...,
	)
	out.Stdin = os.Stdin
	out.Stdout = os.Stdout
	out.Stderr = os.Stderr
	out.Run()
}
<commit_msg>forward stderr/stdout for issue #42<commit_after>package docker

import (
	"os"
	"os/exec"
	"regexp"
	"strconv"

	"github.com/docker-exec/dexec/util"
)

// DockerVersion shells out the command 'docker -v', returning the version
// information if the command is successful, and panicking if not.
var DockerVersion = func() string {
	out, err := exec.Command("docker", "-v").Output()
	if err != nil {
		panic(err.Error())
	} else {
		return string(out)
	}
}

// DockerInfo shells out the command 'docker -info', returning the information
// if the command is successful and panicking if not.
var DockerInfo = func() string {
	out, err := exec.Command("docker", "info").Output()
	if err != nil {
		panic(err.Error())
	} else {
		return string(out)
	}
}

// DockerPull shells out the command 'docker pull {{image}}' where image is
// the name of a Docker image to retrieve from the remote Docker repository.
var DockerPull = func(image string) {
	out := exec.Command("docker", "pull", image)
	out.Stdin = os.Stdin
	out.Stdout = os.Stderr
	out.Stderr = os.Stderr
	out.Run()
}

// ExtractDockerVersion takes a Docker version string in the format:
// 'Docker version 1.0.0, build abcdef0', extracts the major, minor and patch
// versions and returns these as a tuple. If the string does not match, panic.
func ExtractDockerVersion(version string) (int, int, int) {
	dockerVersionPattern := regexp.MustCompile(`^Docker version (\d+)\.(\d+)\.(\d+), build [a-z0-9]{7}`)

	if dockerVersionPattern.MatchString(version) {
		match := dockerVersionPattern.FindStringSubmatch(version)
		major, _ := strconv.Atoi(match[1])
		minor, _ := strconv.Atoi(match[2])
		patch, _ := strconv.Atoi(match[3])
		return major, minor, patch
	}
	panic("Did not match Docker version string")
}

// IsDockerPresent tests for the presence of Docker by invoking DockerVersion
// to get the version of Docker if available, and then attempting to parse the
// version with ExtractDocker version. This function will return true only
// if neither of these functions panics.
func IsDockerPresent() (present bool) {
	present = true
	defer func() {
		if r := recover(); r != nil {
			present = false
		}
	}()
	ExtractDockerVersion(DockerVersion())
	return
}

// IsDockerRunning tests whether Docker is running by invoking DockerInfo
// which will only return information if Docker is up. This function will
// return true if DockerInfo does not panic.
func IsDockerRunning() (running bool) {
	running = true
	defer func() {
		if r := recover(); r != nil {
			running = false
		}
	}()
	DockerInfo()
	return
}

// RunAnonymousContainer shells out the command:
// 'docker run --rm {{extraDockerArgs}} -t {{image}} {{entrypointArgs}}'.
// This will run an anonymouse Docker container with the specified image, with
// any extra arguments to pass to Docker, for example directories to mount,
// as well as arguments to pass to the image's entrypoint.
func RunAnonymousContainer(image string, extraDockerArgs []string, entrypointArgs []string) {
	baseDockerArgs := []string{"run", "--rm"}
	imageDockerArgs := []string{image}
	out := exec.Command(
		"docker",
		util.JoinStringSlices(
			baseDockerArgs,
			extraDockerArgs,
			imageDockerArgs,
			entrypointArgs,
		)...,
	)
	out.Stdin = os.Stdin
	out.Stdout = os.Stdout
	out.Stderr = os.Stderr
	out.Run()
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/plans"
)

// EvalDeleteOutput is an EvalNode implementation that deletes an output
// from the state.
type EvalDeleteOutput struct {
	Addr addrs.OutputValue
}

// TODO: test
func (n *EvalDeleteOutput) Eval(ctx EvalContext) (interface{}, error) {
	state := ctx.State()
	if state == nil {
		return nil, nil
	}

	state.RemoveOutputValue(n.Addr.Absolute(ctx.Path()))
	return nil, nil
}

// EvalWriteOutput is an EvalNode implementation that writes the output
// for the given name to the current state.
type EvalWriteOutput struct {
	Addr      addrs.OutputValue
	Sensitive bool
	Expr      hcl.Expression
	// ContinueOnErr allows interpolation to fail during Input
	ContinueOnErr bool
}

// TODO: test
func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
	addr := n.Addr.Absolute(ctx.Path())

	// This has to run before we have a state lock, since evaluation also
	// reads the state
	val, diags := ctx.EvaluateExpr(n.Expr, cty.DynamicPseudoType, nil)
	// We'll handle errors below, after we have loaded the module.

	state := ctx.State()
	if state == nil {
		return nil, nil
	}

	changes := ctx.Changes() // may be nil, if we're not working on a changeset

	// handling the interpolation error
	if diags.HasErrors() {
		if n.ContinueOnErr || flagWarnOutputErrors {
			log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr.Name, diags.Err())
			// if we're continuing, make sure the output is included, and
			// marked as unknown. If the evaluator was able to find a type
			// for the value in spite of the error then we'll use it.
			state.SetOutputValue(addr, cty.UnknownVal(val.Type()), n.Sensitive)
			return nil, EvalEarlyExitError{}
		}
		return nil, diags.Err()
	}

	if val.IsKnown() && !val.IsNull() {
		state.SetOutputValue(addr, val, n.Sensitive)
	} else {
		state.RemoveOutputValue(addr)
	}

	if changes != nil {
		// For the moment we are not properly tracking changes to output
		// values, and just marking them always as "Create" or "Destroy"
		// actions. A future release will rework the output lifecycle so we
		// can track their changes properly, in a similar way to how we work
		// with resource instances.

		var change *plans.OutputChange
		if !val.IsNull() {
			change = &plans.OutputChange{
				Addr:      addr,
				Sensitive: n.Sensitive,
				Change: plans.Change{
					Action: plans.Create,
					Before: cty.NullVal(cty.DynamicPseudoType),
					After:  val,
				},
			}
		} else {
			change = &plans.OutputChange{
				Addr:      addr,
				Sensitive: n.Sensitive,
				Change: plans.Change{
					// This is just a weird placeholder delete action since
					// we don't have an actual prior value to indicate.
					// FIXME: Generate real planned changes for output values
					// that include the old values.
					Action: plans.Delete,
					Before: cty.NullVal(cty.DynamicPseudoType),
					After:  cty.NullVal(cty.DynamicPseudoType),
				},
			}
		}

		cs, err := change.Encode()
		if err != nil {
			// Should never happen, since we just constructed this right above
			panic(fmt.Sprintf("planned change for %s could not be encoded: %s", addr, err))
		}
		changes.AppendOutputChange(cs)
	}

	return nil, nil
}
<commit_msg>core: EvalWriteOutput discard unknown values before writing state<commit_after>package terraform

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/plans"
)

// EvalDeleteOutput is an EvalNode implementation that deletes an output
// from the state.
type EvalDeleteOutput struct {
	Addr addrs.OutputValue
}

// TODO: test
func (n *EvalDeleteOutput) Eval(ctx EvalContext) (interface{}, error) {
	state := ctx.State()
	if state == nil {
		return nil, nil
	}

	state.RemoveOutputValue(n.Addr.Absolute(ctx.Path()))
	return nil, nil
}

// EvalWriteOutput is an EvalNode implementation that writes the output
// for the given name to the current state.
type EvalWriteOutput struct {
	Addr      addrs.OutputValue
	Sensitive bool
	Expr      hcl.Expression
	// ContinueOnErr allows interpolation to fail during Input
	ContinueOnErr bool
}

// TODO: test
func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
	addr := n.Addr.Absolute(ctx.Path())

	// This has to run before we have a state lock, since evaluation also
	// reads the state
	val, diags := ctx.EvaluateExpr(n.Expr, cty.DynamicPseudoType, nil)
	// We'll handle errors below, after we have loaded the module.

	state := ctx.State()
	if state == nil {
		return nil, nil
	}

	changes := ctx.Changes() // may be nil, if we're not working on a changeset

	// handling the interpolation error
	if diags.HasErrors() {
		if n.ContinueOnErr || flagWarnOutputErrors {
			log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr.Name, diags.Err())
			// if we're continuing, make sure the output is included, and
			// marked as unknown. If the evaluator was able to find a type
			// for the value in spite of the error then we'll use it.
			state.SetOutputValue(addr, cty.UnknownVal(val.Type()), n.Sensitive)
			return nil, EvalEarlyExitError{}
		}
		return nil, diags.Err()
	}

	if val.IsKnown() && !val.IsNull() {
		// The state itself doesn't represent unknown values, so we null them
		// out here and then we'll save the real unknown value in the planned
		// changeset below, if we have one on this graph walk.
		stateVal := cty.UnknownAsNull(val)
		state.SetOutputValue(addr, stateVal, n.Sensitive)
	} else {
		state.RemoveOutputValue(addr)
	}

	if changes != nil {
		// For the moment we are not properly tracking changes to output
		// values, and just marking them always as "Create" or "Destroy"
		// actions. A future release will rework the output lifecycle so we
		// can track their changes properly, in a similar way to how we work
		// with resource instances.

		var change *plans.OutputChange
		if !val.IsNull() {
			change = &plans.OutputChange{
				Addr:      addr,
				Sensitive: n.Sensitive,
				Change: plans.Change{
					Action: plans.Create,
					Before: cty.NullVal(cty.DynamicPseudoType),
					After:  val,
				},
			}
		} else {
			change = &plans.OutputChange{
				Addr:      addr,
				Sensitive: n.Sensitive,
				Change: plans.Change{
					// This is just a weird placeholder delete action since
					// we don't have an actual prior value to indicate.
					// FIXME: Generate real planned changes for output values
					// that include the old values.
					Action: plans.Delete,
					Before: cty.NullVal(cty.DynamicPseudoType),
					After:  cty.NullVal(cty.DynamicPseudoType),
				},
			}
		}

		cs, err := change.Encode()
		if err != nil {
			// Should never happen, since we just constructed this right above
			panic(fmt.Sprintf("planned change for %s could not be encoded: %s", addr, err))
		}
		changes.AppendOutputChange(cs)
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package evaluator

import (
	"github.com/st0012/rooby/object"
	"testing"
)

func TestSelfExpression(t *testing.T) {
	tests := []struct {
		input        string
		expected_obj string
	}{
		{`self`, object.MAIN_OBJ},
		{
			`
			class Bar {
				def whoami() {
					self
				}
			}

			Bar.new.whoami;
		`, object.BASE_OBJECT_OBJ},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
		}

		if string(evaluated.Type()) != tt.expected_obj {
			t.Fatalf("expect self to return %s. got=%s", string(tt.expected_obj), evaluated.Type())
		}
	}
}

func TestEvalInstanceVariable(t *testing.T) {
	input := `
		class Foo {
			def set(x) {
				let @x = x;
			}

			def get() {
				@x
			}

			def double_get() {
				self.get() * 2;
			}
		}

		class Bar {
			def set(x) {
				let @x = x;
			}

			def get() {
				@x
			}
		}

		let f1 = Foo.new;
		f1.set(10);

		let f2 = Foo.new;
		f2.set(20);

		let b = Bar.new;
		b.set(10)

		f2.double_get() + f1.get() + b.get();
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
	}

	result, ok := evaluated.(*object.Integer)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 60 {
		t.Fatalf("expect result to be 60. got=%d", result.Value)
	}
}

func TestEvalInstanceMethodCall(t *testing.T) {
	input := `
		class Foo {
			def add(x, y) {
				x + y
			}
		}
		Foo.new.add(10, 11)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
	}

	result, ok := evaluated.(*object.Integer)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 21 {
		t.Errorf("expect result to be 21. got=%d", result.Value)
	}
}

func TestEvalInfixIntegerExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"5", 5},
		{"10", 10},
		{"-5", -5},
		{"-10", -10},
		{"5 + 5 + 5 + 5 - 10", 10},
		{"2 * 2 * 2 * 2 * 2", 32},
		{"-50 + 100 + -50", 0},
		{"5 * 2 + 10", 20},
		{"5 + 2 * 10", 25},
		{"20 + 2 * -10", 0},
		{"50 / 2 * 2 + 10", 60},
		{"2 * (5 + 10)", 30},
		{"3 * 3 * 3 + 10", 37},
		{"3 * (3 * 3) + 10", 37},
		{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalIfExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`if (10 > 5) {
				100
			} else {
				-10
			}
			`,
			100,
		},
		{
			`if (5 != 5) {
				false
			} else {
				true
			}
			`,
			true,
		},
		{"if (true) { 10 }", 10},
		{"if (false) { 10 }", nil},
		{"if (1) { 10 }", 10},
		{"if (1 < 2) { 10 }", 10},
		{"if (1 > 2) { 10 }", nil},
		{"if (1 > 2) { 10 } else { 20 }", 20},
		{"if (1 < 2) { 10 } else { 20 }", 10},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		switch tt.expected.(type) {
		case int64:
			testIntegerObject(t, evaluated, tt.expected.(int64))
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case nil:
			testNullObject(t, evaluated)
		}

	}
}

func TestEvalBooleanExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"true", true},
		{"false", false},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalInfixStringExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{`"Stan " + "Lo"`, "Stan Lo"},
		{`"Dog" + "&" + "Cat"`, "Dog&Cat"},
		{`"Dog" == "Dog"`, true},
		{`"1234" > "123"`, true},
		{`"1234" < "123"`, false},
		{`"1234" != "123"`, true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		switch tt.expected.(type) {
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case string:
			testStringObject(t, evaluated, tt.expected.(string))
		}
	}
}

func TestEvalInfixBooleanExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"true", true},
		{"false", false},
		{"1 < 2", true},
		{"1 > 2", false},
		{"1 < 1", false},
		{"1 > 1", false},
		{"1 == 1", true},
		{"1 != 1", false},
		{"1 == 2", false},
		{"1 != 2", true},
		{"true == true", true},
		{"false == false", true},
		{"true == false", false},
		{"true != false", true},
		{"false != true", true},
		{"(1 < 2) == true", true},
		{"(1 < 2) == false", false},
		{"(1 > 2) == true", false},
		{"(1 > 2) == false", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalBangPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"!5", false},
		{"!true", false},
		{"!false", true},
		{"!!true", true},
		{"!!false", false},
		{"!!5", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalMinusPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"-5", -5},
		{"-10", -10},
		{"--10", 10},
		{"--5", 5},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalIntegerExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"5", 5},
		{"10", 10},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalStringExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{`"st0012"`, "st0012"},
		{`'Monkey'`, "Monkey"},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testStringObject(t, evaluated, tt.expected)
	}
}
<commit_msg>Improve self expression's test.<commit_after>package evaluator

import (
	"github.com/st0012/rooby/object"
	"testing"
)

func TestSelfExpression(t *testing.T) {
	tests := []struct {
		input        string
		expected_obj string
	}{
		{`self`, object.MAIN_OBJ},
		{
			`
			class Bar {
				def whoami() {
					self
				}
			}

			Bar.new.whoami;
		`, object.BASE_OBJECT_OBJ},
		{
			`
			class Foo {
				self;
			}
			`,
			object.CLASS_OBJ},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		if isError(evaluated) {
			t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
		}

		if string(evaluated.Type()) != tt.expected_obj {
			t.Fatalf("expect self to return %s. got=%s", string(tt.expected_obj), evaluated.Type())
		}
	}
}

func TestEvalInstanceVariable(t *testing.T) {
	input := `
		class Foo {
			def set(x) {
				let @x = x;
			}

			def get() {
				@x
			}

			def double_get() {
				self.get() * 2;
			}
		}

		class Bar {
			def set(x) {
				let @x = x;
			}

			def get() {
				@x
			}
		}

		let f1 = Foo.new;
		f1.set(10);

		let f2 = Foo.new;
		f2.set(20);

		let b = Bar.new;
		b.set(10)

		f2.double_get() + f1.get() + b.get();
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
	}

	result, ok := evaluated.(*object.Integer)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 60 {
		t.Fatalf("expect result to be 60. got=%d", result.Value)
	}
}

func TestEvalInstanceMethodCall(t *testing.T) {
	input := `
		class Foo {
			def add(x, y) {
				x + y
			}
		}
		Foo.new.add(10, 11)
	`

	evaluated := testEval(t, input)

	if isError(evaluated) {
		t.Fatalf("got Error: %s", evaluated.(*object.Error).Message)
	}

	result, ok := evaluated.(*object.Integer)

	if !ok {
		t.Errorf("expect result to be an integer. got=%T", evaluated)
	}

	if result.Value != 21 {
		t.Errorf("expect result to be 21. got=%d", result.Value)
	}
}

func TestEvalInfixIntegerExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"5", 5},
		{"10", 10},
		{"-5", -5},
		{"-10", -10},
		{"5 + 5 + 5 + 5 - 10", 10},
		{"2 * 2 * 2 * 2 * 2", 32},
		{"-50 + 100 + -50", 0},
		{"5 * 2 + 10", 20},
		{"5 + 2 * 10", 25},
		{"20 + 2 * -10", 0},
		{"50 / 2 * 2 + 10", 60},
		{"2 * (5 + 10)", 30},
		{"3 * 3 * 3 + 10", 37},
		{"3 * (3 * 3) + 10", 37},
		{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalIfExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{
			`if (10 > 5) {
				100
			} else {
				-10
			}
			`,
			100,
		},
		{
			`if (5 != 5) {
				false
			} else {
				true
			}
			`,
			true,
		},
		{"if (true) { 10 }", 10},
		{"if (false) { 10 }", nil},
		{"if (1) { 10 }", 10},
		{"if (1 < 2) { 10 }", 10},
		{"if (1 > 2) { 10 }", nil},
		{"if (1 > 2) { 10 } else { 20 }", 20},
		{"if (1 < 2) { 10 } else { 20 }", 10},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)

		switch tt.expected.(type) {
		case int64:
			testIntegerObject(t, evaluated, tt.expected.(int64))
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case nil:
			testNullObject(t, evaluated)
		}

	}
}

func TestEvalBooleanExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"true", true},
		{"false", false},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalInfixStringExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected interface{}
	}{
		{`"Stan " + "Lo"`, "Stan Lo"},
		{`"Dog" + "&" + "Cat"`, "Dog&Cat"},
		{`"Dog" == "Dog"`, true},
		{`"1234" > "123"`, true},
		{`"1234" < "123"`, false},
		{`"1234" != "123"`, true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		switch tt.expected.(type) {
		case bool:
			testBooleanObject(t, evaluated, tt.expected.(bool))
		case string:
			testStringObject(t, evaluated, tt.expected.(string))
		}
	}
}

func TestEvalInfixBooleanExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"true", true},
		{"false", false},
		{"1 < 2", true},
		{"1 > 2", false},
		{"1 < 1", false},
		{"1 > 1", false},
		{"1 == 1", true},
		{"1 != 1", false},
		{"1 == 2", false},
		{"1 != 2", true},
		{"true == true", true},
		{"false == false", true},
		{"true == false", false},
		{"true != false", true},
		{"false != true", true},
		{"(1 < 2) == true", true},
		{"(1 < 2) == false", false},
		{"(1 > 2) == true", false},
		{"(1 > 2) == false", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalBangPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"!5", false},
		{"!true", false},
		{"!false", true},
		{"!!true", true},
		{"!!false", false},
		{"!!5", true},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testBooleanObject(t, evaluated, tt.expected)
	}
}

func TestEvalMinusPrefixExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"-5", -5},
		{"-10", -10},
		{"--10", 10},
		{"--5", 5},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalIntegerExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected int64
	}{
		{"5", 5},
		{"10", 10},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testIntegerObject(t, evaluated, tt.expected)
	}
}

func TestEvalStringExpression(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{`"st0012"`, "st0012"},
		{`'Monkey'`, "Monkey"},
	}

	for _, tt := range tests {
		evaluated := testEval(t, tt.input)
		testStringObject(t, evaluated, tt.expected)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"os"
	"path/filepath"
	"sort"
)

type DirTreeMap map[string][]string

//type DirTreeMap map[string][]os.FileInfo

/*
Check for changes between two DirTreeMaps. If the second map is Nil, it will rescan the folders to update to the state of the filesystem.
If it is not nil, it will not be updated. The updated state will be either the state of the filesystem or the value passed in for newState
*/
func checkForChanges(basePath string, originalState, newState DirTreeMap) (changed bool, updatedState DirTreeMap, newPaths, deletedPaths, matchingPaths []string) {
	var err error
	if newState == nil {
		updatedState, err = createListOfFolders(basePath)
		if err != nil {
			panic(err)
		}
	} else {
		updatedState = newState
	}

	// Get a list of paths and compare them
	originalPaths := make([]string, 0, len(originalState))
	updatedPaths := make([]string, 0, len(updatedState))

	//todo this should already be sorted. This is very repetitive.
	for key := range originalState {
		originalPaths = append(originalPaths, key)
	}
	sort.Strings(originalPaths)

	for key := range updatedState {
		updatedPaths = append(updatedPaths, key)
	}
	sort.Strings(updatedPaths)
	//todo we should leverage the updated paths to obliviate the need to resort.

	// We now have two sorted lists of strings. Go through the original ones and compare the files
	var originalPosition, updatedPosition int

	deletedPaths = make([]string, 0, 100)
	newPaths = make([]string, 0, 100)
	matchingPaths = make([]string, 0, len(originalPaths))

	//pp := func(name string, stringList []string) {
	//	fmt.Println("***************************")
	//	fmt.Println(name)
	//	fmt.Println("***************************")
	//	for index, value := range stringList {
	//		fmt.Printf("[%3d]: %s\n", index, value)
	//	}
	//	fmt.Println("***************************")
	//}
	//pp("original paths", originalPaths)
	//pp("updated Paths", updatedPaths)

	for {
		//fmt.Printf("Original Position %3d    Updated Position %3d\n", originalPosition, updatedPosition)
		if originalPosition >= len(originalPaths) {
			// all remaining updated paths are new
			newPaths = append(newPaths, updatedPaths[updatedPosition:]...)
			//fmt.Println("Adding remaining paths")
			break
		} else if updatedPosition >= len(updatedPaths) {
			// all remaining original paths are new
			//fmt.Println("Deleting remaining paths")
			deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
			break
		} else {
			oldPath := originalPaths[originalPosition]
			updPath := updatedPaths[updatedPosition]
			//fmt.Printf("comparing paths: '%s' and '%s'\n", oldPath, updPath)

			// Start with nothing changed. Base case
			if oldPath == updPath {
				//fmt.Println("match")
				matchingPaths = append(matchingPaths, updatedPaths[updatedPosition])
				updatedPosition++
				originalPosition++
			} else if oldPath > updPath {
				//fmt.Println("adding new path")
				newPaths = append(newPaths, updatedPaths[updatedPosition])
				updatedPosition++
			} else {
				//fmt.Println("Deleting old path")
				deletedPaths = append(deletedPaths, originalPaths[originalPosition])
				originalPosition++
			}
		}
	}

	//fmt.Printf("Path report: new %d, deleted %d, matching %d, original %d, updated %d\n", len(newPaths), len(deletedPaths), len(matchingPaths), len(originalPaths), len(updatedPaths))
	//fmt.Printf("New paths: %v\n", newPaths)
	//fmt.Printf("Deleted paths: %v\n", deletedPaths)

	if len(newPaths) > 0 || len(deletedPaths) > 0 {
		changed = true
	}

	return changed, updatedState, newPaths, deletedPaths, matchingPaths
}
func createListOfFolders(basePath string) (DirTreeMap, error) {
	//paths := make([]string, 0, 100)
	pendingPaths := make([]string, 0, 100)
	pendingPaths = append(pendingPaths, basePath)
	listOfFileInfo := make(DirTreeMap)

	for len(pendingPaths) > 0 {
		currentPath := pendingPaths[0]
		// Strip off of the base path before adding it to the list of folders
		//paths = append(paths, currentPath[len(globalSettings.Directory)+1:])
		fileList := make([]string, 0, 100)
		//fileList := make([]os.FileInfo, 0, 100)
		pendingPaths = pendingPaths[1:]

		// Read the directories in the path
		f, err := os.Open(currentPath)
		if err != nil {
			return nil, err
		}
		dirEntries, err := f.Readdir(-1)
		for _, entry := range dirEntries {
			if entry.IsDir() {
				entry.Mode()
				newDirectory := filepath.Join(currentPath, entry.Name())
				//newDirectory := filepath.Join(currentPath, entry)
				pendingPaths = append(pendingPaths, newDirectory)
			} else {
				fileList = append(fileList, entry.Name())
			}
		}
		f.Close()
		if err != nil {
			return nil, err
		}

		sort.Strings(fileList)
		listOfFileInfo[currentPath] = fileList
	}

	//fmt.Printf("Export:\n")
	//for dir, _ := range listOfFileInfo {
	//	fmt.Printf("%s\n", dir)
	//}
	//fmt.Printf("Export done:\n")

	return listOfFileInfo, nil
}
<commit_msg>add directorytreemap clone function<commit_after>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"os"
	"path/filepath"
	"sort"
)

type DirTreeMap map[string][]string

// create a clone of the treemap
func (orig DirTreeMap) clone() (clone DirTreeMap) {
	clone = make(DirTreeMap)
	for k, v := range orig {
		cloneV := make([]string, len(v))
		for i, str := range v {
			cloneV[i] = str
		}
		clone[k] = cloneV
	}

	return
}

//type DirTreeMap map[string][]os.FileInfo

/*
Check for changes between two DirTreeMaps. If the second map is Nil, it will rescan the folders to update to the state of the filesystem.
If it is not nil, it will not be updated. The updated state will be either the state of the filesystem or the value passed in for newState
*/
func checkForChanges(basePath string, originalState, newState DirTreeMap) (changed bool, updatedState DirTreeMap, newPaths, deletedPaths, matchingPaths []string) {
	var err error
	if newState == nil {
		updatedState, err = createListOfFolders(basePath)
		if err != nil {
			panic(err)
		}
	} else {
		updatedState = newState.clone()
	}

	// Get a list of paths and compare them
	originalPaths := make([]string, 0, len(originalState))
	updatedPaths := make([]string, 0, len(updatedState))

	//todo this should already be sorted. This is very repetitive.
	for key := range originalState {
		originalPaths = append(originalPaths, key)
	}
	sort.Strings(originalPaths)

	for key := range updatedState {
		updatedPaths = append(updatedPaths, key)
	}
	sort.Strings(updatedPaths)
	//todo we should leverage the updated paths to obliviate the need to resort.

	// We now have two sorted lists of strings. Go through the original ones and compare the files
	var originalPosition, updatedPosition int

	deletedPaths = make([]string, 0, 100)
	newPaths = make([]string, 0, 100)
	matchingPaths = make([]string, 0, len(originalPaths))

	//pp := func(name string, stringList []string) {
	//	fmt.Println("***************************")
	//	fmt.Println(name)
	//	fmt.Println("***************************")
	//	for index, value := range stringList {
	//		fmt.Printf("[%3d]: %s\n", index, value)
	//	}
	//	fmt.Println("***************************")
	//}
	//pp("original paths", originalPaths)
	//pp("updated Paths", updatedPaths)

	for {
		//fmt.Printf("Original Position %3d    Updated Position %3d\n", originalPosition, updatedPosition)
		if originalPosition >= len(originalPaths) {
			// all remaining updated paths are new
			newPaths = append(newPaths, updatedPaths[updatedPosition:]...)
			//fmt.Println("Adding remaining paths")
			break
		} else if updatedPosition >= len(updatedPaths) {
			// all remaining original paths are new
			//fmt.Println("Deleting remaining paths")
			deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
			break
		} else {
			oldPath := originalPaths[originalPosition]
			updPath := updatedPaths[updatedPosition]
			//fmt.Printf("comparing paths: '%s' and '%s'\n", oldPath, updPath)

			// Start with nothing changed. Base case
			if oldPath == updPath {
				//fmt.Println("match")
				matchingPaths = append(matchingPaths, updatedPaths[updatedPosition])
				updatedPosition++
				originalPosition++
			} else if oldPath > updPath {
				//fmt.Println("adding new path")
				newPaths = append(newPaths, updatedPaths[updatedPosition])
				updatedPosition++
			} else {
				//fmt.Println("Deleting old path")
				deletedPaths = append(deletedPaths, originalPaths[originalPosition])
				originalPosition++
			}
		}
	}

	//fmt.Printf("Path report: new %d, deleted %d, matching %d, original %d, updated %d\n", len(newPaths), len(deletedPaths), len(matchingPaths), len(originalPaths), len(updatedPaths))
	//fmt.Printf("New paths: %v\n", newPaths)
	//fmt.Printf("Deleted paths: %v\n", deletedPaths)

	if len(newPaths) > 0 || len(deletedPaths) > 0 {
		changed = true
	}

	return changed, updatedState, newPaths, deletedPaths, matchingPaths
}
func createListOfFolders(basePath string) (DirTreeMap, error) {
	//paths := make([]string, 0, 100)
	pendingPaths := make([]string, 0, 100)
	pendingPaths = append(pendingPaths, basePath)
	listOfFileInfo := make(DirTreeMap)

	for len(pendingPaths) > 0 {
		currentPath := pendingPaths[0]
		// Strip off of the base path before adding it to the list of folders
		//paths = append(paths, currentPath[len(globalSettings.Directory)+1:])
		fileList := make([]string, 0, 100)
		//fileList := make([]os.FileInfo, 0, 100)
		pendingPaths = pendingPaths[1:]

		// Read the directories in the path
		f, err := os.Open(currentPath)
		if err != nil {
			return nil, err
		}
		dirEntries, err := f.Readdir(-1)
		for _, entry := range dirEntries {
			if entry.IsDir() {
				entry.Mode()
				newDirectory := filepath.Join(currentPath, entry.Name())
				//newDirectory := filepath.Join(currentPath, entry)
				pendingPaths = append(pendingPaths, newDirectory)
			} else {
				fileList = append(fileList, entry.Name())
			}
		}
		f.Close()
		if err != nil {
			return nil, err
		}

		sort.Strings(fileList)
		listOfFileInfo[currentPath] = fileList
	}

	//fmt.Printf("Export:\n")
	//for dir, _ := range listOfFileInfo {
	//	fmt.Printf("%s\n", dir)
	//}
	//fmt.Printf("Export done:\n")

	return listOfFileInfo, nil
}
<|endoftext|>


<commit_before>package space_test

import (
	. "cf/commands/space"
	"cf/models"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testassert "testhelpers/assert"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
)

func callRenameSpace(args []string, reqFactory *testreq.FakeReqFactory, spaceRepo *testapi.FakeSpaceRepository) (ui *testterm.FakeUI) {
	ui = new(testterm.FakeUI)
	ctxt := testcmd.NewContext("create-space", args)
	configRepo := testconfig.NewRepositoryWithDefaults()
	cmd := NewRenameSpace(ui, configRepo, spaceRepo)
	testcmd.RunCommand(cmd, ctxt, reqFactory)
	return
}

var _ = Describe("Testing with ginkgo", func() {

	It("TestRenameSpaceFailsWithUsage", func() {
		reqFactory := &testreq.FakeReqFactory{}
		spaceRepo := &testapi.FakeSpaceRepository{}

		ui := callRenameSpace([]string{}, reqFactory, spaceRepo)
		Expect(ui.FailedWithUsage).To(BeTrue())

		ui = callRenameSpace([]string{"foo"}, reqFactory, spaceRepo)
		Expect(ui.FailedWithUsage).To(BeTrue())
	})

	It("TestRenameSpaceRequirements", func() {

		spaceRepo := &testapi.FakeSpaceRepository{}

		reqFactory := &testreq.FakeReqFactory{LoginSuccess: false, TargetedOrgSuccess: true}
		callRenameSpace([]string{"my-space", "my-new-space"}, reqFactory, spaceRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeFalse())

		reqFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedOrgSuccess: false}
		callRenameSpace([]string{"my-space", "my-new-space"}, reqFactory, spaceRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeFalse())

		reqFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedOrgSuccess: true}
		callRenameSpace([]string{"my-space", "my-new-space"}, reqFactory, spaceRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeTrue())
		Expect(reqFactory.SpaceName).To(Equal("my-space"))
	})

	It("TestRenameSpaceRun", func() {
		spaceRepo := &testapi.FakeSpaceRepository{}
		space := models.Space{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"
		reqFactory := &testreq.FakeReqFactory{LoginSuccess: true, TargetedOrgSuccess: true, Space: space}
		ui := callRenameSpace([]string{"my-space", "my-new-space"}, reqFactory, spaceRepo)

		testassert.SliceContains(ui.Outputs, testassert.Lines{
			{"Renaming space", "my-space", "my-new-space", "my-org", "my-user"},
			{"OK"},
		})

		Expect(spaceRepo.RenameSpaceGuid).To(Equal("my-space-guid"))
		Expect(spaceRepo.RenameNewName).To(Equal("my-new-space"))
	})
})
<commit_msg>Cleanup rename-space test<commit_after>package space_test

import (
	. "cf/commands/space"
	"cf/models"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	testapi "testhelpers/api"
	testassert "testhelpers/assert"
	testcmd "testhelpers/commands"
	testconfig "testhelpers/configuration"
	testreq "testhelpers/requirements"
	testterm "testhelpers/terminal"
	"cf/configuration"
)

var _ = Describe("rename-space command", func() {
	var (
		ui *testterm.FakeUI
		configRepo configuration.ReadWriter
		reqFactory *testreq.FakeReqFactory
		spaceRepo *testapi.FakeSpaceRepository
	)

	BeforeEach(func() {
		ui = new(testterm.FakeUI)
		configRepo = testconfig.NewRepositoryWithDefaults()
		reqFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedOrgSuccess: true}
		spaceRepo = &testapi.FakeSpaceRepository{}
	})

	var callRenameSpace = func(args []string) {
		cmd := NewRenameSpace(ui, configRepo, spaceRepo)
		testcmd.RunCommand(cmd, testcmd.NewContext("create-space", args), reqFactory)
	}

	Describe("when the user is not logged in", func() {
		It("does not pass requirements", func() {
			reqFactory.LoginSuccess = false
			callRenameSpace([]string{"my-space", "my-new-space"})
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Describe("when the user has not targeted an org", func() {
		It("does not pass requirements", func() {
			reqFactory.TargetedOrgSuccess = false
			callRenameSpace([]string{"my-space", "my-new-space"})
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Describe("when the user provides fewer than two args", func() {
		It("fails with usage", func() {
			callRenameSpace([]string{"foo"})
			Expect(ui.FailedWithUsage).To(BeTrue())
		})
	})

	It("renames a space", func() {
		space := models.Space{}
		space.Name = "my-space"
		space.Guid = "my-space-guid"
		reqFactory.Space = space

		callRenameSpace([]string{"my-space", "my-new-space"})

		testassert.SliceContains(ui.Outputs, testassert.Lines{
			{"Renaming space", "my-space", "my-new-space", "my-org", "my-user"},
			{"OK"},
		})

		Expect(spaceRepo.RenameSpaceGuid).To(Equal("my-space-guid"))
		Expect(spaceRepo.RenameNewName).To(Equal("my-new-space"))
	})
})
<|endoftext|>


<commit_before>package cli_plugin

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"lib/marshal"
	"log"
	"netman-agent/models"
	"os"
	"strconv"
	"text/tabwriter"

	"github.com/cloudfoundry/cli/plugin"
)

type Plugin struct {
	Marshaler   marshal.Marshaler
	Unmarshaler marshal.Unmarshaler
}

type ValidArgs struct {
	SourceAppGuid string
	DestAppGuid   string
	Protocol      string
	Port          int
}

const AllowCommand = "allow-access"
const ListCommand = "list-access"
const DenyCommand = "deny-access"

func (p *Plugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "network-policy",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 0,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 15,
		},
		Commands: []plugin.Command{
			plugin.Command{
				Name:     AllowCommand,
				HelpText: "Allow direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf allow-access SOURCE_APP DESTINATION_APP --protocol <tcp|udp> --port [1-65535]",
				},
			},
			plugin.Command{
				Name:     ListCommand,
				HelpText: "List policy for direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf list-access",
				},
			},
			plugin.Command{
				Name:     DenyCommand,
				HelpText: "Remove direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf deny-access SOURCE_APP DESTINATION_APP --protocol <tcp|udp> --port [1-65535]",
				},
			},
		},
	}
}

func (p *Plugin) Run(cliConnection plugin.CliConnection, args []string) {
	logger := log.New(os.Stdout, "", 0)

	output, err := p.RunWithErrors(cliConnection, args)
	if err != nil {
		logger.Fatalf("%s", err)
	}

	logger.Print(output)
}

func (p *Plugin) RunWithErrors(cliConnection plugin.CliConnection, args []string) (string, error) {
	switch args[0] {
	case AllowCommand:
		return p.AllowCommand(cliConnection, args)
	case ListCommand:
		return p.ListCommand(cliConnection, args)
	case DenyCommand:
		return p.DenyCommand(cliConnection, args)
	}

	return "", nil
}

func (p *Plugin) ListCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	flags := flag.NewFlagSet("cf list-policies", flag.ContinueOnError)
	appName := flags.String("app", "", "app name to filter results")
	flags.Parse(args[1:])

	path := "/networking/v0/external/policies"
	if *appName != "" {
		app, err := cliConnection.GetApp(*appName)
		if err != nil {
			return "", fmt.Errorf("getting app: %s", err)
		}
		path = fmt.Sprintf("%s?id=%s", path, app.Guid)
	}

	apps, err := cliConnection.GetApps()
	if err != nil {
		return "", fmt.Errorf("getting apps: %s", err)
	}

	var policiesResponse = struct {
		Policies []models.Policy `json:"policies"`
	}{}

	policiesJSON, err := cliConnection.CliCommandWithoutTerminalOutput("curl", path)
	if err != nil {
		return "", fmt.Errorf("getting policies: %s", err)
	}

	output := bytes.NewBuffer([]byte{})
	tabWriter := new(tabwriter.Writer)
	tabWriter.Init(output, 0, 8, 2, '\t', 0)
	fmt.Fprintln(tabWriter, "Source\tDestination\tProtocol\tPort")
	err = p.Unmarshaler.Unmarshal([]byte(policiesJSON[0]), &policiesResponse)
	if err != nil {
		return "", fmt.Errorf("unmarshaling: %s", err)
	}
	policies := policiesResponse.Policies

	for _, policy := range policies {
		srcName := ""
		dstName := ""
		for _, app := range apps {
			if policy.Source.ID == app.Guid {
				srcName = app.Name
			}
			if policy.Destination.ID == app.Guid {
				dstName = app.Name
			}
		}
		if srcName != "" && dstName != "" {
			fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%d\n", srcName, dstName, policy.Destination.Protocol, policy.Destination.Port)
		}
	}

	tabWriter.Flush()
	outBytes, err := ioutil.ReadAll(output)
	if err != nil {
		//untested
		return "", fmt.Errorf("formatting output: %s", err)
	}

	return string(outBytes), nil
}

func (p *Plugin) AllowCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	validArgs, err := ValidateArgs(cliConnection, args)
	if err != nil {
		return "", err
	}

	policy := models.Policy{
		Source: models.Source{
			ID: validArgs.SourceAppGuid,
		},
		Destination: models.Destination{
			ID:       validArgs.DestAppGuid,
			Protocol: validArgs.Protocol,
			Port:     validArgs.Port,
		},
	}

	var policies = struct {
		Policies []models.Policy `json:"policies"`
	}{
		[]models.Policy{policy},
	}

	payload, err := p.Marshaler.Marshal(policies)
	if err != nil {
		return "", fmt.Errorf("payload cannot be marshaled: %s", err)
	}

	_, err = cliConnection.CliCommandWithoutTerminalOutput(
		"curl", "-X", "POST", "/networking/v0/external/policies", "-d", "'"+string(payload)+"'",
	)
	if err != nil {
		return "", fmt.Errorf("policy creation failed: %s", err)
	}

	return "", nil
}

func (p *Plugin) DenyCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	validArgs, err := ValidateArgs(cliConnection, args)
	if err != nil {
		panic(err)
	}

	policy := models.Policy{
		Source: models.Source{
			ID: validArgs.SourceAppGuid,
		},
		Destination: models.Destination{
			ID:       validArgs.DestAppGuid,
			Protocol: validArgs.Protocol,
			Port:     validArgs.Port,
		},
	}

	var policies = struct {
		Policies []models.Policy `json:"policies"`
	}{
		[]models.Policy{policy},
	}

	payload, err := p.Marshaler.Marshal(policies)
	if err != nil {
		return "", fmt.Errorf("payload cannot be marshaled: %s", err)
	}

	_, err = cliConnection.CliCommandWithoutTerminalOutput(
		"curl", "-X", "DELETE", "/networking/v0/external/policies", "-d", "'"+string(payload)+"'",
	)
	if err != nil {
		return "", fmt.Errorf("policy creation failed: %s", err)
	}

	return "", nil
}

func ValidateArgs(cliConnection plugin.CliConnection, args []string) (ValidArgs, error) {
	validArgs := ValidArgs{}

	if len(args) < 3 {
		return ValidArgs{}, errors.New("not enough arguments")
	}
	srcAppName := args[1]
	dstAppName := args[2]

	srcAppModel, err := cliConnection.GetApp(srcAppName)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("resolving source app: %s", err)
	}
	if srcAppModel.Guid == "" {
		return ValidArgs{}, fmt.Errorf("resolving source app: %s not found", srcAppName)
	}
	validArgs.SourceAppGuid = srcAppModel.Guid

	dstAppModel, err := cliConnection.GetApp(dstAppName)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("resolving destination app: %s", err)
	}
	if dstAppModel.Guid == "" {
		return ValidArgs{}, fmt.Errorf("resolving destination app: %s not found", dstAppName)
	}
	validArgs.DestAppGuid = dstAppModel.Guid

	flags := flag.NewFlagSet("cf "+args[0]+" <src> <dest>", flag.ContinueOnError)
	protocol := flags.String("protocol", "", "the protocol allowed")
	portString := flags.String("port", "", "the destination port")
	flags.Parse(args[3:])

	if *protocol == "" {
		return ValidArgs{}, fmt.Errorf("Requires --protocol PROTOCOL as argument.")
	}
	validArgs.Protocol = *protocol

	if *portString == "" {
		return ValidArgs{}, fmt.Errorf("Requires --port PORT as argument.")
	}

	port, err := strconv.Atoi(*portString)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("port is not valid: %s", *portString)
	}
	validArgs.Port = port

	return validArgs, nil
}
<commit_msg>Fixes missing return for deny validation<commit_after>package cli_plugin

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"lib/marshal"
	"log"
	"netman-agent/models"
	"os"
	"strconv"
	"text/tabwriter"

	"github.com/cloudfoundry/cli/plugin"
)

type Plugin struct {
	Marshaler   marshal.Marshaler
	Unmarshaler marshal.Unmarshaler
}

type ValidArgs struct {
	SourceAppGuid string
	DestAppGuid   string
	Protocol      string
	Port          int
}

const AllowCommand = "allow-access"
const ListCommand = "list-access"
const DenyCommand = "deny-access"

const CLR_N = "\x1b[0m"
const CLR_R = "\x1b[31;1m"
const CLR_G = "\x1b[32;1m"

func (p *Plugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "network-policy",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 0,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 15,
		},
		Commands: []plugin.Command{
			plugin.Command{
				Name:     AllowCommand,
				HelpText: "Allow direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf allow-access SOURCE_APP DESTINATION_APP --protocol <tcp|udp> --port [1-65535]",
				},
			},
			plugin.Command{
				Name:     ListCommand,
				HelpText: "List policy for direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf list-access",
				},
			},
			plugin.Command{
				Name:     DenyCommand,
				HelpText: "Remove direct network traffic from one app to another",
				UsageDetails: plugin.Usage{
					Usage: "cf deny-access SOURCE_APP DESTINATION_APP --protocol <tcp|udp> --port [1-65535]",
				},
			},
		},
	}
}

func (p *Plugin) Run(cliConnection plugin.CliConnection, args []string) {
	logger := log.New(os.Stdout, "", 0)

	output, err := p.RunWithErrors(cliConnection, args)
	if err != nil {
		logger.Printf("%sFAILED%s", CLR_R, CLR_N)
		logger.Fatalf("%s", err)
	}

	logger.Printf("%sOK%s", CLR_G, CLR_N)
	logger.Print(output)
}

func (p *Plugin) RunWithErrors(cliConnection plugin.CliConnection, args []string) (string, error) {
	switch args[0] {
	case AllowCommand:
		return p.AllowCommand(cliConnection, args)
	case ListCommand:
		return p.ListCommand(cliConnection, args)
	case DenyCommand:
		return p.DenyCommand(cliConnection, args)
	}

	return "", nil
}

func (p *Plugin) ListCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	flags := flag.NewFlagSet("cf list-policies", flag.ContinueOnError)
	appName := flags.String("app", "", "app name to filter results")
	flags.Parse(args[1:])

	path := "/networking/v0/external/policies"
	if *appName != "" {
		app, err := cliConnection.GetApp(*appName)
		if err != nil {
			return "", fmt.Errorf("getting app: %s", err)
		}
		path = fmt.Sprintf("%s?id=%s", path, app.Guid)
	}

	apps, err := cliConnection.GetApps()
	if err != nil {
		return "", fmt.Errorf("getting apps: %s", err)
	}

	var policiesResponse = struct {
		Policies []models.Policy `json:"policies"`
	}{}

	policiesJSON, err := cliConnection.CliCommandWithoutTerminalOutput("curl", path)
	if err != nil {
		return "", fmt.Errorf("getting policies: %s", err)
	}

	output := bytes.NewBuffer([]byte{})
	tabWriter := new(tabwriter.Writer)
	tabWriter.Init(output, 0, 8, 2, '\t', 0)
	fmt.Fprintln(tabWriter, "Source\tDestination\tProtocol\tPort")
	err = p.Unmarshaler.Unmarshal([]byte(policiesJSON[0]), &policiesResponse)
	if err != nil {
		return "", fmt.Errorf("unmarshaling: %s", err)
	}
	policies := policiesResponse.Policies

	for _, policy := range policies {
		srcName := ""
		dstName := ""
		for _, app := range apps {
			if policy.Source.ID == app.Guid {
				srcName = app.Name
			}
			if policy.Destination.ID == app.Guid {
				dstName = app.Name
			}
		}
		if srcName != "" && dstName != "" {
			fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%d\n", srcName, dstName, policy.Destination.Protocol, policy.Destination.Port)
		}
	}

	tabWriter.Flush()
	outBytes, err := ioutil.ReadAll(output)
	if err != nil {
		//untested
		return "", fmt.Errorf("formatting output: %s", err)
	}

	return string(outBytes), nil
}

func (p *Plugin) AllowCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	validArgs, err := ValidateArgs(cliConnection, args)
	if err != nil {
		return "", err
	}

	policy := models.Policy{
		Source: models.Source{
			ID: validArgs.SourceAppGuid,
		},
		Destination: models.Destination{
			ID:       validArgs.DestAppGuid,
			Protocol: validArgs.Protocol,
			Port:     validArgs.Port,
		},
	}

	var policies = struct {
		Policies []models.Policy `json:"policies"`
	}{
		[]models.Policy{policy},
	}

	payload, err := p.Marshaler.Marshal(policies)
	if err != nil {
		return "", fmt.Errorf("payload cannot be marshaled: %s", err)
	}

	_, err = cliConnection.CliCommandWithoutTerminalOutput(
		"curl", "-X", "POST", "/networking/v0/external/policies", "-d", "'"+string(payload)+"'",
	)
	if err != nil {
		return "", fmt.Errorf("policy creation failed: %s", err)
	}

	return "", nil
}

func (p *Plugin) DenyCommand(cliConnection plugin.CliConnection, args []string) (string, error) {
	validArgs, err := ValidateArgs(cliConnection, args)
	if err != nil {
		return "", err
	}

	policy := models.Policy{
		Source: models.Source{
			ID: validArgs.SourceAppGuid,
		},
		Destination: models.Destination{
			ID:       validArgs.DestAppGuid,
			Protocol: validArgs.Protocol,
			Port:     validArgs.Port,
		},
	}

	var policies = struct {
		Policies []models.Policy `json:"policies"`
	}{
		[]models.Policy{policy},
	}

	payload, err := p.Marshaler.Marshal(policies)
	if err != nil {
		return "", fmt.Errorf("payload cannot be marshaled: %s", err)
	}

	_, err = cliConnection.CliCommandWithoutTerminalOutput(
		"curl", "-X", "DELETE", "/networking/v0/external/policies", "-d", "'"+string(payload)+"'",
	)
	if err != nil {
		return "", fmt.Errorf("policy creation failed: %s", err)
	}

	return "", nil
}

func ValidateArgs(cliConnection plugin.CliConnection, args []string) (ValidArgs, error) {
	validArgs := ValidArgs{}

	if len(args) < 3 {
		return ValidArgs{}, errors.New("not enough arguments")
	}
	srcAppName := args[1]
	dstAppName := args[2]

	srcAppModel, err := cliConnection.GetApp(srcAppName)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("resolving source app: %s", err)
	}
	if srcAppModel.Guid == "" {
		return ValidArgs{}, fmt.Errorf("resolving source app: %s not found", srcAppName)
	}
	validArgs.SourceAppGuid = srcAppModel.Guid

	dstAppModel, err := cliConnection.GetApp(dstAppName)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("resolving destination app: %s", err)
	}
	if dstAppModel.Guid == "" {
		return ValidArgs{}, fmt.Errorf("resolving destination app: %s not found", dstAppName)
	}
	validArgs.DestAppGuid = dstAppModel.Guid

	flags := flag.NewFlagSet("cf "+args[0]+" <src> <dest>", flag.ContinueOnError)
	protocol := flags.String("protocol", "", "the protocol allowed")
	portString := flags.String("port", "", "the destination port")
	flags.Parse(args[3:])

	if *protocol == "" {
		return ValidArgs{}, fmt.Errorf("Requires --protocol PROTOCOL as argument.")
	}
	validArgs.Protocol = *protocol

	if *portString == "" {
		return ValidArgs{}, fmt.Errorf("Requires --port PORT as argument.")
	}

	port, err := strconv.Atoi(*portString)
	if err != nil {
		return ValidArgs{}, fmt.Errorf("port is not valid: %s", *portString)
	}
	validArgs.Port = port

	return validArgs, nil
}
<|endoftext|>


<commit_before>// +build windows

package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wav"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio = &wav.File{}
	var file []byte

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&filenameFlag, "input", "Specify WAVE format audio (e.g. music.wav)")
	f.Var(&filenameFlag, "i", "Alias of --input")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}
	if file, err = ioutil.ReadFile(filenameFlag.Value); err != nil {
		return
	}
	if err = wav.Unmarshal(file, audio); err != nil {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
	}()

	if err = renderSharedEventDriven(ctx, audio); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func renderSharedEventDriven(ctx context.Context, audio *wav.File) (err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var mmde *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &mmde); err != nil {
		return
	}
	defer mmde.Release()

	var mmd *wca.IMMDevice
	if err = mmde.GetDefaultAudioEndpoint(wca.ERender, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Rendering audio to: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.NSamplesPerSec = uint32(audio.SamplesPerSec())
	wfx.WBitsPerSample = uint16(audio.BitsPerSample())
	wfx.NChannels = uint16(audio.Channels())
	wfx.NBlockAlign = uint16(audio.BlockAlign())
	wfx.NAvgBytesPerSec = uint32(audio.AvgBytesPerSec())
	wfx.CbSize = 0

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", wfx.WBitsPerSample)
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	var latency time.Duration
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	latency = time.Duration(defaultPeriod * 100)

	fmt.Println("Default period: ", defaultPeriod)
	fmt.Println("Minimum period: ", minimumPeriod)
	fmt.Println("Latency: ", latency)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_SHARED, wca.AUDCLNT_STREAMFLAGS_EVENTCALLBACK, defaultPeriod, 0, wfx, nil); err != nil {
		return
	}

	audioReadyEvent := wca.CreateEventExA(0, 0, 0, wca.EVENT_MODIFY_STATE|wca.SYNCHRONIZE)
	defer wca.CloseHandle(audioReadyEvent)

	if err = ac.SetEventHandle(audioReadyEvent); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var arc *wca.IAudioRenderClient
	if err = ac.GetService(wca.IID_IAudioRenderClient, &arc); err != nil {
		return
	}
	defer arc.Release()

	if err = ac.Start(); err != nil {
		return
	}
	fmt.Println("Start rendering audio with shared-event-driven mode")
	fmt.Println("Press Ctrl-C to stop")

	var input = audio.Bytes()
	var b *byte
	var data *byte
	var offset int
	var isPlaying bool = true
	var padding uint32
	var availableFrameSize uint32

	errorChan := make(chan error, 1)

	for {
		if !isPlaying {
			close(errorChan)
			break
		}
		go func() {
			errorChan <- watchEvent(ctx, audioReadyEvent)
		}()
		select {
		case <-ctx.Done():
			isPlaying = false
			<-errorChan
			break
		case err = <-errorChan:
			if err != nil {
				isPlaying = false
				break
			}
			if offset >= audio.Length() {
				isPlaying = false
				break
			}
			if err = ac.GetCurrentPadding(&padding); err != nil {
				return
			}
			if availableFrameSize = bufferFrameSize - padding; availableFrameSize == 0 {
				continue
			}
			if err = arc.GetBuffer(availableFrameSize, &data); err != nil {
				return
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)
			remaining := audio.Length() - offset

			if remaining < lim {
				lim = remaining
			}
			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				*b = input[offset+n]
			}

			offset += lim

			if err = arc.ReleaseBuffer(availableFrameSize, 0); err != nil {
				return
			}
		}
	}
	if err != nil {
		return
	}

// Render samples remaining in buffer.
	time.Sleep(latency)

	return ac.Stop()
}

func watchEvent(ctx context.Context, event uintptr) (err error) {
	errorChan := make(chan error, 1)
	go func() {
		errorChan <- eventEmitter(event)
	}()
	select {
	case err = <-errorChan:
		close(errorChan)
		return
	case <-ctx.Done():
		err = ctx.Err()
		return
	}
	return
}

func eventEmitter(event uintptr) (err error) {
	//if err = ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil {
	//	return
	//}
	dw := wca.WaitForSingleObject(event, wca.INFINITE)
	if dw != 0 {
		return fmt.Errorf("failed to watch event")
	}
	//ole.CoUninitialize()
	return
}
<commit_msg>refactor<commit_after>// +build windows

package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"
	"unsafe"

	"github.com/go-ole/go-ole"
	"github.com/moutend/go-wav"
	"github.com/moutend/go-wca"
)

var version = "latest"
var revision = "latest"

type FilenameFlag struct {
	Value string
}

func (f *FilenameFlag) Set(value string) (err error) {
	if !strings.HasSuffix(value, ".wav") {
		err = fmt.Errorf("specify WAVE audio file (*.wav)")
		return
	}
	f.Value = value
	return
}

func (f *FilenameFlag) String() string {
	return f.Value
}

func main() {
	var err error
	if err = run(os.Args); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) (err error) {
	var filenameFlag FilenameFlag
	var versionFlag bool
	var audio = &wav.File{}
	var file []byte

	f := flag.NewFlagSet(args[0], flag.ExitOnError)
	f.Var(&filenameFlag, "input", "Specify WAVE format audio (e.g. music.wav)")
	f.Var(&filenameFlag, "i", "Alias of --input")
	f.BoolVar(&versionFlag, "version", false, "Show version")
	f.Parse(args[1:])

	if versionFlag {
		fmt.Printf("%s-%s\n", version, revision)
		return
	}
	if filenameFlag.Value == "" {
		return
	}
	if file, err = ioutil.ReadFile(filenameFlag.Value); err != nil {
		return
	}
	if err = wav.Unmarshal(file, audio); err != nil {
		return
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		select {
		case <-signalChan:
			fmt.Println("Interrupted by SIGINT")
			cancel()
		}
	}()

	if err = renderSharedEventDriven(ctx, audio); err != nil {
		return
	}
	fmt.Println("Successfully done")
	return
}

func renderSharedEventDriven(ctx context.Context, audio *wav.File) (err error) {
	if err = ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED); err != nil {
		return
	}
	defer ole.CoUninitialize()

	var mmde *wca.IMMDeviceEnumerator
	if err = wca.CoCreateInstance(wca.CLSID_MMDeviceEnumerator, 0, wca.CLSCTX_ALL, wca.IID_IMMDeviceEnumerator, &mmde); err != nil {
		return
	}
	defer mmde.Release()

	var mmd *wca.IMMDevice
	if err = mmde.GetDefaultAudioEndpoint(wca.ERender, wca.EConsole, &mmd); err != nil {
		return
	}
	defer mmd.Release()

	var ps *wca.IPropertyStore
	if err = mmd.OpenPropertyStore(wca.STGM_READ, &ps); err != nil {
		return
	}
	defer ps.Release()

	var pv wca.PROPVARIANT
	if err = ps.GetValue(&wca.PKEY_Device_FriendlyName, &pv); err != nil {
		return
	}
	fmt.Printf("Rendering audio to: %s\n", pv.String())

	var ac *wca.IAudioClient
	if err = mmd.Activate(wca.IID_IAudioClient, wca.CLSCTX_ALL, nil, &ac); err != nil {
		return
	}
	defer ac.Release()

	var wfx *wca.WAVEFORMATEX
	if err = ac.GetMixFormat(&wfx); err != nil {
		return
	}
	defer ole.CoTaskMemFree(uintptr(unsafe.Pointer(wfx)))

	wfx.WFormatTag = 1
	wfx.NSamplesPerSec = uint32(audio.SamplesPerSec())
	wfx.WBitsPerSample = uint16(audio.BitsPerSample())
	wfx.NChannels = uint16(audio.Channels())
	wfx.NBlockAlign = uint16(audio.BlockAlign())
	wfx.NAvgBytesPerSec = uint32(audio.AvgBytesPerSec())
	wfx.CbSize = 0

	fmt.Println("--------")
	fmt.Printf("Format: PCM %d bit signed integer\n", wfx.WBitsPerSample)
	fmt.Printf("Rate: %d Hz\n", wfx.NSamplesPerSec)
	fmt.Printf("Channels: %d\n", wfx.NChannels)
	fmt.Println("--------")

	var defaultPeriod wca.REFERENCE_TIME
	var minimumPeriod wca.REFERENCE_TIME
	var latency time.Duration
	if err = ac.GetDevicePeriod(&defaultPeriod, &minimumPeriod); err != nil {
		return
	}
	latency = time.Duration(defaultPeriod * 100)

	fmt.Println("Default period: ", defaultPeriod)
	fmt.Println("Minimum period: ", minimumPeriod)
	fmt.Println("Latency: ", latency)

	if err = ac.Initialize(wca.AUDCLNT_SHAREMODE_SHARED, wca.AUDCLNT_STREAMFLAGS_EVENTCALLBACK, defaultPeriod, 0, wfx, nil); err != nil {
		return
	}

	audioReadyEvent := wca.CreateEventExA(0, 0, 0, wca.EVENT_MODIFY_STATE|wca.SYNCHRONIZE)
	defer wca.CloseHandle(audioReadyEvent)

	if err = ac.SetEventHandle(audioReadyEvent); err != nil {
		return
	}

	var bufferFrameSize uint32
	if err = ac.GetBufferSize(&bufferFrameSize); err != nil {
		return
	}
	fmt.Printf("Allocated buffer size: %d\n", bufferFrameSize)

	var arc *wca.IAudioRenderClient
	if err = ac.GetService(wca.IID_IAudioRenderClient, &arc); err != nil {
		return
	}
	defer arc.Release()

	if err = ac.Start(); err != nil {
		return
	}
	fmt.Println("Start rendering audio with shared-event-driven mode")
	fmt.Println("Press Ctrl-C to stop")

	var input = audio.Bytes()
	var b *byte
	var data *byte
	var offset int
	var isPlaying bool = true
	var padding uint32
	var availableFrameSize uint32

	errorChan := make(chan error, 1)

	for {
		if !isPlaying {
			close(errorChan)
			break
		}
		go func() {
			errorChan <- watchEvent(ctx, audioReadyEvent)
		}()
		select {
		case <-ctx.Done():
			isPlaying = false
			<-errorChan
			break
		case err = <-errorChan:
			if err != nil {
				isPlaying = false
				break
			}
			if offset >= audio.Length() {
				isPlaying = false
				break
			}
			if err = ac.GetCurrentPadding(&padding); err != nil {
				return
			}
			if availableFrameSize = bufferFrameSize - padding; availableFrameSize == 0 {
				continue
			}
			if err = arc.GetBuffer(availableFrameSize, &data); err != nil {
				return
			}

			start := unsafe.Pointer(data)
			lim := int(availableFrameSize) * int(wfx.NBlockAlign)
			remaining := audio.Length() - offset

			if remaining < lim {
				lim = remaining
			}
			for n := 0; n < lim; n++ {
				b = (*byte)(unsafe.Pointer(uintptr(start) + uintptr(n)))
				*b = input[offset+n]
			}

			offset += lim

			if err = arc.ReleaseBuffer(availableFrameSize, 0); err != nil {
				return
			}
		}
	}
	if err != nil {
		return
	}

	// Render samples remaining in buffer.
	time.Sleep(latency)

	return ac.Stop()
}

func watchEvent(ctx context.Context, event uintptr) (err error) {
	errorChan := make(chan error, 1)
	go func() {
		errorChan <- eventEmitter(event)
	}()
	select {
	case err = <-errorChan:
		close(errorChan)
		return
	case <-ctx.Done():
		err = ctx.Err()
		return
	}
	return
}

func eventEmitter(event uintptr) (err error) {
	dw := wca.WaitForSingleObject(event, wca.INFINITE)
	if dw != 0 {
		return fmt.Errorf("failed to watch event")
	}
	return
}
<|endoftext|>


<commit_before>// +build !js

package ninchat

import (
	"crypto/tls"
	"encoding/json"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

const webSocketSupported = true

var webSocketTLSConfig = &tls.Config{
	PreferServerCipherSuites: true,
}

type webSocket struct {
	notify    chan struct{}
	goingAway bool
	err       error

	conn *websocket.Conn
	lock sync.Mutex
	buf  [][]byte
}

func newWebSocket(url string, timeout duration) (ws *webSocket) {
	dialer := &websocket.Dialer{
		TLSClientConfig:  webSocketTLSConfig,
		HandshakeTimeout: time.Duration(timeout),
	}

	ws = &webSocket{
		notify: make(chan struct{}, 1),
	}

	go func() {
		defer close(ws.notify)

		if ws.conn, _, ws.err = dialer.Dial(url, nil); ws.err != nil {
			return
		}

		ws.notify <- struct{}{}

		for {
			var (
				typ  int
				data []byte
			)

			if typ, data, ws.err = ws.conn.ReadMessage(); ws.err != nil {
				// TODO: goingAway
				return
			}

			switch typ {
			case websocket.TextMessage, websocket.BinaryMessage:
				ws.lock.Lock()
				ws.buf = append(ws.buf, data)
				ws.lock.Unlock()

				select {
				case ws.notify <- struct{}{}:
				default:
				}

			default:
			}
		}
	}()

	return
}

func (ws *webSocket) send(data []byte) error {
	return ws.conn.WriteMessage(websocket.BinaryMessage, data)
}

func (ws *webSocket) sendJSON(object interface{}) error {
	return ws.conn.WriteJSON(object)
}

func (ws *webSocket) sendPayload(action *Action) (err error) {
	for _, data := range action.Payload {
		if err = ws.send(data); err != nil {
			return
		}
	}
	return
}

func (ws *webSocket) receive() (data []byte) {
	ws.lock.Lock()
	defer ws.lock.Unlock()

	if len(ws.buf) > 0 {
		data = ws.buf[0]
		ws.buf = ws.buf[1:]
	}

	return
}

func (ws *webSocket) receiveJSON() (object map[string]interface{}, err error) {
	x := ws.receive()
	if x == nil {
		return
	}

	err = json.Unmarshal(x, &object)
	return
}

func (ws *webSocket) close() {
	ws.conn.Close()
}
<commit_msg>WebSocket going away detection hack for Go<commit_after>// +build !js

package ninchat

import (
	"crypto/tls"
	"encoding/json"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

const webSocketSupported = true

var webSocketTLSConfig = &tls.Config{
	PreferServerCipherSuites: true,
}

type webSocket struct {
	notify    chan struct{}
	goingAway bool
	err       error

	conn *websocket.Conn
	lock sync.Mutex
	buf  [][]byte
}

func newWebSocket(url string, timeout duration) (ws *webSocket) {
	dialer := &websocket.Dialer{
		TLSClientConfig:  webSocketTLSConfig,
		HandshakeTimeout: time.Duration(timeout),
	}

	ws = &webSocket{
		notify: make(chan struct{}, 1),
	}

	go func() {
		defer close(ws.notify)

		if ws.conn, _, ws.err = dialer.Dial(url, nil); ws.err != nil {
			return
		}

		ws.notify <- struct{}{}

		for {
			var (
				typ  int
				data []byte
			)

			if typ, data, ws.err = ws.conn.ReadMessage(); ws.err != nil {
				// XXX: this will break eventually
				ws.goingAway = strings.HasPrefix(ws.err.Error(), "websocket: close 1001 ")
				return
			}

			switch typ {
			case websocket.TextMessage, websocket.BinaryMessage:
				ws.lock.Lock()
				ws.buf = append(ws.buf, data)
				ws.lock.Unlock()

				select {
				case ws.notify <- struct{}{}:
				default:
				}

			default:
				// XXX: is this possible?
			}
		}
	}()

	return
}

func (ws *webSocket) send(data []byte) error {
	return ws.conn.WriteMessage(websocket.BinaryMessage, data)
}

func (ws *webSocket) sendJSON(object interface{}) error {
	return ws.conn.WriteJSON(object)
}

func (ws *webSocket) sendPayload(action *Action) (err error) {
	for _, data := range action.Payload {
		if err = ws.send(data); err != nil {
			return
		}
	}
	return
}

func (ws *webSocket) receive() (data []byte) {
	ws.lock.Lock()
	defer ws.lock.Unlock()

	if len(ws.buf) > 0 {
		data = ws.buf[0]
		ws.buf = ws.buf[1:]
	}

	return
}

func (ws *webSocket) receiveJSON() (object map[string]interface{}, err error) {
	x := ws.receive()
	if x == nil {
		return
	}

	err = json.Unmarshal(x, &object)
	return
}

func (ws *webSocket) close() {
	ws.conn.Close()
}
<|endoftext|>