<commit_before>package main

import (
	"fmt"
	"math/rand"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

// UAPiece user agent generator prototype
type UAPiece interface {
	UserAgentPiece() string
	Geo() (float64, float64)
}

type geo struct{}

func (g geo) Geo() (float64, float64) {
	return 30. + rand.Float64()*30, 45. + rand.Float64()*30
}

// AndroidUA android device UAPiece generator
type AndroidUA struct {
	geo
}

var androidDevs = []string{
	"Samsung S7",
	"Samsung GT-i9000",
	"Sony XT-5",
	"Huawei-P6/2016",
	"Xiaomi Mi-6",
	"Nexus 5 32Gb",
	"Pixel 2 XL 128Gb",
}
var androidVersions = []string{
	"2.3.0",
	"8.0.0",
	"6.1.1",
	"7.1.1",
	"7.0.1",
	"5.1.9",
}

func (android AndroidUA) UserAgentPiece() string {
	index := rand.Int() % len(androidDevs)
	dev := androidDevs[index]
	index = rand.Int() % len(androidVersions)
	os := androidVersions[index]
	return fmt.Sprintf("%s Android/%s", dev, os)
}

// IPhoneUA device UAPiece generator
type IPhoneUA struct {
	geo
}

var iphoneDevices = []string{
	"iPhone 8+",
	"iPhone X",
	"iPhone 7",
	"iPhone 6s+",
	"iPhone 5",
}

var iosVersions = []string{
	"11.0.2",
	"10.1.2",
	"9.1.1",
}

func (i IPhoneUA) UserAgentPiece() string {
	index := rand.Int() % len(iphoneDevices)
	dev := iphoneDevices[index]
	index = rand.Int() % len(iosVersions)
	os := iosVersions[index]
	return fmt.Sprintf("%s iOS/%s", dev, os)
}

// WindowsUA ...
type WindowsUA struct{}

var windowsVersions = []string{
	"10.0.1",
	"7.1.1",
	"XP SP3",
	"Vista SP1",
}

func (w WindowsUA) UserAgentPiece() string {
	index := rand.Int() % len(windowsVersions)
	os := windowsVersions[index]
	return fmt.Sprintf("Windows/%s", os)
}

func (w WindowsUA) Geo() (float64, float64) {
	return 0.0, 0.0
}

// FullUA is not a UAPiece
type FullUA struct{}

var countries = []string{
	"RU", "US", "BR", "BY", "DE", "UK", "AU", "CZ", "PL", "KZ", "UA", "TZ", "NZ", "FR", "TR", "RO",
}

// UserAgent blah-blah-blah
func (fua FullUA) UserAgent(piece UAPiece) string {
	index := rand.Int() % len(countries)
	country := countries[index]
	return fmt.Sprintf("App.Com %s/%s", piece.UserAgentPiece(), country)
}

var easylines [][]byte

var START = time.Date(2015, 1, 1, 1, 1, 0, 0, time.UTC)

var users = map[string]struct{}{}

func init() {
	var pieces []UAPiece
	for i := 0; i < 20; i++ {
		pieces = append(pieces, AndroidUA{geo{}})
	}
	for i := 0; i < 3; i++ {
		pieces = append(pieces, IPhoneUA{geo{}})
	}
	for i := 0; i < 5; i++ {
		pieces = append(pieces, WindowsUA{})
	}

	// Generating userlist
	var userlist []string
	for i := 0; i < 100000; i++ {
		uid := rand.Uint64()
		barrier := uint64(10000000000)
		if uid < barrier {
			uid += barrier
		}
		userlist = append(userlist, fmt.Sprintf("%d", uid))
		users[fmt.Sprintf("%d", uid)] = struct{}{}
	}

	// Generating user agents for userlist
	type Node struct {
		UA  string
		Geo func() (float64, float64)
	}
	var agentmap = map[string]Node{}
	for _, u := range userlist {
		index := rand.Int() % len(pieces)
		node := Node{}
		node.UA = FullUA{}.UserAgent(pieces[index])
		node.Geo = pieces[index].Geo
		agentmap[u] = node
	}

	start := START
	total := 0
	for i := 0; i < 1000000; i++ {
		index := rand.Int() % len(userlist)
		gens := agentmap[userlist[index]]
		pid := rand.Int() % 65536
		line := fmt.Sprintf("[%d %s] PRESENCE uid=%s ua='%s'", pid, start.Format("2006-01-02T15:04:05"), userlist[index], gens.UA)
		lat, lon := gens.Geo()
		if lat != 0 || lon != 0 {
			line += fmt.Sprintf(" Geo={Lat: %f, Lon: %f}", lat, lon)
		}
		act := rand.Int() % 6
		line += fmt.Sprintf(" Activity=%d", act)
		easylines = append(easylines, []byte(line))
		total += len(line)
		start = start.Add(time.Second)
	}
	buf := make([]byte, total)
	offset := 0
	for i, line := range easylines {
		copy(buf[offset:], line)
		easylines[i] = buf[offset : offset+len(line)]
		offset += len(line)
	}
}

func TestRagelExtraction(t *testing.T) {
	p := &Easy{}
	f := &EasyFloat{}
	e := &PresenceFloats{}
	r := &Presence{}

	start := START
	for _, line := range easylines {
		ok, err := p.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = f.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = e.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = r.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		require.Equal(t, start.Format("2006-01-02T15:04:05"), string(p.Time))
		if _, ok := users[string(p.UID)]; !ok {
			t.Fatalf("Unknown user `\033[01m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
		}
		start = start.Add(time.Second)

		require.Equal(t, string(p.Time), string(r.Time))
		require.Equal(t, string(p.UID), string(r.UID))
		require.Equal(t, string(p.UA), string(r.UA))
		require.Equal(t, p.Geo.Valid, r.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, string(p.Geo.Lat), string(r.Geo.Lat))
			require.Equal(t, string(p.Geo.Lon), string(r.Geo.Lon))
		}
		require.Equal(t, string(p.Activity), string(r.Activity))

		require.Equal(t, string(p.Time), string(e.Time))
		require.Equal(t, string(p.UID), string(e.UID))
		require.Equal(t, string(p.UA), string(e.UA))
		require.Equal(t, p.Geo.Valid, e.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, string(p.Geo.Lat), fmt.Sprintf("%f", e.Geo.Lat))
			require.Equal(t, string(p.Geo.Lon), fmt.Sprintf("%f", e.Geo.Lon))
		}
		require.Equal(t, string(p.Activity), fmt.Sprintf("%d", e.Activity))

		require.Equal(t, string(p.Time), string(e.Time))
		require.Equal(t, string(p.UID), string(e.UID))
		require.Equal(t, string(p.UA), string(e.UA))
		require.Equal(t, p.Geo.Valid, e.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, f.Geo.Lat, e.Geo.Lat)
			require.Equal(t, f.Geo.Lon, e.Geo.Lon)
		}
		require.Equal(t, f.Activity, e.Activity)
	}
}

func BenchmarkLDEEasyRealWorld(b *testing.B) {
	p := &Presence{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkLDEEasyFloatsRealWorld(b *testing.B) {
	p := &PresenceFloats{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkRagelEasyRealWorld(b *testing.B) {
	p := &Easy{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkRagelEasyFloatsRealWorld(b *testing.B) {
	p := &EasyFloat{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}
<commit_msg>Some more data on testing (Ragel is getting slower)<commit_after>package main

import (
	"fmt"
	"math/rand"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

// UAPiece user agent generator prototype
type UAPiece interface {
	UserAgentPiece() string
	Geo() (float64, float64)
}

type geo struct{}

func (g geo) Geo() (float64, float64) {
	return 30. + rand.Float64()*30, 45. + rand.Float64()*30
}

// AndroidUA android device UAPiece generator
type AndroidUA struct {
	geo
}

var androidDevs = []string{
	"Samsung S7",
	"Samsung GT-i9000",
	"Sony XT-5",
	"Huawei-P6/2016",
	"Xiaomi Mi-6",
	"Nexus 5 32Gb",
	"Pixel 2 XL 128Gb",
}
var androidVersions = []string{
	"2.3.0",
	"8.0.0",
	"6.1.1",
	"7.1.1",
	"7.0.1",
	"5.1.9",
}

func (android AndroidUA) UserAgentPiece() string {
	index := rand.Int() % len(androidDevs)
	dev := androidDevs[index]
	index = rand.Int() % len(androidVersions)
	os := androidVersions[index]
	return fmt.Sprintf("%s Android/%s", dev, os)
}

// IPhoneUA device UAPiece generator
type IPhoneUA struct {
	geo
}

var iphoneDevices = []string{
	"iPhone 8+",
	"iPhone X",
	"iPhone 7",
	"iPhone 6s+",
	"iPhone 5",
}

var iosVersions = []string{
	"11.0.2",
	"10.1.2",
	"9.1.1",
}

func (i IPhoneUA) UserAgentPiece() string {
	index := rand.Int() % len(iphoneDevices)
	dev := iphoneDevices[index]
	index = rand.Int() % len(iosVersions)
	os := iosVersions[index]
	return fmt.Sprintf("%s iOS/%s", dev, os)
}

// WindowsUA ...
type WindowsUA struct{}

var windowsVersions = []string{
	"10.0.1",
	"7.1.1",
	"XP SP3",
	"Vista SP1",
}

func (w WindowsUA) UserAgentPiece() string {
	index := rand.Int() % len(windowsVersions)
	os := windowsVersions[index]
	return fmt.Sprintf("Windows/%s", os)
}

func (w WindowsUA) Geo() (float64, float64) {
	return 0.0, 0.0
}

// FullUA is not a UAPiece
type FullUA struct{}

var countries = []string{
	"RU/Beeline",
	"RU/MTS",
	"RU/Megafone",
	"RU/Tele2",
	"US/Verizon",
	"US/AT&T",
	"US/T-Mobile",
	"US/Sprint",
	"US/Cellular",
	"BR/Vivo",
	"BR/Nextel",
	"BR/Sercomtel",
	"BR/TIM",
	"BR/Claro",
	"BR/Algar Telecom",
	"BY/MTS",
	"BY/Megafone",
	"BY/Telecom Austria",
	"BY/Life",
	"DE/T-Mobile",
	"DE/Vodafone",
	"DE/E-Plus",
	"DE/O2",
	"UK/Vodafone",
	"UK/T-Mobile",
	"UK/O2",
	"UK/Orange",
	"UK/Three",
	"AU/Telstra",
	"AU/Optus",
	"AU/Vodafone",
	"CZ/T-Mobile",
	"CZ/O2",
	"CZ/Vodafone",
	"PL/T-Mobile",
	"PL/Orange",
	"PL/Play",
	"PL/Plus",
	"KZ/Beeline",
	"KZ/Kcell",
	"KZ/Activ",
	"KZ/Tele2",
	"UA/Киевстар",
	"UA/Vodafone",
	"UA/Lifecell",
	"TZ/Airtel",
	"TZ/Benson infomatics",
	"TZ/Vodacom Tanzania",
	"NZ/2degrees",
	"NZ/Vodafone New Zealand",
	"NZ/Spark New Zealand",
	"FR/Orange",
	"FR/SFR",
	"FR/Bouygues Telecom",
	"FR/Free Mobile",
	"TR/Turkcell",
	"TR/Vodaphone",
	"TR/Türk Telekom",
	"RO/Orange",
	"RO/Vodafone",
	"RO/Telekom",
	"RO/Digi.Mobil",
}

// UserAgent blah-blah-blah
func (fua FullUA) UserAgent(piece UAPiece) string {
	index := rand.Int() % len(countries)
	country := countries[index]
	return fmt.Sprintf("App.Com %s/%s", piece.UserAgentPiece(), country)
}

var easylines [][]byte

var START = time.Date(2015, 1, 1, 1, 1, 0, 0, time.UTC)

var users = map[string]struct{}{}

func init() {
	var pieces []UAPiece
	for i := 0; i < 20; i++ {
		pieces = append(pieces, AndroidUA{geo{}})
	}
	for i := 0; i < 3; i++ {
		pieces = append(pieces, IPhoneUA{geo{}})
	}
	for i := 0; i < 5; i++ {
		pieces = append(pieces, WindowsUA{})
	}

	// Generating userlist
	var userlist []string
	for i := 0; i < 100000; i++ {
		uid := rand.Uint64()
		barrier := uint64(10000000000)
		if uid < barrier {
			uid += barrier
		}
		userlist = append(userlist, fmt.Sprintf("%d", uid))
		users[fmt.Sprintf("%d", uid)] = struct{}{}
	}

	// Generating user agents for userlist
	type Node struct {
		UA  string
		Geo func() (float64, float64)
	}
	var agentmap = map[string]Node{}
	for _, u := range userlist {
		index := rand.Int() % len(pieces)
		node := Node{}
		node.UA = FullUA{}.UserAgent(pieces[index])
		node.Geo = pieces[index].Geo
		agentmap[u] = node
	}

	start := START
	total := 0
	for i := 0; i < 1000000; i++ {
		index := rand.Int() % len(userlist)
		gens := agentmap[userlist[index]]
		pid := rand.Int() % 65536
		line := fmt.Sprintf("[%d %s] PRESENCE uid=%s ua='%s'", pid, start.Format("2006-01-02T15:04:05"), userlist[index], gens.UA)
		lat, lon := gens.Geo()
		if lat != 0 || lon != 0 {
			line += fmt.Sprintf(" Geo={Lat: %f, Lon: %f}", lat, lon)
		}
		act := rand.Int() % 6
		line += fmt.Sprintf(" Activity=%d", act)
		easylines = append(easylines, []byte(line))
		total += len(line)
		start = start.Add(time.Second)
	}
	buf := make([]byte, total)
	offset := 0
	for i, line := range easylines {
		copy(buf[offset:], line)
		easylines[i] = buf[offset : offset+len(line)]
		offset += len(line)
	}
}

func TestRagelExtraction(t *testing.T) {
	p := &Easy{}
	f := &EasyFloat{}
	e := &PresenceFloats{}
	r := &Presence{}

	start := START
	for _, line := range easylines {
		ok, err := p.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = f.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = e.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		ok, err = r.Extract(line)
		if err != nil {
			t.Fatal(err)
		}
		require.True(t, ok)

		require.Equal(t, start.Format("2006-01-02T15:04:05"), string(p.Time))
		if _, ok := users[string(p.UID)]; !ok {
			t.Fatalf("Unknown user `\033[01m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
		}
		start = start.Add(time.Second)

		require.Equal(t, string(p.Time), string(r.Time))
		require.Equal(t, string(p.UID), string(r.UID))
		require.Equal(t, string(p.UA), string(r.UA))
		require.Equal(t, p.Geo.Valid, r.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, string(p.Geo.Lat), string(r.Geo.Lat))
			require.Equal(t, string(p.Geo.Lon), string(r.Geo.Lon))
		}
		require.Equal(t, string(p.Activity), string(r.Activity))

		require.Equal(t, string(p.Time), string(e.Time))
		require.Equal(t, string(p.UID), string(e.UID))
		require.Equal(t, string(p.UA), string(e.UA))
		require.Equal(t, p.Geo.Valid, e.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, string(p.Geo.Lat), fmt.Sprintf("%f", e.Geo.Lat))
			require.Equal(t, string(p.Geo.Lon), fmt.Sprintf("%f", e.Geo.Lon))
		}
		require.Equal(t, string(p.Activity), fmt.Sprintf("%d", e.Activity))

		require.Equal(t, string(p.Time), string(e.Time))
		require.Equal(t, string(p.UID), string(e.UID))
		require.Equal(t, string(p.UA), string(e.UA))
		require.Equal(t, p.Geo.Valid, e.Geo.Valid)
		if p.Geo.Valid {
			require.Equal(t, f.Geo.Lat, e.Geo.Lat)
			require.Equal(t, f.Geo.Lon, e.Geo.Lon)
		}
		require.Equal(t, f.Activity, e.Activity)
	}
}

func BenchmarkLDEEasyRealWorld(b *testing.B) {
	p := &Presence{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkLDEEasyFloatsRealWorld(b *testing.B) {
	p := &PresenceFloats{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkRagelEasyRealWorld(b *testing.B) {
	p := &Easy{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}

func BenchmarkRagelEasyFloatsRealWorld(b *testing.B) {
	p := &EasyFloat{}
	for i := 0; i < b.N; i++ {
		for _, line := range easylines {
			p.Extract(line)
			if _, ok := users[string(p.UID)]; !ok {
				b.Fatalf("Unknown user `\033[1m%s\033[0m` extracted on parsing>>\033[1m%s\033[0m", string(p.UID), string(line))
			}
		}
	}
}
<|endoftext|>


<commit_before>package openstack

import (
	"fmt"
	"log"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceFWRuleV1() *schema.Resource {
	return &schema.Resource{
		Create: resourceFWRuleV1Create,
		Read:   resourceFWRuleV1Read,
		Update: resourceFWRuleV1Update,
		Delete: resourceFWRuleV1Delete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"protocol": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"action": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
			},
			"source_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"destination_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"source_port": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"destination_port": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"value_specs": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceFWRuleV1Create(d *schema.ResourceData, meta interface{}) error {

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	enabled := d.Get("enabled").(bool)
	ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int))
	protocol := resourceFWRuleV1DetermineProtocol(d.Get("protocol").(string))

	ruleConfiguration := RuleCreateOpts{
		rules.CreateOpts{
			Name:                 d.Get("name").(string),
			Description:          d.Get("description").(string),
			Protocol:             protocol,
			Action:               d.Get("action").(string),
			IPVersion:            ipVersion,
			SourceIPAddress:      d.Get("source_ip_address").(string),
			DestinationIPAddress: d.Get("destination_ip_address").(string),
			SourcePort:           d.Get("source_port").(string),
			DestinationPort:      d.Get("destination_port").(string),
			Enabled:              &enabled,
			TenantID:             d.Get("tenant_id").(string),
		},
		MapValueSpecs(d),
	}

	log.Printf("[DEBUG] Create firewall rule: %#v", ruleConfiguration)

	rule, err := rules.Create(networkingClient, ruleConfiguration).Extract()

	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Firewall rule with id %s : %#v", rule.ID, rule)

	d.SetId(rule.ID)

	return resourceFWRuleV1Read(d, meta)
}

func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] Retrieve information about firewall rule: %s", d.Id())

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	rule, err := rules.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "FW rule")
	}

	log.Printf("[DEBUG] Read OpenStack Firewall Rule %s: %#v", d.Id(), rule)

	d.Set("action", rule.Action)
	d.Set("name", rule.Name)
	d.Set("description", rule.Description)
	d.Set("ip_version", rule.IPVersion)
	d.Set("source_ip_address", rule.SourceIPAddress)
	d.Set("destination_ip_address", rule.DestinationIPAddress)
	d.Set("source_port", rule.SourcePort)
	d.Set("destination_port", rule.DestinationPort)
	d.Set("enabled", rule.Enabled)

	if rule.Protocol == "" {
		d.Set("protocol", "any")
	} else {
		d.Set("protocol", rule.Protocol)
	}

	d.Set("region", GetRegion(d, config))

	return nil
}

func resourceFWRuleV1Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	opts := rules.UpdateOpts{}

	if d.HasChange("name") {
		v := d.Get("name").(string)
		opts.Name = &v
	}

	if d.HasChange("description") {
		v := d.Get("description").(string)
		opts.Description = &v
	}

	if d.HasChange("protocol") {
		v := d.Get("protocol").(string)
		opts.Protocol = &v
	}

	if d.HasChange("action") {
		v := d.Get("action").(string)
		opts.Action = &v
	}

	if d.HasChange("ip_version") {
		v := d.Get("ip_version").(int)
		ipVersion := resourceFWRuleV1DetermineIPVersion(v)
		opts.IPVersion = &ipVersion
	}

	if d.HasChange("source_ip_address") {
		v := d.Get("source_ip_address").(string)
		opts.SourceIPAddress = &v
	}

	if d.HasChange("destination_ip_address") {
		v := d.Get("destination_ip_address").(string)
		opts.DestinationIPAddress = &v
	}

	if d.HasChange("source_port") {
		v := d.Get("source_port").(string)
		opts.SourcePort = &v
	}

	if d.HasChange("destination_port") {
		v := d.Get("destination_port").(string)
		opts.DestinationPort = &v
	}

	if d.HasChange("enabled") {
		v := d.Get("enabled").(bool)
		opts.Enabled = &v
	}

	log.Printf("[DEBUG] Updating firewall rules: %#v", opts)

	err = rules.Update(networkingClient, d.Id(), opts).Err
	if err != nil {
		return err
	}

	return resourceFWRuleV1Read(d, meta)
}

func resourceFWRuleV1Delete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] Destroy firewall rule: %s", d.Id())

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	rule, err := rules.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return err
	}

	if rule.PolicyID != "" {
		_, err := policies.RemoveRule(networkingClient, rule.PolicyID, rule.ID).Extract()
		if err != nil {
			return err
		}
	}

	return rules.Delete(networkingClient, d.Id()).Err
}

func resourceFWRuleV1DetermineIPVersion(ipv int) gophercloud.IPVersion {
	// Determine the IP Version
	var ipVersion gophercloud.IPVersion
	switch ipv {
	case 4:
		ipVersion = gophercloud.IPv4
	case 6:
		ipVersion = gophercloud.IPv6
	}

	return ipVersion
}

func resourceFWRuleV1DetermineProtocol(p string) rules.Protocol {
	var protocol rules.Protocol
	switch p {
	case "any":
		protocol = rules.ProtocolAny
	case "icmp":
		protocol = rules.ProtocolICMP
	case "tcp":
		protocol = rules.ProtocolTCP
	case "udp":
		protocol = rules.ProtocolUDP
	}

	return protocol
}
<commit_msg>Firewall v1: Pass all attributes when a rule update occurs<commit_after>package openstack

import (
	"fmt"
	"log"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceFWRuleV1() *schema.Resource {
	return &schema.Resource{
		Create: resourceFWRuleV1Create,
		Read:   resourceFWRuleV1Read,
		Update: resourceFWRuleV1Update,
		Delete: resourceFWRuleV1Delete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"region": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"protocol": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"action": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"ip_version": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  4,
			},
			"source_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"destination_ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"source_port": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"destination_port": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			"enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"tenant_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"value_specs": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: true,
			},
		},
	}
}

func resourceFWRuleV1Create(d *schema.ResourceData, meta interface{}) error {

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	enabled := d.Get("enabled").(bool)
	ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int))
	protocol := resourceFWRuleV1DetermineProtocol(d.Get("protocol").(string))

	ruleConfiguration := RuleCreateOpts{
		rules.CreateOpts{
			Name:                 d.Get("name").(string),
			Description:          d.Get("description").(string),
			Protocol:             protocol,
			Action:               d.Get("action").(string),
			IPVersion:            ipVersion,
			SourceIPAddress:      d.Get("source_ip_address").(string),
			DestinationIPAddress: d.Get("destination_ip_address").(string),
			SourcePort:           d.Get("source_port").(string),
			DestinationPort:      d.Get("destination_port").(string),
			Enabled:              &enabled,
			TenantID:             d.Get("tenant_id").(string),
		},
		MapValueSpecs(d),
	}

	log.Printf("[DEBUG] Create firewall rule: %#v", ruleConfiguration)

	rule, err := rules.Create(networkingClient, ruleConfiguration).Extract()

	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Firewall rule with id %s : %#v", rule.ID, rule)

	d.SetId(rule.ID)

	return resourceFWRuleV1Read(d, meta)
}

func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] Retrieve information about firewall rule: %s", d.Id())

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	rule, err := rules.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return CheckDeleted(d, err, "FW rule")
	}

	log.Printf("[DEBUG] Read OpenStack Firewall Rule %s: %#v", d.Id(), rule)

	d.Set("action", rule.Action)
	d.Set("name", rule.Name)
	d.Set("description", rule.Description)
	d.Set("ip_version", rule.IPVersion)
	d.Set("source_ip_address", rule.SourceIPAddress)
	d.Set("destination_ip_address", rule.DestinationIPAddress)
	d.Set("source_port", rule.SourcePort)
	d.Set("destination_port", rule.DestinationPort)
	d.Set("enabled", rule.Enabled)

	if rule.Protocol == "" {
		d.Set("protocol", "any")
	} else {
		d.Set("protocol", rule.Protocol)
	}

	d.Set("region", GetRegion(d, config))

	return nil
}

func resourceFWRuleV1Update(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	name := d.Get("name").(string)
	description := d.Get("description").(string)
	protocol := d.Get("protocol").(string)
	action := d.Get("action").(string)
	ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int))
	sourceIPAddress := d.Get("source_ip_address").(string)
	sourcePort := d.Get("source_port").(string)
	destinationIPAddress := d.Get("destination_ip_address").(string)
	destinationPort := d.Get("destination_port").(string)
	enabled := d.Get("enabled").(bool)

	opts := rules.UpdateOpts{
		Name:                 &name,
		Description:          &description,
		Protocol:             &protocol,
		Action:               &action,
		IPVersion:            &ipVersion,
		SourceIPAddress:      &sourceIPAddress,
		DestinationIPAddress: &destinationIPAddress,
		SourcePort:           &sourcePort,
		DestinationPort:      &destinationPort,
		Enabled:              &enabled,
	}

	log.Printf("[DEBUG] Updating firewall rules: %#v", opts)
	err = rules.Update(networkingClient, d.Id(), opts).Err
	if err != nil {
		return err
	}

	return resourceFWRuleV1Read(d, meta)
}

func resourceFWRuleV1Delete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[DEBUG] Destroy firewall rule: %s", d.Id())

	config := meta.(*Config)
	networkingClient, err := config.networkingV2Client(GetRegion(d, config))
	if err != nil {
		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
	}

	rule, err := rules.Get(networkingClient, d.Id()).Extract()
	if err != nil {
		return err
	}

	if rule.PolicyID != "" {
		_, err := policies.RemoveRule(networkingClient, rule.PolicyID, rule.ID).Extract()
		if err != nil {
			return err
		}
	}

	return rules.Delete(networkingClient, d.Id()).Err
}

func resourceFWRuleV1DetermineIPVersion(ipv int) gophercloud.IPVersion {
	// Determine the IP Version
	var ipVersion gophercloud.IPVersion
	switch ipv {
	case 4:
		ipVersion = gophercloud.IPv4
	case 6:
		ipVersion = gophercloud.IPv6
	}

	return ipVersion
}

func resourceFWRuleV1DetermineProtocol(p string) rules.Protocol {
	var protocol rules.Protocol
	switch p {
	case "any":
		protocol = rules.ProtocolAny
	case "icmp":
		protocol = rules.ProtocolICMP
	case "tcp":
		protocol = rules.ProtocolTCP
	case "udp":
		protocol = rules.ProtocolUDP
	}

	return protocol
}
<|endoftext|>


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

package consumer

import (
	"fmt"
	"github.com/miekg/pcap"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	"github.com/trivago/gollum/shared"
	"hash/fnv"
	"sync"
	"sync/atomic"
	"time"
)

// PcapHTTP consumer plugin
// Configuration example
//
//   - "consumer.PcapHTTP":
//     Enable: true
//     Interface: eth0
//     Filter: "dst port 80 and dst host 127.0.0.1"
//     Promiscuous: true
//     TimeoutMs: 3000
//     DebugTCP: false
//
type PcapHTTP struct {
	core.ConsumerBase
	netInterface   string
	filter         string
	capturing      bool
	promiscuous    bool
	debugTCP       bool
	handle         *pcap.Pcap
	sessions       pcapSessionMap
	seqNum         uint64
	sessionTimeout time.Duration
}

type pcapSessionMap map[uint32]*pcapSession

const (
	pcapNextExEOF     = -2
	pcapNextExError   = -1
	pcapNextExTimeout = 0
	pcapNextExOk      = 1
	pcapFin           = 0x1
)

func init() {
	shared.RuntimeType.Register(PcapHTTP{})
}

func (cons *PcapHTTP) Configure(conf core.PluginConfig) error {
	err := cons.ConsumerBase.Configure(conf)
	if err != nil {
		return err
	}

	cons.netInterface = conf.GetString("Interface", "eth0")
	cons.promiscuous = conf.GetBool("Promiscuous", true)
	cons.debugTCP = conf.GetBool("DebugTCP", false)
	cons.filter = conf.GetString("Filter", "dst port 80 and dst host 127.0.0.1")
	cons.capturing = true
	cons.sessions = make(pcapSessionMap)
	cons.sessionTimeout = time.Duration(conf.GetInt("TimeoutSec", 3000)) * time.Millisecond

	return nil
}

func (cons *PcapHTTP) enqueueBuffer(data []byte) {
	cons.Enqueue(data, cons.seqNum)
	atomic.AddUint64(&cons.seqNum, 1)
}

func (cons *PcapHTTP) getStreamKey(pkt *pcap.Packet) (uint32, string, bool) {
	if len(pkt.Headers) != 2 {
		Log.Debug.Printf("Invalid number of headers: %d", len(pkt.Headers))
		Log.Debug.Printf("Not a TCP/IP packet: %#v", pkt)
		return 0, "", false
	}

	ipHeader, isIPHeader := ipFromPcap(pkt)
	tcpHeader, isTCPHeader := tcpFromPcap(pkt)
	if !isIPHeader || !isTCPHeader {
		Log.Debug.Printf("Not a TCP/IP packet: %#v", pkt)
		return 0, "", false
	}

	if len(pkt.Payload) == 0 {
		return 0, "", false
	}

	clientID := fmt.Sprintf("%s:%d", ipHeader.SrcAddr(), tcpHeader.SrcPort)
	key := fmt.Sprintf("%s-%s:%d", clientID, ipHeader.DestAddr(), tcpHeader.DestPort)
	keyHash := fnv.New32a()
	keyHash.Write([]byte(key))

	return keyHash.Sum32(), clientID, true
}

func (cons *PcapHTTP) readPackets() {
	defer func() {
		cons.handle.Close()
		if panicMessage := recover(); panicMessage != nil {
			// try again
			Log.Error.Print("[PANIC] PcapHTTP: ", panicMessage)
			cons.initPcap()
			go cons.readPackets()
		} else {
			// done
			cons.WorkerDone()
		}
	}()

	for cons.capturing {
		pkt, resultCode := cons.handle.NextEx()

		switch resultCode {
		case pcapNextExEOF:
			cons.capturing = false
			Log.Note.Print("PcapHTTP: End of file, stopping.")
			continue

		case pcapNextExError:
			Log.Error.Print("PcapHTTP: ", cons.handle.Geterror())
			continue

		case pcapNextExTimeout:
			continue
		}

		pkt.Decode()
		TCPHeader, _ := tcpFromPcap(pkt)

		key, client, validPacket := cons.getStreamKey(pkt)
		session, sessionExists := cons.sessions[key]

		if cons.debugTCP {
			headerString := fmt.Sprintf("TCP: [%t] [%s] %#v", validPacket, client, TCPHeader)
			cons.enqueueBuffer([]byte(headerString))
		}

		if validPacket {
			if sessionExists {
				session.timer.Reset(cons.sessionTimeout)
			} else {
				session = newPcapSession(client)
				cons.sessions[key] = session

				session.timer = time.AfterFunc(cons.sessionTimeout, func() {
					if len(session.packets) > 0 {
						if session.lastError == nil {
							session.lastError = fmt.Errorf("-")
						}
						// TODO: Try to recover io.ErrUnexpectedEOF by adding \r\n
						//       Generate the missing package (seq + payload)
						Log.Debug.Printf("PcapHTTP: Incomplete session timed out: \"%s\" %s", session.lastError, session)
					}
					delete(cons.sessions, key)
				})
			}
			session.addPacket(cons, pkt)
		}

		if sessionExists && validPacket && (TCPHeader.Flags&pcapFin != 0) {
			closeString := fmt.Sprintf("TCP: [closed] [%s]", client)
			cons.enqueueBuffer([]byte(closeString))

			session.timer.Stop()
			delete(cons.sessions, key)
		}
	}
}

func (cons *PcapHTTP) close() {
	cons.capturing = false
}

func (cons *PcapHTTP) initPcap() {
	var err error

	// Start listening
	// device, snaplen, promisc, read timeout ms
	cons.handle, err = pcap.OpenLive(cons.netInterface, int32(1<<16), cons.promiscuous, 500)
	if err != nil {
		Log.Error.Print("PcapHTTP: ", err)
		return
	}

	err = cons.handle.SetFilter(cons.filter)
	if err != nil {
		cons.handle.Close()
		Log.Error.Print("PcapHTTP: ", err)
		return
	}
}

func (cons *PcapHTTP) Consume(workers *sync.WaitGroup) {
	cons.initPcap()
	cons.AddMainWorker(workers)

	go cons.readPackets()
	defer cons.close()

	cons.DefaultControlLoop(nil)
}
<commit_msg>Thread safe session map<commit_after>// Copyright 2015 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package consumer

import (
	"fmt"
	"github.com/miekg/pcap"
	"github.com/trivago/gollum/core"
	"github.com/trivago/gollum/core/log"
	"github.com/trivago/gollum/shared"
	"hash/fnv"
	"sync"
	"sync/atomic"
	"time"
)

// PcapHTTP consumer plugin
// Configuration example
//
//   - "consumer.PcapHTTP":
//     Enable: true
//     Interface: eth0
//     Filter: "dst port 80 and dst host 127.0.0.1"
//     Promiscuous: true
//     TimeoutMs: 3000
//     DebugTCP: false
//
type PcapHTTP struct {
	core.ConsumerBase
	netInterface   string
	filter         string
	capturing      bool
	promiscuous    bool
	debugTCP       bool
	handle         *pcap.Pcap
	sessions       pcapSessionMap
	seqNum         uint64
	sessionTimeout time.Duration
	sessionGuard   *sync.Mutex
}

type pcapSessionMap map[uint32]*pcapSession

const (
	pcapNextExEOF     = -2
	pcapNextExError   = -1
	pcapNextExTimeout = 0
	pcapNextExOk      = 1
	pcapFin           = 0x1
)

func init() {
	shared.RuntimeType.Register(PcapHTTP{})
}

func (cons *PcapHTTP) Configure(conf core.PluginConfig) error {
	err := cons.ConsumerBase.Configure(conf)
	if err != nil {
		return err
	}

	cons.netInterface = conf.GetString("Interface", "eth0")
	cons.promiscuous = conf.GetBool("Promiscuous", true)
	cons.debugTCP = conf.GetBool("DebugTCP", false)
	cons.filter = conf.GetString("Filter", "dst port 80 and dst host 127.0.0.1")
	cons.capturing = true
	cons.sessions = make(pcapSessionMap)
	cons.sessionTimeout = time.Duration(conf.GetInt("TimeoutSec", 3000)) * time.Millisecond
	cons.sessionGuard = new(sync.Mutex)

	return nil
}

func (cons *PcapHTTP) enqueueBuffer(data []byte) {
	cons.Enqueue(data, cons.seqNum)
	atomic.AddUint64(&cons.seqNum, 1)
}

func (cons *PcapHTTP) getStreamKey(pkt *pcap.Packet) (uint32, string, bool) {
	if len(pkt.Headers) != 2 {
		Log.Debug.Printf("Invalid number of headers: %d", len(pkt.Headers))
		Log.Debug.Printf("Not a TCP/IP packet: %#v", pkt)
		return 0, "", false
	}

	ipHeader, isIPHeader := ipFromPcap(pkt)
	tcpHeader, isTCPHeader := tcpFromPcap(pkt)
	if !isIPHeader || !isTCPHeader {
		Log.Debug.Printf("Not a TCP/IP packet: %#v", pkt)
		return 0, "", false
	}

	if len(pkt.Payload) == 0 {
		return 0, "", false
	}

	clientID := fmt.Sprintf("%s:%d", ipHeader.SrcAddr(), tcpHeader.SrcPort)
	key := fmt.Sprintf("%s-%s:%d", clientID, ipHeader.DestAddr(), tcpHeader.DestPort)
	keyHash := fnv.New32a()
	keyHash.Write([]byte(key))

	return keyHash.Sum32(), clientID, true
}

func (cons *PcapHTTP) readPackets() {
	defer func() {
		cons.handle.Close()
		if panicMessage := recover(); panicMessage != nil {
			// try again
			Log.Error.Print("[PANIC] PcapHTTP: ", panicMessage)
			cons.initPcap()
			go cons.readPackets()
		} else {
			// done
			cons.WorkerDone()
		}
	}()

	for cons.capturing {
		pkt, resultCode := cons.handle.NextEx()

		switch resultCode {
		case pcapNextExEOF:
			cons.capturing = false
			Log.Note.Print("PcapHTTP: End of file, stopping.")
			continue

		case pcapNextExError:
			Log.Error.Print("PcapHTTP: ", cons.handle.Geterror())
			continue

		case pcapNextExTimeout:
			continue
		}

		pkt.Decode()
		TCPHeader, _ := tcpFromPcap(pkt)

		key, client, validPacket := cons.getStreamKey(pkt)
		session, sessionExists := cons.tryGetSession(key)

		if cons.debugTCP {
			headerString := fmt.Sprintf("TCP: [%t] [%s] %#v", validPacket, client, TCPHeader)
			cons.enqueueBuffer([]byte(headerString))
		}

		if validPacket {
			if sessionExists {
				session.timer.Reset(cons.sessionTimeout)
			} else {
				session = newPcapSession(client)
				cons.setSession(key, session)

				session.timer = time.AfterFunc(cons.sessionTimeout, func() {
					if len(session.packets) > 0 {
						if session.lastError == nil {
							session.lastError = fmt.Errorf("-")
						}
						// TODO: Try to recover io.ErrUnexpectedEOF by adding \r\n
						//       Generate the missing package (seq + payload)
						Log.Debug.Printf("PcapHTTP: Incomplete session timed out: \"%s\" %s", session.lastError, session)
					}
					cons.clearSession(key)
				})
			}
			session.addPacket(cons, pkt)
		}

		if sessionExists && validPacket && (TCPHeader.Flags&pcapFin != 0) {
			closeString := fmt.Sprintf("TCP: [closed] [%s]", client)
			cons.enqueueBuffer([]byte(closeString))

			session.timer.Stop()
			cons.clearSession(key)
		}
	}
}

func (cons *PcapHTTP) tryGetSession(key uint32) (*pcapSession, bool) {
	cons.sessionGuard.Lock()
	defer cons.sessionGuard.Unlock()
	session, exists := cons.sessions[key]
	return session, exists
}

func (cons *PcapHTTP) setSession(key uint32, session *pcapSession) {
	cons.sessionGuard.Lock()
	defer cons.sessionGuard.Unlock()
	cons.sessions[key] = session
}

func (cons *PcapHTTP) clearSession(key uint32) {
	cons.sessionGuard.Lock()
	defer cons.sessionGuard.Unlock()
	delete(cons.sessions, key)
}

func (cons *PcapHTTP) close() {
	cons.capturing = false
}

func (cons *PcapHTTP) initPcap() {
	var err error

	// Start listening
	// device, snaplen, promisc, read timeout ms
	cons.handle, err = pcap.OpenLive(cons.netInterface, int32(1<<16), cons.promiscuous, 500)
	if err != nil {
		Log.Error.Print("PcapHTTP: ", err)
		return
	}

	err = cons.handle.SetFilter(cons.filter)
	if err != nil {
		cons.handle.Close()
		Log.Error.Print("PcapHTTP: ", err)
		return
	}
}

func (cons *PcapHTTP) Consume(workers *sync.WaitGroup) {
	cons.initPcap()
	cons.AddMainWorker(workers)

	go cons.readPackets()
	defer cons.close()

	cons.DefaultControlLoop(nil)
}
<|endoftext|>


<commit_before>package context

import (
	"fmt"
	"log"
	"path/filepath"
	"reflect"
	"strconv"

	sw "github.com/wellington/spritewell"
)

func init() {

	RegisterHandler("sprite-map($glob, $spacing: 0px)", SpriteMap)
	RegisterHandler("sprite-file($map, $name)", SpriteFile)
	RegisterHandler("image-url($name)", ImageURL)
	RegisterHandler("image-height($path)", ImageHeight)
	RegisterHandler("image-width($path)", ImageWidth)
	RegisterHandler("inline-image($path)", InlineImage)
	RegisterHandler("font-url($path, $raw: false)", FontURL)
}

// ImageURL handles calls to resolve a local image from the
// built css file path.
func ImageURL(ctx *Context, csv UnionSassValue) UnionSassValue {
	var path []string
	err := Unmarshal(csv, &path)
	// This should create and throw a sass error
	if err != nil {
		return Error(err)
	}
	url := filepath.Join(ctx.RelativeImage(), path[0])
	res, err := Marshal(fmt.Sprintf("url('%s')", url))
	if err != nil {
		return Error(err)
	}
	return res
}

func ImageHeight(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		glob string
		name string
	)
	err := Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			log.Fatal(err)
			return Error(err)
		} else {
			glob = infs[0].(string)
			name = infs[1].(string)
		}
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	if glob == "" {
		if hit, ok := ctx.Imgs.M[name]; ok {
			imgs = hit
		} else {
			imgs.Decode(name)
			imgs.Combine()
			ctx.Imgs.Lock()
			ctx.Imgs.M[name] = imgs
			ctx.Imgs.Unlock()
		}
	} else {
		ctx.Sprites.RLock()
		imgs = ctx.Sprites.M[glob]
		ctx.Sprites.RUnlock()
	}
	height := imgs.SImageHeight(name)
	Hheight := SassNumber{
		Value: float64(height),
		Unit:  "px",
	}
	res, err := Marshal(Hheight)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

// ImageWidth takes a file path (or sprite glob) and returns the
// height in pixels of the image being referenced.
func ImageWidth(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		glob, name string
	)
	err := Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			log.Fatal(err)
			return Error(err)
		} else {
			glob = infs[0].(string)
			name = infs[1].(string)
		}
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	if glob == "" {
		if hit, ok := ctx.Imgs.M[name]; ok {
			imgs = hit
		} else {
			imgs.Decode(name)
			imgs.Combine()
			ctx.Imgs.Lock()
			ctx.Imgs.M[name] = imgs
			ctx.Imgs.Unlock()
		}
	} else {
		ctx.Sprites.RLock()
		imgs = ctx.Sprites.M[glob]
		ctx.Sprites.RUnlock()
	}
	v := imgs.SImageWidth(name)
	vv := SassNumber{
		Value: float64(v),
		Unit:  "px",
	}
	res, err := Marshal(vv)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

func InlineImage(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		name string
	)
	err := Unmarshal(usv, &name)
	if err != nil {
		fmt.Println(err)
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	err = imgs.Decode(name)
	if err != nil {
		return Error(err)
	}
	_, err = imgs.Combine()
	if err != nil {
		fmt.Println(err)
	}
	str := imgs.Inline()
	res, err := Marshal(str)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

// SpriteFile proxies the sprite glob and image name through.
func SpriteFile(ctx *Context, usv UnionSassValue) UnionSassValue {
	var glob, name string
	err := Unmarshal(usv, &glob, &name)
	if err != nil {
		panic(err)
	}
	infs := []interface{}{glob, name}
	res, err := Marshal(infs)
	return res
}

// SpriteMap generates a sprite from the passed glob and sprite
// parameters.
func SpriteMap(ctx *Context, usv UnionSassValue) UnionSassValue {
	var glob string
	var spacing SassNumber
	err := Unmarshal(usv, &glob, &spacing)
	if err != nil {
		return Error(err)
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	imgs.Padding = int(spacing.Value)
	if cglob, err := strconv.Unquote(glob); err == nil {
		glob = cglob
	}

	key := glob + strconv.FormatInt(int64(spacing.Value), 10)
	ctx.Sprites.RLock()
	if hit, ok := ctx.Sprites.M[key]; ok {
		ctx.Sprites.RUnlock()
		gpath := hit.OutFile
		res, err := Marshal(gpath)
		if err != nil {
			fmt.Println("hang?")
			log.Fatal(err)
		}
		return res
	} else {
		ctx.Sprites.RUnlock()
	}
	err = imgs.Decode(glob)
	if err != nil {
		return Error(err)
	}
	gpath, err := imgs.Combine()
	_ = gpath
	if err != nil {
		return Error(err)
	}

	_, err = imgs.Export()
	if err != nil {
		log.Fatal(err)
	}

	res, err := Marshal(key)
	ctx.Sprites.Lock()
	ctx.Sprites.M[key] = imgs
	ctx.Sprites.Unlock()
	if err != nil {
		log.Fatal(err)
	}
	return res
}

// SpriteFile proxies the sprite glob and image name through.
func FontURL(ctx *Context, usv UnionSassValue) UnionSassValue {

	var (
		path, format string
		csv          UnionSassValue
		raw          bool
	)
	err := Unmarshal(usv, &path, &raw)

	if err != nil {
		return Error(err)
	}

	// Enter warning
	if ctx.FontDir == "." {
		s := "font path not provided"
		log.Println(s)
		res, _ := Marshal(s)
		return res
	}

	rel, err := filepath.Rel(ctx.BuildDir, ctx.FontDir)

	if err != nil {
		return Error(err)
	}
	if raw {
		format = "%s"
	} else {
		format = `url("%s")`
	}

	csv, err = Marshal(fmt.Sprintf(format, filepath.Join(rel, path)))
	if err != nil {
		return Error(err)
	}
	return csv
}
<commit_msg>exit quickly on invalid file types<commit_after>package context

import (
	"fmt"
	"log"
	"path/filepath"
	"reflect"
	"strconv"

	sw "github.com/wellington/spritewell"
)

func init() {

	RegisterHandler("sprite-map($glob, $spacing: 0px)", SpriteMap)
	RegisterHandler("sprite-file($map, $name)", SpriteFile)
	RegisterHandler("image-url($name)", ImageURL)
	RegisterHandler("image-height($path)", ImageHeight)
	RegisterHandler("image-width($path)", ImageWidth)
	RegisterHandler("inline-image($path)", InlineImage)
	RegisterHandler("font-url($path, $raw: false)", FontURL)
}

// ImageURL handles calls to resolve a local image from the
// built css file path.
func ImageURL(ctx *Context, csv UnionSassValue) UnionSassValue {
	var path []string
	err := Unmarshal(csv, &path)
	// This should create and throw a sass error
	if err != nil {
		return Error(err)
	}
	url := filepath.Join(ctx.RelativeImage(), path[0])
	res, err := Marshal(fmt.Sprintf("url('%s')", url))
	if err != nil {
		return Error(err)
	}
	return res
}

func ImageHeight(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		glob string
		name string
	)
	err := Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			log.Fatal(err)
			return Error(err)
		} else {
			glob = infs[0].(string)
			name = infs[1].(string)
		}
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	if glob == "" {
		if hit, ok := ctx.Imgs.M[name]; ok {
			imgs = hit
		} else {
			imgs.Decode(name)
			imgs.Combine()
			ctx.Imgs.Lock()
			ctx.Imgs.M[name] = imgs
			ctx.Imgs.Unlock()
		}
	} else {
		ctx.Sprites.RLock()
		imgs = ctx.Sprites.M[glob]
		ctx.Sprites.RUnlock()
	}
	height := imgs.SImageHeight(name)
	Hheight := SassNumber{
		Value: float64(height),
		Unit:  "px",
	}
	res, err := Marshal(Hheight)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

// ImageWidth takes a file path (or sprite glob) and returns the
// height in pixels of the image being referenced.
func ImageWidth(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		glob, name string
	)
	err := Unmarshal(usv, &name)
	// Check for sprite-file override first
	if err != nil {
		var inf interface{}
		var infs []interface{}
		// Can't unmarshal to []interface{}, so unmarshal to
		// interface{} then reflect it into a []interface{}
		err = Unmarshal(usv, &inf)
		k := reflect.ValueOf(&infs).Elem()
		k.Set(reflect.ValueOf(inf))

		if err != nil {
			log.Fatal(err)
			return Error(err)
		} else {
			glob = infs[0].(string)
			name = infs[1].(string)
		}
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	if glob == "" {
		if hit, ok := ctx.Imgs.M[name]; ok {
			imgs = hit
		} else {
			imgs.Decode(name)
			imgs.Combine()
			ctx.Imgs.Lock()
			ctx.Imgs.M[name] = imgs
			ctx.Imgs.Unlock()
		}
	} else {
		ctx.Sprites.RLock()
		imgs = ctx.Sprites.M[glob]
		ctx.Sprites.RUnlock()
	}
	v := imgs.SImageWidth(name)
	vv := SassNumber{
		Value: float64(v),
		Unit:  "px",
	}
	res, err := Marshal(vv)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

func InlineImage(ctx *Context, usv UnionSassValue) UnionSassValue {
	var (
		name string
	)
	err := Unmarshal(usv, &name)
	if err != nil {
		fmt.Println(err)
	}

	if !sw.CanDecode(filepath.Ext(name)) {
		s := fmt.Sprintf("filetype %s is not supported", filepath.Ext(name))
		// TODO: Replace with warning
		log.Println(s)
		res, _ := Marshal(s)
		return res
	}

	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		GenImgDir: ctx.GenImgDir,
	}
	err = imgs.Decode(name)
	if err != nil {
		return Error(err)
	}
	_, err = imgs.Combine()
	if err != nil {
		fmt.Println(err)
	}
	str := imgs.Inline()
	res, err := Marshal(str)
	if err != nil {
		fmt.Println(err)
	}
	return res
}

// SpriteFile proxies the sprite glob and image name through.
func SpriteFile(ctx *Context, usv UnionSassValue) UnionSassValue {
	var glob, name string
	err := Unmarshal(usv, &glob, &name)
	if err != nil {
		panic(err)
	}
	infs := []interface{}{glob, name}
	res, err := Marshal(infs)
	return res
}

// SpriteMap generates a sprite from the passed glob and sprite
// parameters.
func SpriteMap(ctx *Context, usv UnionSassValue) UnionSassValue {
	var glob string
	var spacing SassNumber
	err := Unmarshal(usv, &glob, &spacing)
	if err != nil {
		return Error(err)
	}
	imgs := sw.ImageList{
		ImageDir:  ctx.ImageDir,
		BuildDir:  ctx.BuildDir,
		GenImgDir: ctx.GenImgDir,
	}
	imgs.Padding = int(spacing.Value)
	if cglob, err := strconv.Unquote(glob); err == nil {
		glob = cglob
	}

	key := glob + strconv.FormatInt(int64(spacing.Value), 10)
	ctx.Sprites.RLock()
	if hit, ok := ctx.Sprites.M[key]; ok {
		ctx.Sprites.RUnlock()
		gpath := hit.OutFile
		res, err := Marshal(gpath)
		if err != nil {
			fmt.Println("hang?")
			log.Fatal(err)
		}
		return res
	} else {
		ctx.Sprites.RUnlock()
	}
	err = imgs.Decode(glob)
	if err != nil {
		return Error(err)
	}
	gpath, err := imgs.Combine()
	_ = gpath
	if err != nil {
		return Error(err)
	}

	_, err = imgs.Export()
	if err != nil {
		log.Fatal(err)
	}

	res, err := Marshal(key)
	ctx.Sprites.Lock()
	ctx.Sprites.M[key] = imgs
	ctx.Sprites.Unlock()
	if err != nil {
		log.Fatal(err)
	}
	return res
}

// SpriteFile proxies the sprite glob and image name through.
func FontURL(ctx *Context, usv UnionSassValue) UnionSassValue {

	var (
		path, format string
		csv          UnionSassValue
		raw          bool
	)
	err := Unmarshal(usv, &path, &raw)

	if err != nil {
		return Error(err)
	}

	// Enter warning
	if ctx.FontDir == "." {
		s := "font path not provided"
		log.Println(s)
		res, _ := Marshal(s)
		return res
	}

	rel, err := filepath.Rel(ctx.BuildDir, ctx.FontDir)

	if err != nil {
		return Error(err)
	}
	if raw {
		format = "%s"
	} else {
		format = `url("%s")`
	}

	csv, err = Marshal(fmt.Sprintf(format, filepath.Join(rel, path)))
	if err != nil {
		return Error(err)
	}
	return csv
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"strconv"

	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	"github.com/techjanitor/pram-get/models"
	u "github.com/techjanitor/pram-get/utils"
)

// IndexController handles index pages
func IndexController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// how many threads per index page
	threads := c.DefaultQuery("threads", strconv.Itoa(int(config.Settings.Limits.ThreadsPerPage)))
	// how many posts per thread
	posts := c.DefaultQuery("posts", strconv.Itoa(int(config.Settings.Limits.PostsPerThread)))

	// validate query parameter
	ut, err := u.ValidateParam(threads)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// validate query parameter
	up, err := u.ValidateParam(posts)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// Initialize model struct
	m := &models.IndexModel{
		Ib:      params[0],
		Page:    params[1],
		Threads: ut,
		Posts:   up,
	}

	// Get the model which outputs JSON
	err = m.Get()
	if err == e.ErrNotFound {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Marshal the structs into JSON
	output, err := json.Marshal(m.Result)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Hand off data to cache middleware
	c.Set("data", output)

	c.Writer.Header().Set("Content-Type", "application/json")
	c.Writer.Write(output)

	return

}
<commit_msg>add ability to change number of threads per index page<commit_after>package controllers

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"strconv"

	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	"github.com/techjanitor/pram-get/models"
	u "github.com/techjanitor/pram-get/utils"
)

// IndexController handles index pages
func IndexController(c *gin.Context) {

	// Get parameters from validate middleware
	params := c.MustGet("params").([]uint)

	// how many threads per index page
	threads := c.DefaultQuery("threads", strconv.Itoa(int(config.Settings.Limits.ThreadsPerPage)))
	// how many posts per thread
	posts := c.DefaultQuery("posts", strconv.Itoa(int(config.Settings.Limits.PostsPerThread)))

	// validate query parameter
	ut, err := u.ValidateParam(threads)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// max for query params
	if ut > 20 || ut < 5 {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// validate query parameter
	up, err := u.ValidateParam(posts)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// max for query params
	if up > 20 || up < 5 {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInvalidParam))
		c.Error(err)
		return
	}

	// Initialize model struct
	m := &models.IndexModel{
		Ib:      params[0],
		Page:    params[1],
		Threads: ut,
		Posts:   up,
	}

	// Get the model which outputs JSON
	err = m.Get()
	if err == e.ErrNotFound {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrNotFound))
		c.Error(err)
		return
	} else if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Marshal the structs into JSON
	output, err := json.Marshal(m.Result)
	if err != nil {
		c.Set("controllerError", err)
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err)
		return
	}

	// Hand off data to cache middleware
	c.Set("data", output)

	c.Writer.Header().Set("Content-Type", "application/json")
	c.Writer.Write(output)

	return

}
<|endoftext|>


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

// Binary viewindex prints a .kindex as JSON to stdout.
//
// Example:
//   viewindex compilation.kindex | jq .
package main

import (
	"context"
	"encoding/json"
	"flag"
	"log"
	"os"

	"kythe.io/kythe/go/platform/kindex"
	"kythe.io/kythe/go/util/flagutil"

	"github.com/golang/protobuf/jsonpb"

	_ "kythe.io/kythe/proto/buildinfo_go_proto"
	_ "kythe.io/kythe/proto/cxx_go_proto"
	_ "kythe.io/kythe/proto/go_go_proto"
	_ "kythe.io/kythe/proto/java_go_proto"
)

func init() {
	flag.Usage = flagutil.SimpleUsage("Print a .kindex archive as JSON to stdout",
		"[--files] <kindex-file>")
}

var (
	printFiles = flag.Bool("files", false, "Print file contents as well as the compilation")

	m = &jsonpb.Marshaler{
		OrigName: true,
	}
)

func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		flagutil.UsageError("missing kindex-file path")
	} else if len(flag.Args()) > 1 {
		flagutil.UsageErrorf("unknown arguments: %v", flag.Args()[1:])
	}

	path := flag.Arg(0)
	idx, err := kindex.Open(context.Background(), path)
	if err != nil {
		log.Fatalf("Error reading %q: %v", path, err)
	}

	out := os.Stdout
	if *printFiles {
		if err := json.NewEncoder(out).Encode(idx); err != nil {
			log.Fatalf("Error encoding JSON: %v", err)
		}
	} else {
		if err := m.Marshal(out, idx.Proto); err != nil {
			log.Fatalf("Error encoding JSON compilation: %v", err)
		}
	}
}
<commit_msg>viewindex: add --file flag to print a single file's contents (#2796)<commit_after>/*
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Binary viewindex prints a .kindex as JSON to stdout.
//
// Example:
//   viewindex compilation.kindex | jq .
package main

import (
	"context"
	"encoding/json"
	"flag"
	"log"
	"os"

	"kythe.io/kythe/go/platform/kindex"
	"kythe.io/kythe/go/util/flagutil"

	"github.com/golang/protobuf/jsonpb"

	_ "kythe.io/kythe/proto/buildinfo_go_proto"
	_ "kythe.io/kythe/proto/cxx_go_proto"
	_ "kythe.io/kythe/proto/go_go_proto"
	_ "kythe.io/kythe/proto/java_go_proto"
)

func init() {
	flag.Usage = flagutil.SimpleUsage("Print a .kindex archive as JSON to stdout",
		"[--files] <kindex-file>")
}

var (
	printFiles = flag.Bool("files", false, "Print all file contents as well as the compilation")
	printFile  = flag.String("file", "", "Only print the file contents for the given digest")

	m = &jsonpb.Marshaler{
		OrigName: true,
	}
)

func main() {
	flag.Parse()
	if len(flag.Args()) == 0 {
		flagutil.UsageError("missing kindex-file path")
	} else if len(flag.Args()) > 1 {
		flagutil.UsageErrorf("unknown arguments: %v", flag.Args()[1:])
	}

	path := flag.Arg(0)
	idx, err := kindex.Open(context.Background(), path)
	if err != nil {
		log.Fatalf("Error reading %q: %v", path, err)
	}

	out := os.Stdout
	if *printFiles {
		if err := json.NewEncoder(out).Encode(idx); err != nil {
			log.Fatalf("Error encoding JSON: %v", err)
		}
	} else if *printFile != "" {
		for _, f := range idx.Files {
			if f.Info.GetDigest() == *printFile {
				if _, err := os.Stdout.Write(f.Content); err != nil {
					log.Fatal(err)
				}
				return
			}
		}
		log.Fatalf("File digest %q not found", *printFile)
	} else {
		if err := m.Marshal(out, idx.Proto); err != nil {
			log.Fatalf("Error encoding JSON compilation: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Knorkebrot/fatberris/fatberris-lib"
	"fmt"
	"net/http"
	"net/http/fcgi"
	"time"
	"log"
)

type cacheObj struct {
	updated time.Time
	value string
}

var (
	cache map[string]cacheObj = make(map[string]cacheObj, 4)
)

const (
	PAGE string = `<!DOCTYPE html>

	<title>Fat Berri's m3u</title>
	<meta name="viewport" content="width=device-width" />

What's your mood today?

Chill
		   Up
		   Down
		   Mix

Streams provided by Fat Berri's

			  Converter by bo (kbct.de)

			  Source code available at github.com

`
)

func output(w http.ResponseWriter, name, out string) {
	w.Header().Set("Content-Type", "audio/x-mpegurl; charset=utf-8")
	w.Header().Set("Content-Disposition", "attachment; filename=" + name + ".m3u")
	fmt.Fprint(w, out)
}

func handler(w http.ResponseWriter, r *http.Request) {
	mood := r.FormValue("mood")

	if mood == "" {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, PAGE)
		return;
	}

	if c, ok := cache[mood]; ok && time.Since(c.updated).Hours() < 24 {
		log.Printf("cached: %s\n", mood)
		output(w, mood, cache[mood].value)
		return
	}

	out, err := fatberris.GetM3u([]string{mood})
	if err != nil {
		http.Error(w, fmt.Sprintf("%v", err), http.StatusInternalServerError)
		return
	}
	log.Printf("fetched: %s\n", mood)

	cache[mood] = cacheObj{time.Now(), out}

	output(w, mood, out)
}

func main() {
	err := fcgi.Serve(nil, http.HandlerFunc(handler))
	//err := http.ListenAndServe("localhost:1234", http.HandlerFunc(handler))
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>style<commit_after>package main

import (
	"github.com/Knorkebrot/fatberris/fatberris-lib"
	"fmt"
	"net/http"
	"net/http/fcgi"
	"time"
	"log"
)

type cacheObj struct {
	updated time.Time
	value string
}

var (
	cache map[string]cacheObj = make(map[string]cacheObj, 4)
)

const (
	PAGE string = `<!DOCTYPE html>

	<title>Fat Berri's m3u</title>
	<meta name="viewport" content="width=device-width" />

What's your mood today?

Chill
		   Up
		   Down
		   Mix

Streams provided by Fat Berri's

			  Converter by bo (kbct.de)

			  Source code available at github.com

`
)

func output(w http.ResponseWriter, name, out string) {
	w.Header().Set("Content-Type", "audio/x-mpegurl; charset=utf-8")
	w.Header().Set("Content-Disposition", "attachment; filename=" + name + ".m3u")
	fmt.Fprint(w, out)
}

func handler(w http.ResponseWriter, r *http.Request) {
	mood := r.FormValue("mood")

	if mood == "" {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, PAGE)
		return;
	}

	if c, ok := cache[mood]; ok && time.Since(c.updated).Hours() < 24 {
		log.Printf("cached: %s\n", mood)
		output(w, mood, cache[mood].value)
		return
	}

	out, err := fatberris.GetM3u([]string{mood})
	if err != nil {
		http.Error(w, fmt.Sprintf("%v", err), http.StatusInternalServerError)
		return
	}
	log.Printf("fetched: %s\n", mood)

	cache[mood] = cacheObj{time.Now(), out}

	output(w, mood, out)
}

func main() {
	err := fcgi.Serve(nil, http.HandlerFunc(handler))
	//err := http.ListenAndServe("localhost:1234", http.HandlerFunc(handler))
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package gateway

import (
	"errors"
	"net"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

const (
	maxSharedNodes = 10
	minPeers       = 3
)

var (
	errNodeExists = errors.New("node already added")
	errOurAddress = errors.New("can't add our own address")
)

// addNode adds an address to the set of nodes on the network.
func (g *Gateway) addNode(addr modules.NetAddress) error {
	if addr == g.myAddr {
		return errOurAddress
	} else if _, exists := g.nodes[addr]; exists {
		return errNodeExists
	} else if addr.IsValid() != nil {
		return errors.New("address is not valid: " + string(addr))
	} else if net.ParseIP(addr.Host()) == nil {
		return errors.New("address must be an IP address: " + string(addr))
	}
	g.nodes[addr] = struct{}{}
	return nil
}

func (g *Gateway) removeNode(addr modules.NetAddress) error {
	if _, exists := g.nodes[addr]; !exists {
		return errors.New("no record of that node")
	}
	delete(g.nodes, addr)
	return nil
}

func (g *Gateway) randomNode() (modules.NetAddress, error) {
	if len(g.nodes) > 0 {
		r, _ := crypto.RandIntn(len(g.nodes))
		for node := range g.nodes {
			if r <= 0 {
				return node, nil
			}
			r--
		}
	}

	return "", errNoPeers
}

// shareNodes is the receiving end of the ShareNodes RPC. It writes up to 10
// randomly selected nodes to the caller.
func (g *Gateway) shareNodes(conn modules.PeerConn) error {
	g.mu.RLock()
	var nodes []modules.NetAddress
	for node := range g.nodes {
		if len(nodes) == maxSharedNodes {
			break
		}
		nodes = append(nodes, node)
	}
	g.mu.RUnlock()
	return encoding.WriteObject(conn, nodes)
}

// requestNodes is the calling end of the ShareNodes RPC.
func (g *Gateway) requestNodes(conn modules.PeerConn) error {
	var nodes []modules.NetAddress
	if err := encoding.ReadObject(conn, &nodes, maxSharedNodes*modules.MaxEncodedNetAddressLength); err != nil {
		return err
	}
	g.mu.Lock()
	for _, node := range nodes {
		err := g.addNode(node)
		if err != nil && err != errNodeExists && err != errOurAddress {
			g.log.Printf("WARN: peer '%v' sent the invalid addr '%v'", conn.RPCAddr(), node)
		}
	}
	g.save()
	g.mu.Unlock()
	return nil
}

// threadedNodeManager tries to keep the Gateway's node list healthy. As long
// as the Gateway has fewer than minNodeListSize nodes, it asks a random peer
// for more nodes. It also continually pings nodes in order to establish their
// connectivity. Unresponsive nodes are aggressively removed.
func (g *Gateway) threadedNodeManager() {
	if g.threads.Add() != nil {
		return
	}
	defer g.threads.Done()

	for {
		select {
		case <-time.After(5 * time.Second):
		case <-g.threads.StopChan():
			return
		}

		g.mu.RLock()
		numNodes := len(g.nodes)
		peer, err := g.randomPeer()
		g.mu.RUnlock()
		if err != nil {
			// can't do much until we have peers
			continue
		}

		if numNodes < minNodeListLen {
			err := g.RPC(peer, "ShareNodes", g.requestNodes)
			if err != nil {
				g.log.Debugf("WARN: RPC ShareNodes failed on peer %q: %v", peer, err)
				continue
			}
		}

		// find an untested node to check
		g.mu.RLock()
		node, err := g.randomNode()
		g.mu.RUnlock()
		if err != nil {
			continue
		}

		// try to connect
		conn, err := net.DialTimeout("tcp", string(node), dialTimeout)
		if err != nil {
			g.mu.Lock()
			g.removeNode(node)
			g.save()
			g.mu.Unlock()
			g.log.Debugf("INFO: removing node %q because dialing it failed: %v", node, err)
			continue
		}
		// if connection succeeds, supply an unacceptable version to ensure
		// they won't try to add us as a peer
		encoding.WriteObject(conn, "0.0.0")
		conn.Close()
		// sleep for an extra 10 minutes after success; we don't want to spam
		// connectable nodes
		select {
		case <-time.After(10 * time.Minute):
		case <-g.threads.StopChan():
			return
		}
	}
}
<commit_msg>clean up gateway.randomNode<commit_after>package gateway

import (
	"errors"
	"net"
	"time"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
)

const (
	maxSharedNodes = 10
	minPeers       = 3
)

var (
	errNodeExists = errors.New("node already added")
	errOurAddress = errors.New("can't add our own address")
)

// addNode adds an address to the set of nodes on the network.
func (g *Gateway) addNode(addr modules.NetAddress) error {
	if addr == g.myAddr {
		return errOurAddress
	} else if _, exists := g.nodes[addr]; exists {
		return errNodeExists
	} else if addr.IsValid() != nil {
		return errors.New("address is not valid: " + string(addr))
	} else if net.ParseIP(addr.Host()) == nil {
		return errors.New("address must be an IP address: " + string(addr))
	}
	g.nodes[addr] = struct{}{}
	return nil
}

// removeNode will remove a node from the gateway.
func (g *Gateway) removeNode(addr modules.NetAddress) error {
	if _, exists := g.nodes[addr]; !exists {
		return errors.New("no record of that node")
	}
	delete(g.nodes, addr)
	return nil
}

// randomNode returns a random node from the gateway. An error can be returned
func (g *Gateway) randomNode() (modules.NetAddress, error) {
	if len(g.nodes) == 0 {
		return "", errNoPeers
	}

	// Select a random peer. Note that the algorithm below is roughly linear in
	// the number of nodes known by the gateway, and this number can approach
	// every node on the network. If the network gets large, this algorithm
	// will either need to be refactored, or more likely a cap on the size of
	// g.nodes will need to be added.
	r, err := crypto.RandIntn(len(g.nodes))
	if err != nil {
		return err
	}
	for node := range g.nodes {
		if r <= 0 {
			return node, nil
		}
		r--
	}

	return "", errNoPeers
}

// shareNodes is the receiving end of the ShareNodes RPC. It writes up to 10
// randomly selected nodes to the caller.
func (g *Gateway) shareNodes(conn modules.PeerConn) error {
	g.mu.RLock()
	var nodes []modules.NetAddress
	for node := range g.nodes {
		if len(nodes) == maxSharedNodes {
			break
		}
		nodes = append(nodes, node)
	}
	g.mu.RUnlock()
	return encoding.WriteObject(conn, nodes)
}

// requestNodes is the calling end of the ShareNodes RPC.
func (g *Gateway) requestNodes(conn modules.PeerConn) error {
	var nodes []modules.NetAddress
	if err := encoding.ReadObject(conn, &nodes, maxSharedNodes*modules.MaxEncodedNetAddressLength); err != nil {
		return err
	}
	g.mu.Lock()
	for _, node := range nodes {
		err := g.addNode(node)
		if err != nil && err != errNodeExists && err != errOurAddress {
			g.log.Printf("WARN: peer '%v' sent the invalid addr '%v'", conn.RPCAddr(), node)
		}
	}
	g.save()
	g.mu.Unlock()
	return nil
}

// threadedNodeManager tries to keep the Gateway's node list healthy. As long
// as the Gateway has fewer than minNodeListSize nodes, it asks a random peer
// for more nodes. It also continually pings nodes in order to establish their
// connectivity. Unresponsive nodes are aggressively removed.
func (g *Gateway) threadedNodeManager() {
	if g.threads.Add() != nil {
		return
	}
	defer g.threads.Done()

	for {
		select {
		case <-time.After(5 * time.Second):
		case <-g.threads.StopChan():
			return
		}

		g.mu.RLock()
		numNodes := len(g.nodes)
		peer, err := g.randomPeer()
		g.mu.RUnlock()
		if err != nil {
			// can't do much until we have peers
			continue
		}

		if numNodes < minNodeListLen {
			err := g.RPC(peer, "ShareNodes", g.requestNodes)
			if err != nil {
				g.log.Debugf("WARN: RPC ShareNodes failed on peer %q: %v", peer, err)
				continue
			}
		}

		// find an untested node to check
		g.mu.RLock()
		node, err := g.randomNode()
		g.mu.RUnlock()
		if err != nil {
			continue
		}

		// try to connect
		conn, err := net.DialTimeout("tcp", string(node), dialTimeout)
		if err != nil {
			g.mu.Lock()
			g.removeNode(node)
			g.save()
			g.mu.Unlock()
			g.log.Debugf("INFO: removing node %q because dialing it failed: %v", node, err)
			continue
		}
		// if connection succeeds, supply an unacceptable version to ensure
		// they won't try to add us as a peer
		encoding.WriteObject(conn, "0.0.0")
		conn.Close()
		// sleep for an extra 10 minutes after success; we don't want to spam
		// connectable nodes
		select {
		case <-time.After(10 * time.Minute):
		case <-g.threads.StopChan():
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"

	"github.com/dickeyxxx/golock"
	"github.com/heroku/heroku-cli/gode"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Name     string     `json:"name"`
	Version  string     `json:"version"`
	Topics   TopicSet   `json:"topics"`
	Topic    *Topic     `json:"topic"`
	Commands CommandSet `json:"commands"`
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	gode.SetRootPath(AppDir())
	setup, err := gode.IsSetup()
	PrintError(err)
	if !setup {
		setupNode()
	}
}

func setupNode() {
	Err("heroku-cli: Adding dependencies...")
	PrintError(gode.Setup())
	Errln(" done")
}

func updateNode() {
	gode.SetRootPath(AppDir())
	needsUpdate, err := gode.NeedsUpdate()
	PrintError(err)
	if needsUpdate {
		setupNode()
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins map[string]*Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		if plugin.Topic != nil {
			cli.AddTopic(plugin.Topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errf("WARNING: command %s has already been defined\n", command)
			}
		}
	}
	sort.Sort(cli.Topics)
	sort.Sort(cli.Commands)
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		err := installPlugins(name)
		ExitIfError(err)
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("\nThis does not appear to be a Heroku plugin, uninstalling... ")
			ExitIfError(gode.RemovePackage(name))
		}
		AddPluginsToCache(plugin)
		Errln("done")
	},
}

var pluginsLinkCmd = &Command{
	Topic:       "plugins",
	Command:     "link",
	Description: "Links a local plugin into CLI",
	Args:        []Arg{{Name: "path", Optional: true}},
	Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into ~/.heroku/node_modules

  Example:
	$ heroku plugins:link .`,

	Run: func(ctx *Context) {
		path := ctx.Args.(map[string]string)["path"]
		if path == "" {
			path = "."
		}
		path, err := filepath.Abs(path)
		if err != nil {
			panic(err)
		}
		if _, err := os.Stat(path); err != nil {
			panic(err)
		}
		name := filepath.Base(path)
		newPath := filepath.Join(ctx.HerokuDir, "node_modules", name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		err = os.Symlink(path, newPath)
		if err != nil {
			panic(err)
		}
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Errln(name + " does not appear to be a Heroku plugin.\nDid you run `npm install`?")
			if err := os.Remove(newPath); err != nil {
				panic(err)
			}
			return
		}
		if name != plugin.Name {
			path = newPath
			newPath = filepath.Join(ctx.HerokuDir, "node_modules", plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		Println("symlinked", plugin.Name)
		Err("Updating plugin cache... ")
		AddPluginsToCache(plugin)
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		err := gode.RemovePackage(name)
		ExitIfError(err)
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Hidden:      true,
	Description: "Lists installed plugins",
	Help: `
Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		for _, plugin := range GetPlugins() {
			if len(plugin.Commands) > 0 {
				Println(plugin.Name, plugin.Version)
			}
		}
	},
}

func runFn(plugin *Plugin, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		lockfile := updateLockPath + "." + plugin.Name
		if exists, _ := fileExists(lockfile); exists {
			golock.Lock(lockfile)
			golock.Unlock(lockfile)
		}
		ctx.Dev = isPluginSymlinked(plugin.Name)
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		title, _ := json.Marshal(processTitle(ctx))
		script := fmt.Sprintf(`
		'use strict';
		var moduleName = '%s';
		var moduleVersion = '%s';
		var topic = '%s';
		var command = '%s';
		process.title = %s;
		var ctx = %s;
		ctx.version = ctx.version + ' ' + moduleName + '/' + moduleVersion + ' node-' + process.version;
		var logPath = %s;
		process.chdir(ctx.cwd);
		function repair (name) {
			console.error('Attempting to repair ' + name + '...');
			require('child_process')
			.spawnSync('heroku', ['plugins:install', name],
			{stdio: [0,1,2]});
			console.error('Repair complete. Try running your command again.');
		}
		if (!ctx.dev) {
			process.on('uncaughtException', function (err) {
				console.error(' !   Error in ' + moduleName + ':')
				if (err.message) {
					console.error(' !   ' + err.message);
					if (err.message.indexOf('Cannot find module') != -1) {
						repair(moduleName);
						process.exit(1);
					}
				} else {
					console.error(' !   ' + err);
				}
				if (err.stack) {
					var fs = require('fs');
					var log = function (line) {
						var d = new Date().toISOString()
						.replace(/T/, ' ')
						.replace(/-/g, '/')
						.replace(/\..+/, '');
						fs.appendFileSync(logPath, d + ' ' + line + '\n');
					}
					log('Error during ' + topic + ':' + command);
					log(err.stack);
					console.error(' !   See ' + logPath + ' for more info.');
				}
				process.exit(1);
			});
		}
		if (command === '') { command = null }
		var module = require(moduleName);
		var cmd = module.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0];
		cmd.run(ctx);`, plugin.Name, plugin.Version, topic, command, string(title), ctxJSON, strconv.Quote(ErrLogPath))

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := gode.RunScript(script)
		if ctx.Flags["debugger"] == true {
			cmd = gode.DebugScript(script)
		}
		os.Chdir(cmd.Dir)
		execBin(cmd.Path, cmd.Args)
	}
}

func execBin(bin string, args []string) {
	if runtime.GOOS == "windows" {
		cmd := exec.Command(bin, args[1:]...)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			os.Exit(getExitCode(err))
		}
	} else {
		if err := syscall.Exec(bin, args, os.Environ()); err != nil {
			panic(err)
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	switch e := err.(type) {
	case *exec.ExitError:
		status, ok := e.Sys().(syscall.WaitStatus)
		if !ok {
			panic(err)
		}
		return status.ExitStatus()
	default:
		panic(err)
	}
}

func getPlugin(name string, attemptReinstall bool) *Plugin {
	script := `
	var plugin = require('` + name + `');
	if (!plugin.commands) plugin = {}; // not a real plugin
	var pjson  = require('` + name + `/package.json');

	plugin.name    = pjson.name;
	plugin.version = pjson.version;

	console.log(JSON.stringify(plugin))`
	cmd := gode.RunScript(script)
	output, err := cmd.CombinedOutput()
	if err != nil {
		if attemptReinstall && strings.Contains(string(output), "Error: Cannot find module") {
			Errf("Error reading plugin %s. Reinstalling... ", name)
			if err := installPlugins(name); err != nil {
				panic(errors.New(name + ": " + string(output)))
			}
			Errln("done")
			return getPlugin(name, false)
		}
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err, "\n", string(output))
		return nil
	}
	var plugin Plugin
	json.Unmarshal([]byte(output), &plugin)
	for _, command := range plugin.Commands {
		command.Plugin = plugin.Name
		command.Help = strings.TrimSpace(command.Help)
	}
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() map[string]*Plugin {
	plugins := FetchPluginCache()
	for _, plugin := range plugins {
		for _, command := range plugin.Commands {
			command.Run = runFn(plugin, command.Topic, command.Command)
		}
	}
	return plugins
}

// PluginNames lists all the plugin names
func PluginNames() []string {
	plugins := FetchPluginCache()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		names = append(names, plugin.Name)
	}
	return names
}

// PluginNamesNotSymlinked returns all the plugins that are not symlinked
func PluginNamesNotSymlinked() []string {
	a := PluginNames()
	b := make([]string, 0, len(a))
	for _, plugin := range a {
		if !isPluginSymlinked(plugin) {
			b = append(b, plugin)
		}
	}
	return b
}

func isPluginSymlinked(plugin string) bool {
	path := filepath.Join(AppDir(), "node_modules", plugin)
	fi, err := os.Lstat(path)
	if err != nil {
		panic(err)
	}
	return fi.Mode()&os.ModeSymlink != 0
}

// SetupBuiltinPlugins ensures all the builtinPlugins are installed
func SetupBuiltinPlugins() {
	pluginNames := difference(BuiltinPlugins, PluginNames())
	if len(pluginNames) == 0 {
		return
	}
	Err("heroku-cli: Installing core plugins...")
	err := installPlugins(pluginNames...)
	if err != nil {
		Errln()
		PrintError(err)
		return
	}
	plugins := make([]*Plugin, 0, len(pluginNames))
	for _, name := range pluginNames {
		plugins = append(plugins, getPlugin(name, false))
	}
	AddPluginsToCache(plugins...)
	Errln(" done")
}

func difference(a, b []string) []string {
	res := make([]string, 0, len(a))
	for _, aa := range a {
		if !contains(b, aa) {
			res = append(res, aa)
		}
	}
	return res
}

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

func installPlugins(plugins ...string) error {
	for _, plugin := range plugins {
		lockfile := updateLockPath + "." + plugin
		LogIfError(golock.Lock(lockfile))
	}
	err := gode.InstallPackage(plugins...)
	for _, plugin := range plugins {
		lockfile := updateLockPath + "." + plugin
		LogIfError(golock.Unlock(lockfile))
	}
	return err
}
<commit_msg>reinstall missing plugins<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"

	"github.com/dickeyxxx/golock"
	"github.com/heroku/heroku-cli/gode"
)

// Plugin represents a javascript plugin
type Plugin struct {
	Name     string     `json:"name"`
	Version  string     `json:"version"`
	Topics   TopicSet   `json:"topics"`
	Topic    *Topic     `json:"topic"`
	Commands CommandSet `json:"commands"`
}

// SetupNode sets up node and npm in ~/.heroku
func SetupNode() {
	gode.SetRootPath(AppDir())
	setup, err := gode.IsSetup()
	PrintError(err)
	if !setup {
		setupNode()
	}
}

func setupNode() {
	Err("heroku-cli: Adding dependencies...")
	PrintError(gode.Setup())
	Errln(" done")
}

func updateNode() {
	gode.SetRootPath(AppDir())
	needsUpdate, err := gode.NeedsUpdate()
	PrintError(err)
	if needsUpdate {
		setupNode()
	}
}

// LoadPlugins loads the topics and commands from the JavaScript plugins into the CLI
func (cli *Cli) LoadPlugins(plugins map[string]*Plugin) {
	for _, plugin := range plugins {
		for _, topic := range plugin.Topics {
			cli.AddTopic(topic)
		}
		if plugin.Topic != nil {
			cli.AddTopic(plugin.Topic)
		}
		for _, command := range plugin.Commands {
			if !cli.AddCommand(command) {
				Errf("WARNING: command %s has already been defined\n", command)
			}
		}
	}
	sort.Sort(cli.Topics)
	sort.Sort(cli.Commands)
}

var pluginsTopic = &Topic{
	Name:        "plugins",
	Description: "manage plugins",
}

var pluginsInstallCmd = &Command{
	Topic:       "plugins",
	Command:     "install",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Installs a plugin into the CLI",
	Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install dickeyxxx/heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		if len(name) == 0 {
			Errln("Must specify a plugin name")
			return
		}
		Errf("Installing plugin %s... ", name)
		err := installPlugins(name)
		ExitIfError(err)
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Err("\nThis does not appear to be a Heroku plugin, uninstalling... ")
			ExitIfError(gode.RemovePackage(name))
		}
		Errln("done")
	},
}

var pluginsLinkCmd = &Command{
	Topic:       "plugins",
	Command:     "link",
	Description: "Links a local plugin into CLI",
	Args:        []Arg{{Name: "path", Optional: true}},
	Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into ~/.heroku/node_modules

  Example:
	$ heroku plugins:link .`,

	Run: func(ctx *Context) {
		path := ctx.Args.(map[string]string)["path"]
		if path == "" {
			path = "."
		}
		path, err := filepath.Abs(path)
		if err != nil {
			panic(err)
		}
		if _, err := os.Stat(path); err != nil {
			panic(err)
		}
		name := filepath.Base(path)
		newPath := filepath.Join(ctx.HerokuDir, "node_modules", name)
		os.Remove(newPath)
		os.RemoveAll(newPath)
		err = os.Symlink(path, newPath)
		if err != nil {
			panic(err)
		}
		plugin := getPlugin(name, false)
		if plugin == nil || len(plugin.Commands) == 0 {
			Errln(name + " does not appear to be a Heroku plugin.\nDid you run `npm install`?")
			if err := os.Remove(newPath); err != nil {
				panic(err)
			}
			return
		}
		if name != plugin.Name {
			path = newPath
			newPath = filepath.Join(ctx.HerokuDir, "node_modules", plugin.Name)
			os.Remove(newPath)
			os.RemoveAll(newPath)
			os.Rename(path, newPath)
		}
		Println("symlinked", plugin.Name)
		Err("Updating plugin cache... ")
		AddPluginsToCache(plugin)
		Errln("done")
	},
}

var pluginsUninstallCmd = &Command{
	Topic:       "plugins",
	Command:     "uninstall",
	Hidden:      true,
	Args:        []Arg{{Name: "name"}},
	Description: "Uninstalls a plugin from the CLI",
	Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

	Run: func(ctx *Context) {
		name := ctx.Args.(map[string]string)["name"]
		Errf("Uninstalling plugin %s... ", name)
		err := gode.RemovePackage(name)
		ExitIfError(err)
		Errln("done")
	},
}

var pluginsListCmd = &Command{
	Topic:       "plugins",
	Hidden:      true,
	Description: "Lists installed plugins",
	Help: `
Example:
  $ heroku plugins`,

	Run: func(ctx *Context) {
		for _, plugin := range GetPlugins() {
			if len(plugin.Commands) > 0 {
				Println(plugin.Name, plugin.Version)
			}
		}
	},
}

func runFn(plugin *Plugin, topic, command string) func(ctx *Context) {
	return func(ctx *Context) {
		lockfile := updateLockPath + "." + plugin.Name
		if exists, _ := fileExists(lockfile); exists {
			golock.Lock(lockfile)
			golock.Unlock(lockfile)
		}
		checkIfPluginIsInstalled(plugin.Name)
		ctx.Dev = isPluginSymlinked(plugin.Name)
		ctxJSON, err := json.Marshal(ctx)
		if err != nil {
			panic(err)
		}
		title, _ := json.Marshal(processTitle(ctx))
		script := fmt.Sprintf(`
		'use strict';
		var moduleName = '%s';
		var moduleVersion = '%s';
		var topic = '%s';
		var command = '%s';
		process.title = %s;
		var ctx = %s;
		ctx.version = ctx.version + ' ' + moduleName + '/' + moduleVersion + ' node-' + process.version;
		var logPath = %s;
		process.chdir(ctx.cwd);
		function repair (name) {
			console.error('Attempting to repair ' + name + '...');
			require('child_process')
			.spawnSync('heroku', ['plugins:install', name],
			{stdio: [0,1,2]});
			console.error('Repair complete. Try running your command again.');
		}
		if (!ctx.dev) {
			process.on('uncaughtException', function (err) {
				console.error(' !   Error in ' + moduleName + ':')
				if (err.message) {
					console.error(' !   ' + err.message);
					if (err.message.indexOf('Cannot find module') != -1) {
						repair(moduleName);
						process.exit(1);
					}
				} else {
					console.error(' !   ' + err);
				}
				if (err.stack) {
					var fs = require('fs');
					var log = function (line) {
						var d = new Date().toISOString()
						.replace(/T/, ' ')
						.replace(/-/g, '/')
						.replace(/\..+/, '');
						fs.appendFileSync(logPath, d + ' ' + line + '\n');
					}
					log('Error during ' + topic + ':' + command);
					log(err.stack);
					console.error(' !   See ' + logPath + ' for more info.');
				}
				process.exit(1);
			});
		}
		if (command === '') { command = null }
		var module = require(moduleName);
		var cmd = module.commands.filter(function (c) {
			return c.topic === topic && c.command == command;
		})[0];
		cmd.run(ctx);`, plugin.Name, plugin.Version, topic, command, string(title), ctxJSON, strconv.Quote(ErrLogPath))

		// swallow sigint since the plugin will handle it
		swallowSignal(os.Interrupt)

		cmd := gode.RunScript(script)
		if ctx.Flags["debugger"] == true {
			cmd = gode.DebugScript(script)
		}
		os.Chdir(cmd.Dir)
		execBin(cmd.Path, cmd.Args)
	}
}

func execBin(bin string, args []string) {
	if runtime.GOOS == "windows" {
		cmd := exec.Command(bin, args[1:]...)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			os.Exit(getExitCode(err))
		}
	} else {
		if err := syscall.Exec(bin, args, os.Environ()); err != nil {
			panic(err)
		}
	}
}

func swallowSignal(s os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, s)
	go func() {
		<-c
	}()
}

func getExitCode(err error) int {
	switch e := err.(type) {
	case *exec.ExitError:
		status, ok := e.Sys().(syscall.WaitStatus)
		if !ok {
			panic(err)
		}
		return status.ExitStatus()
	default:
		panic(err)
	}
}

func getPlugin(name string, attemptReinstall bool) *Plugin {
	script := `
	var plugin = require('` + name + `');
	if (!plugin.commands) plugin = {}; // not a real plugin
	var pjson  = require('` + name + `/package.json');

	plugin.name    = pjson.name;
	plugin.version = pjson.version;

	console.log(JSON.stringify(plugin))`
	cmd := gode.RunScript(script)
	output, err := cmd.CombinedOutput()
	if err != nil {
		if attemptReinstall && strings.Contains(string(output), "Error: Cannot find module") {
			Errf("Error reading plugin %s. Reinstalling... ", name)
			if err := installPlugins(name); err != nil {
				panic(errors.New(name + ": " + string(output)))
			}
			Errln("done")
			return getPlugin(name, false)
		}
		Errf("Error reading plugin: %s. See %s for more information.\n", name, ErrLogPath)
		Logln(err, "\n", string(output))
		return nil
	}
	var plugin Plugin
	json.Unmarshal([]byte(output), &plugin)
	for _, command := range plugin.Commands {
		command.Plugin = plugin.Name
		command.Help = strings.TrimSpace(command.Help)
	}
	return &plugin
}

// GetPlugins goes through all the node plugins and returns them in Go stucts
func GetPlugins() map[string]*Plugin {
	plugins := FetchPluginCache()
	for _, plugin := range plugins {
		for _, command := range plugin.Commands {
			command.Run = runFn(plugin, command.Topic, command.Command)
		}
	}
	return plugins
}

// PluginNames lists all the plugin names
func PluginNames() []string {
	plugins := FetchPluginCache()
	names := make([]string, 0, len(plugins))
	for _, plugin := range plugins {
		names = append(names, plugin.Name)
	}
	return names
}

// PluginNamesNotSymlinked returns all the plugins that are not symlinked
func PluginNamesNotSymlinked() []string {
	a := PluginNames()
	b := make([]string, 0, len(a))
	for _, plugin := range a {
		if !isPluginSymlinked(plugin) {
			b = append(b, plugin)
		}
	}
	return b
}

func isPluginSymlinked(plugin string) bool {
	path := filepath.Join(AppDir(), "node_modules", plugin)
	fi, err := os.Lstat(path)
	if err != nil {
		panic(err)
	}
	return fi.Mode()&os.ModeSymlink != 0
}

// SetupBuiltinPlugins ensures all the builtinPlugins are installed
func SetupBuiltinPlugins() {
	pluginNames := difference(BuiltinPlugins, PluginNames())
	if len(pluginNames) == 0 {
		return
	}
	Err("heroku-cli: Installing core plugins...")
	err := installPlugins(pluginNames...)
	if err != nil {
		Errln()
		PrintError(err)
		return
	}
	Errln(" done")
}

func difference(a, b []string) []string {
	res := make([]string, 0, len(a))
	for _, aa := range a {
		if !contains(b, aa) {
			res = append(res, aa)
		}
	}
	return res
}

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

func installPlugins(names ...string) error {
	for _, name := range names {
		lockfile := updateLockPath + "." + name
		LogIfError(golock.Lock(lockfile))
	}
	err := gode.InstallPackage(names...)
	plugins := make([]*Plugin, 0, len(names))
	for _, name := range names {
		plugins = append(plugins, getPlugin(name, false))
	}
	AddPluginsToCache(plugins...)
	for _, name := range names {
		lockfile := updateLockPath + "." + name
		LogIfError(golock.Unlock(lockfile))
	}
	return err
}

func checkIfPluginIsInstalled(plugin string) {
	if exists, _ := fileExists(filepath.Join(AppDir(), "node_modules", plugin)); !exists {
		installPlugins(plugin)
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"github.com/gin-gonic/gin"
	"regexp"
)

func If_Written(handler func(*gin.Context)) func(*gin.Context) { // Runs handler if the content is already written.
	return func(c *gin.Context) {
		if c.Writer.Written() {
			handler(c)
		}
	}
}

func If_Regexp(regex string, handler func(*gin.Context)) (func(*gin.Context), error) { // Runs if the URL matches the given regexp, otherwise does nothing.
	expr, err := regexp.Compile(regex)
	if err != nil {
		return nil, err
	}
	return func(c *gin.Context) {
		if regexp.MatchString(expr, c.Request.URL.Path) {
			handler(c)
		}
	}, nil
}

func If_Status(status int, handler func(*gin.Context)) func(*gin.Context) {
	return func(c *gin.Context) {
		if c.Writer.Status() == status {
			handler(c)
		}
	}
}

// And below the inverted..

func If_Not_Written(handler func(*gin.Context)) func(*gin.Context) { // Runs handler if the content is already written.
	return func(c *gin.Context) {
		if !c.Writer.Written() {
			handler(c)
		}
	}
}

func If_Not_Regexp(regex string, handler func(*gin.Context)) (func(*gin.Context), error) { // Runs if the URL matches the given regexp, otherwise does nothing.
	expr, err := regexp.Compile(regex)
	if err != nil {
		return nil, err
	}
	return func(c *gin.Context) {
		if !regexp.MatchString(expr, c.Request.URL.Path) {
			handler(c)
		}
	}, nil
}

func If_Not_Status(status int, handler func(*gin.Context)) func(*gin.Context) {
	return func(c *gin.Context) {
		if c.Writer.Status() != status {
			handler(c)
		}
	}
}
<commit_msg>There are only so many things I can do wrong, but apparently I do all of them wrong.<commit_after>package middleware

import (
	"github.com/gin-gonic/gin"
	"regexp"
)

func If_Written(handler func(*gin.Context)) func(*gin.Context) { // Runs handler if the content is already written.
	return func(c *gin.Context) {
		if c.Writer.Written() {
			handler(c)
		}
	}
}

func If_Regexp(regex string, handler func(*gin.Context)) (func(*gin.Context), error) { // Runs if the URL matches the given regexp, otherwise does nothing.
	expr, err := regexp.Compile(regex)
	if err != nil {
		return nil, err
	}
	return func(c *gin.Context) {
		if expr.MatchString(c.Request.URL.Path) {
			handler(c)
		}
	}, nil
}

func If_Status(status int, handler func(*gin.Context)) func(*gin.Context) {
	return func(c *gin.Context) {
		if c.Writer.Status() == status {
			handler(c)
		}
	}
}

// And below the inverted..

func If_Not_Written(handler func(*gin.Context)) func(*gin.Context) { // Runs handler if the content is already written.
	return func(c *gin.Context) {
		if !c.Writer.Written() {
			handler(c)
		}
	}
}

func If_Not_Regexp(regex string, handler func(*gin.Context)) (func(*gin.Context), error) { // Runs if the URL matches the given regexp, otherwise does nothing.
	expr, err := regexp.Compile(regex)
	if err != nil {
		return nil, err
	}
	return func(c *gin.Context) {
		if !expr.MatchString(c.Request.URL.Path) {
			handler(c)
		}
	}, nil
}

func If_Not_Status(status int, handler func(*gin.Context)) func(*gin.Context) {
	return func(c *gin.Context) {
		if c.Writer.Status() != status {
			handler(c)
		}
	}
}
<|endoftext|>