<commit_before>/*
Copyright 2021 The Vitess Authors.

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 aggregation

import (
	"context"
	"testing"

	"vitess.io/vitess/go/test/endtoend/vtgate/utils"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/test/endtoend/cluster"
)

func TestAggregateTypes(t *testing.T) {
	defer cluster.PanicHandler(t)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'A',1), (3,'b',1), (4,'c',3), (5,'c',4)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(6,'d',null), (7,'e',null), (8,'E',1)")
	utils.AssertMatches(t, conn, "select val1, count(distinct val2), count(*) from aggr_test group by val1", `[[VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("d") INT64(0) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1, sum(distinct val2), sum(val2) from aggr_test group by val1", `[[VARCHAR("a") DECIMAL(1) DECIMAL(2)] [VARCHAR("b") DECIMAL(1) DECIMAL(1)] [VARCHAR("c") DECIMAL(7) DECIMAL(7)] [VARCHAR("d") NULL NULL] [VARCHAR("e") DECIMAL(1) DECIMAL(1)]]`)
	utils.AssertMatches(t, conn, "select val1, count(distinct val2) k, count(*) from aggr_test group by val1 order by k desc, val1", `[[VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)] [VARCHAR("d") INT64(0) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select val1, count(distinct val2) k, count(*) from aggr_test group by val1 order by k desc, val1 limit 4", `[[VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(99) INT64(2)] [INT64(100) INT64(1)] [INT64(101) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(99) INT64(2)] [INT64(100) INT64(1)] [INT64(101) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by 2, a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(100) INT64(1)] [INT64(101) INT64(1)] [INT64(99) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a", `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a order by a", `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a order by 2, a", `[[VARCHAR("b") INT64(1)] [VARCHAR("d") INT64(1)] [VARCHAR("a") INT64(2)] [VARCHAR("c") INT64(2)] [VARCHAR("e") INT64(2)]]`)
	utils.Exec(t, conn, "delete from aggr_test")
}

func TestGroupBy(t *testing.T) {
	defer cluster.PanicHandler(t)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into t3(id5, id6, id7) values(1,1,2), (2,2,4), (3,2,4), (4,1,2), (5,1,2), (6,3,6)")
	// test ordering and group by int column
	utils.AssertMatches(t, conn, "select id6, id7, count(*) k from t3 group by id6, id7 order by k", `[[INT64(3) INT64(6) INT64(1)] [INT64(2) INT64(4) INT64(2)] [INT64(1) INT64(2) INT64(3)]]`)

	defer func() {
		utils.Exec(t, conn, "set workload = oltp")
		utils.Exec(t, conn, "delete from t3")
	}()
	// Test the same queries in streaming mode
	utils.Exec(t, conn, "set workload = olap")
	utils.AssertMatches(t, conn, "select id6, id7, count(*) k from t3 group by id6, id7 order by k", `[[INT64(3) INT64(6) INT64(1)] [INT64(2) INT64(4) INT64(2)] [INT64(1) INT64(2) INT64(3)]]`)
}

func TestDistinct(t *testing.T) {
	defer cluster.PanicHandler(t)

	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into t3(id5,id6,id7) values(1,3,3), (2,3,4), (3,3,6), (4,5,7), (5,5,6)")
	utils.Exec(t, conn, "insert into t7_xxhash(uid,phone) values('1',4), ('2',4), ('3',3), ('4',1), ('5',1)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'A',1), (3,'b',1), (4,'c',3), (5,'c',4)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(6,'d',null), (7,'e',null), (8,'E',1)")
	utils.AssertMatches(t, conn, "select distinct val2, count(*) from aggr_test group by val2", `[[NULL INT64(2)] [INT64(1) INT64(4)] [INT64(3) INT64(1)] [INT64(4) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select distinct id6 from t3 join t7_xxhash on t3.id5 = t7_xxhash.phone", `[[INT64(3)] [INT64(5)]]`)
	utils.Exec(t, conn, "delete from t3")
	utils.Exec(t, conn, "delete from t7_xxhash")
	utils.Exec(t, conn, "delete from aggr_test")
}
<commit_msg>Addition of an end-to-end test for equality filter on scatter<commit_after>/*
Copyright 2021 The Vitess Authors.

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 aggregation

import (
	"context"
	"testing"

	"vitess.io/vitess/go/test/endtoend/vtgate/utils"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/test/endtoend/cluster"
)

func TestAggregateTypes(t *testing.T) {
	defer cluster.PanicHandler(t)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'A',1), (3,'b',1), (4,'c',3), (5,'c',4)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(6,'d',null), (7,'e',null), (8,'E',1)")
	utils.AssertMatches(t, conn, "select val1, count(distinct val2), count(*) from aggr_test group by val1", `[[VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("d") INT64(0) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1, sum(distinct val2), sum(val2) from aggr_test group by val1", `[[VARCHAR("a") DECIMAL(1) DECIMAL(2)] [VARCHAR("b") DECIMAL(1) DECIMAL(1)] [VARCHAR("c") DECIMAL(7) DECIMAL(7)] [VARCHAR("d") NULL NULL] [VARCHAR("e") DECIMAL(1) DECIMAL(1)]]`)
	utils.AssertMatches(t, conn, "select val1, count(distinct val2) k, count(*) from aggr_test group by val1 order by k desc, val1", `[[VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)] [VARCHAR("d") INT64(0) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select val1, count(distinct val2) k, count(*) from aggr_test group by val1 order by k desc, val1 limit 4", `[[VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(99) INT64(2)] [INT64(100) INT64(1)] [INT64(101) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(99) INT64(2)] [INT64(100) INT64(1)] [INT64(101) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by 2, a", `[[INT64(65) INT64(1)] [INT64(69) INT64(1)] [INT64(97) INT64(1)] [INT64(98) INT64(1)] [INT64(100) INT64(1)] [INT64(101) INT64(1)] [INT64(99) INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a", `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a order by a", `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`)
	utils.AssertMatches(t, conn, "select val1 as a, count(*) from aggr_test group by a order by 2, a", `[[VARCHAR("b") INT64(1)] [VARCHAR("d") INT64(1)] [VARCHAR("a") INT64(2)] [VARCHAR("c") INT64(2)] [VARCHAR("e") INT64(2)]]`)
	utils.Exec(t, conn, "delete from aggr_test")
}

func TestGroupBy(t *testing.T) {
	defer cluster.PanicHandler(t)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into t3(id5, id6, id7) values(1,1,2), (2,2,4), (3,2,4), (4,1,2), (5,1,2), (6,3,6)")
	// test ordering and group by int column
	utils.AssertMatches(t, conn, "select id6, id7, count(*) k from t3 group by id6, id7 order by k", `[[INT64(3) INT64(6) INT64(1)] [INT64(2) INT64(4) INT64(2)] [INT64(1) INT64(2) INT64(3)]]`)

	defer func() {
		utils.Exec(t, conn, "set workload = oltp")
		utils.Exec(t, conn, "delete from t3")
	}()
	// Test the same queries in streaming mode
	utils.Exec(t, conn, "set workload = olap")
	utils.AssertMatches(t, conn, "select id6, id7, count(*) k from t3 group by id6, id7 order by k", `[[INT64(3) INT64(6) INT64(1)] [INT64(2) INT64(4) INT64(2)] [INT64(1) INT64(2) INT64(3)]]`)
}

func TestDistinct(t *testing.T) {
	defer cluster.PanicHandler(t)

	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()
	utils.Exec(t, conn, "insert into t3(id5,id6,id7) values(1,3,3), (2,3,4), (3,3,6), (4,5,7), (5,5,6)")
	utils.Exec(t, conn, "insert into t7_xxhash(uid,phone) values('1',4), ('2',4), ('3',3), ('4',1), ('5',1)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'A',1), (3,'b',1), (4,'c',3), (5,'c',4)")
	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(6,'d',null), (7,'e',null), (8,'E',1)")
	utils.AssertMatches(t, conn, "select distinct val2, count(*) from aggr_test group by val2", `[[NULL INT64(2)] [INT64(1) INT64(4)] [INT64(3) INT64(1)] [INT64(4) INT64(1)]]`)
	utils.AssertMatches(t, conn, "select distinct id6 from t3 join t7_xxhash on t3.id5 = t7_xxhash.phone", `[[INT64(3)] [INT64(5)]]`)
	utils.Exec(t, conn, "delete from t3")
	utils.Exec(t, conn, "delete from t7_xxhash")
	utils.Exec(t, conn, "delete from aggr_test")
}

func TestEqualityFilterOnScatter(t *testing.T) {
	defer cluster.PanicHandler(t)
	ctx := context.Background()
	conn, err := mysql.Connect(ctx, &vtParams)
	require.Nil(t, err)
	defer conn.Close()

	utils.Exec(t, conn, "insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'b',2), (3,'c',3), (4,'d',4), (5,'e',5)")

	defer func() {
		utils.Exec(t, conn, "delete from aggr_test")
	}()

	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having 1 = 1", `[[INT64(5)]]`)     // where clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having a = 5", `[[INT64(5)]]`)     // having clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having 5 = a", `[[INT64(5)]]`)     // having clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having a = a", `[[INT64(5)]]`)     // having clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having a = 3+2", `[[INT64(5)]]`)   // having clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having 1+4 = 3+2", `[[INT64(5)]]`) // where clause
	utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having a = 1", `[]`)               // having clause
	// utils.AssertMatches(t, conn, "select /* GEN4_COMPARE_ONLY_GEN4 */ count(*) as a from aggr_test having 0 = 1", `[]`) // where clause, still returns one row with a value of 0
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic_test

import (
	"encoding/json"
	"testing"

	"gopkg.in/olivere/elastic.v3-unstable"
)

func ExampleWildcardQuery() {
	// Get a client to the local Elasticsearch instance.
	client, err := elastic.NewClient()
	if err != nil {
		// Handle error
		panic(err)
	}

	// Define wildcard query
	q := elastic.NewWildcardQuery("user", "oli*er?").Boost(1.2)
	searchResult, err := client.Search().
		Index("twitter"). // search in index "twitter"
		Query(q).         // use wildcard query defined above
		Do()              // execute
	if err != nil {
		// Handle error
		panic(err)
	}
	_ = searchResult
}

func TestWildcardQuery(t *testing.T) {
	q := elastic.NewWildcardQuery("user", "ki*y??")
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"wildcard":{"user":{"wildcard":"ki*y??"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}

func TestWildcardQueryWithBoost(t *testing.T) {
	q := elastic.NewWildcardQuery("user", "ki*y??").Boost(1.2)
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"wildcard":{"user":{"boost":1.2,"wildcard":"ki*y??"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}
<commit_msg>Fix package path in cluster-test<commit_after>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic_test

import (
	"encoding/json"
	"testing"

	"gopkg.in/olivere/elastic.v3"
)

func ExampleWildcardQuery() {
	// Get a client to the local Elasticsearch instance.
	client, err := elastic.NewClient()
	if err != nil {
		// Handle error
		panic(err)
	}

	// Define wildcard query
	q := elastic.NewWildcardQuery("user", "oli*er?").Boost(1.2)
	searchResult, err := client.Search().
		Index("twitter"). // search in index "twitter"
		Query(q).         // use wildcard query defined above
		Do()              // execute
	if err != nil {
		// Handle error
		panic(err)
	}
	_ = searchResult
}

func TestWildcardQuery(t *testing.T) {
	q := elastic.NewWildcardQuery("user", "ki*y??")
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"wildcard":{"user":{"wildcard":"ki*y??"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}

func TestWildcardQueryWithBoost(t *testing.T) {
	q := elastic.NewWildcardQuery("user", "ki*y??").Boost(1.2)
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"wildcard":{"user":{"boost":1.2,"wildcard":"ki*y??"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"encoding/json"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/cmd"
)

const (
	pingTime      = (readDeadline * 9) / 10
	readLimit     = 16384
	readDeadline  = 60 * time.Second
	writeDeadline = 10 * time.Second
)

type conn struct {
	cType string
	topic string
	queue string
	exit  chan bool

	sync.Mutex
	ws *websocket.Conn
}

var (
	once sync.Once

	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	contentType = "text/plain"
)

func (c *conn) readLoop() {
	defer func() {
		close(c.exit)
		c.ws.Close()
	}()

	c.ws.SetReadLimit(readLimit)
	c.ws.SetReadDeadline(time.Now().Add(readDeadline))
	c.ws.SetPongHandler(func(string) error {
		c.ws.SetReadDeadline(time.Now().Add(readDeadline))
		return nil
	})

	for {
		_, message, err := c.ws.ReadMessage()
		if err != nil {
			return
		}
		(*cmd.DefaultOptions().Broker).Publish(c.topic, &broker.Message{
			Header: map[string]string{"Content-Type": c.cType},
			Body:   message,
		})
	}
}

func (c *conn) write(mType int, data []byte) error {
	c.Lock()
	c.ws.SetWriteDeadline(time.Now().Add(writeDeadline))
	err := c.ws.WriteMessage(mType, data)
	c.Unlock()
	return err
}

func (c *conn) writeLoop() {
	ticker := time.NewTicker(pingTime)

	var opts []broker.SubscribeOption

	if len(c.queue) > 0 {
		opts = append(opts, broker.Queue(c.queue))
	}

	subscriber, err := (*cmd.DefaultOptions().Broker).Subscribe(c.topic, func(p broker.Publication) error {
		b, err := json.Marshal(p.Message())
		if err != nil {
			return nil
		}
		return c.write(websocket.TextMessage, b)
	}, opts...)

	defer func() {
		subscriber.Unsubscribe()
		ticker.Stop()
		c.ws.Close()
	}()

	if err != nil {
		log.Print(err.Error())
		return
	}

	for {
		select {
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		case <-c.exit:
			return
		}
	}
}

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

	r.ParseForm()
	topic := r.Form.Get("topic")
	if len(topic) == 0 {
		http.Error(w, "Topic not specified", 400)
		return
	}
	queue := r.Form.Get("queue")

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

	once.Do(func() {
		(*cmd.DefaultOptions().Broker).Init()
		(*cmd.DefaultOptions().Broker).Connect()
	})

	cType := r.Header.Get("Content-Type")
	if len(cType) == 0 {
		cType = contentType
	}

	c := &conn{
		cType: cType,
		topic: topic,
		queue: queue,
		exit:  make(chan bool),
		ws:    ws,
	}

	go c.writeLoop()
	c.readLoop()
}
<commit_msg>Handle connection close<commit_after>package handler

import (
	"encoding/json"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/cmd"
)

const (
	pingTime      = (readDeadline * 9) / 10
	readLimit     = 16384
	readDeadline  = 60 * time.Second
	writeDeadline = 10 * time.Second
)

type conn struct {
	cType string
	topic string
	queue string
	exit  chan bool

	sync.Mutex
	ws *websocket.Conn
}

var (
	once sync.Once

	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	contentType = "text/plain"
)

func (c *conn) close() {
	select {
	case <-c.exit:
		return
	default:
		close(c.exit)
	}
}

func (c *conn) readLoop() {
	defer func() {
		c.close()
		c.ws.Close()
	}()

	// set read limit/deadline
	c.ws.SetReadLimit(readLimit)
	c.ws.SetReadDeadline(time.Now().Add(readDeadline))

	// set close handler
	ch := c.ws.CloseHandler()
	c.ws.SetCloseHandler(func(code int, text string) error {
		err := ch(code, text)
		c.close()
		return err
	})

	// set pong handler
	c.ws.SetPongHandler(func(string) error {
		c.ws.SetReadDeadline(time.Now().Add(readDeadline))
		return nil
	})

	for {
		_, message, err := c.ws.ReadMessage()
		if err != nil {
			return
		}
		(*cmd.DefaultOptions().Broker).Publish(c.topic, &broker.Message{
			Header: map[string]string{"Content-Type": c.cType},
			Body:   message,
		})
	}
}

func (c *conn) write(mType int, data []byte) error {
	c.Lock()
	c.ws.SetWriteDeadline(time.Now().Add(writeDeadline))
	err := c.ws.WriteMessage(mType, data)
	c.Unlock()
	return err
}

func (c *conn) writeLoop() {
	ticker := time.NewTicker(pingTime)

	var opts []broker.SubscribeOption

	if len(c.queue) > 0 {
		opts = append(opts, broker.Queue(c.queue))
	}

	subscriber, err := (*cmd.DefaultOptions().Broker).Subscribe(c.topic, func(p broker.Publication) error {
		b, err := json.Marshal(p.Message())
		if err != nil {
			return nil
		}
		return c.write(websocket.TextMessage, b)
	}, opts...)

	defer func() {
		subscriber.Unsubscribe()
		ticker.Stop()
		c.ws.Close()
	}()

	if err != nil {
		log.Print(err.Error())
		return
	}

	for {
		select {
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		case <-c.exit:
			return
		}
	}
}

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

	r.ParseForm()
	topic := r.Form.Get("topic")
	if len(topic) == 0 {
		http.Error(w, "Topic not specified", 400)
		return
	}
	queue := r.Form.Get("queue")

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

	once.Do(func() {
		(*cmd.DefaultOptions().Broker).Init()
		(*cmd.DefaultOptions().Broker).Connect()
	})

	cType := r.Header.Get("Content-Type")
	if len(cType) == 0 {
		cType = contentType
	}

	c := &conn{
		cType: cType,
		topic: topic,
		queue: queue,
		exit:  make(chan bool),
		ws:    ws,
	}

	go c.writeLoop()
	c.readLoop()
}
<|endoftext|>


<commit_before>package interpreter

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
)

type CommandNotFound struct {
	Name string
	Err  error
}

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

type NextT int

const (
	THROUGH  NextT = 0
	CONTINUE NextT = 1
	SHUTDOWN NextT = 2
)

func (this NextT) String() string {
	switch this {
	case THROUGH:
		return "THROUGH"
	case CONTINUE:
		return "CONTINUE"
	case SHUTDOWN:
		return "SHUTDOWN"
	default:
		return "UNKNOWN"
	}
}

type Interpreter struct {
	exec.Cmd
	Stdio     [3]*os.File
	HookCount int
	Closer    []io.Closer
	Tag       interface{}
}

func (this *Interpreter) closeAtEnd() {
	if this.Closer != nil {
		for _, c := range this.Closer {
			c.Close()
		}
		this.Closer = nil
	}
}

func New() *Interpreter {
	this := Interpreter{
		Stdio: [3]*os.File{os.Stdin, os.Stdout, os.Stderr},
	}
	this.Stdin = os.Stdin
	this.Stdout = os.Stdout
	this.Stderr = os.Stderr
	this.Tag = nil
	return &this
}

func (this *Interpreter) SetStdin(f *os.File) {
	this.Stdio[0] = f
	this.Stdin = f
}
func (this *Interpreter) SetStdout(f *os.File) {
	this.Stdio[1] = f
	this.Stdout = f
}
func (this *Interpreter) SetStderr(f *os.File) {
	this.Stdio[2] = f
	this.Stderr = f
}

func (this *Interpreter) Clone() *Interpreter {
	rv := new(Interpreter)
	rv.Stdio[0] = this.Stdio[0]
	rv.Stdio[1] = this.Stdio[1]
	rv.Stdio[2] = this.Stdio[2]
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.Closer = nil
	return rv
}

type ArgsHookT func(it *Interpreter, args []string) []string

var argsHook = func(it *Interpreter, args []string) []string {
	return args
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*Interpreter) (NextT, error)

var hook = func(*Interpreter) (NextT, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Interpreter, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var errorStatusPattern = regexp.MustCompile("^exit status ([0-9]+)")
var ErrorLevel string

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func (this *Interpreter) Spawnvp() (NextT, error) {
	var whatToDo NextT = CONTINUE
	var err error = nil

	if len(this.Args) > 0 {
		whatToDo, err = hook(this)
		if whatToDo == THROUGH {
			this.Path, err = exec.LookPath(this.Args[0])
			if err == nil {
				err = this.Run()
			} else {
				err = OnCommandNotFound(this, err)
			}
			whatToDo = CONTINUE
		}
	}
	return whatToDo, err
}

type result_t struct {
	NextValue NextT
	Error     error
}

func (this *Interpreter) Interpret(text string) (NextT, error) {
	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		return CONTINUE, statementsErr
	}
	if argsHook != nil {
		for _, pipeline := range statements {
			for _, state := range pipeline {
				state.Argv = argsHook(this, state.Argv)
			}
		}
	}
	var result chan result_t = nil
	for _, pipeline := range statements {
		var pipeOut *os.File = nil
		for i := len(pipeline) - 1; i >= 0; i-- {
			state := pipeline[i]

			cmd := new(Interpreter)
			cmd.Tag = this.Tag
			cmd.HookCount = this.HookCount
			cmd.SetStdin(nvl(this.Stdio[0], os.Stdin))
			cmd.SetStdout(nvl(this.Stdio[1], os.Stdout))
			cmd.SetStderr(nvl(this.Stdio[2], os.Stderr))

			var err error = nil

			if state.Term[0] == '|' {
				cmd.SetStdout(pipeOut)
				if state.Term == "|&" {
					cmd.SetStderr(pipeOut)
				}
				cmd.Closer = append(cmd.Closer, pipeOut)
			}

			if i > 0 && pipeline[i-1].Term[0] == '|' {
				var pipeIn *os.File
				pipeIn, pipeOut, err = os.Pipe()
				if err != nil {
					return CONTINUE, err
				}
				cmd.SetStdin(pipeIn)
				cmd.Closer = append(cmd.Closer, pipeIn)
			} else {
				pipeOut = nil
			}

			for _, red := range state.Redirect {
				err = red.OpenOn(cmd)
				if err != nil {
					return CONTINUE, err
				}
			}
			cmd.Args = state.Argv
			if i == len(pipeline)-1 && state.Term != "&" {
				result = make(chan result_t)
				go func() {
					whatToDo, err := cmd.Spawnvp()
					cmd.closeAtEnd()
					result <- result_t{whatToDo, err}
				}()
			} else {
				go func() {
					cmd.Spawnvp()
					cmd.closeAtEnd()
				}()
			}
		}
	}
	if result != nil {
		resultValue := <-result
		if resultValue.Error != nil {
			m := errorStatusPattern.FindStringSubmatch(
				resultValue.Error.Error())
			if m != nil {
				ErrorLevel = m[1]
				resultValue.Error = nil
			} else {
				ErrorLevel = "-1"
			}
		} else {
			ErrorLevel = "0"
		}
		return resultValue.NextValue, resultValue.Error
	} else {
		return CONTINUE, nil
	}
}
<commit_msg>Fixed 'A ; B' was same as 'A & B'<commit_after>package interpreter

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
)

type CommandNotFound struct {
	Name string
	Err  error
}

func (this CommandNotFound) Stringer() string {
	return fmt.Sprintf("'%s' is not recognized as an internal or external command,\noperable program or batch file", this.Name)
}

func (this CommandNotFound) Error() string {
	return this.Stringer()
}

type NextT int

const (
	THROUGH  NextT = 0
	CONTINUE NextT = 1
	SHUTDOWN NextT = 2
)

func (this NextT) String() string {
	switch this {
	case THROUGH:
		return "THROUGH"
	case CONTINUE:
		return "CONTINUE"
	case SHUTDOWN:
		return "SHUTDOWN"
	default:
		return "UNKNOWN"
	}
}

type Interpreter struct {
	exec.Cmd
	Stdio     [3]*os.File
	HookCount int
	Closer    []io.Closer
	Tag       interface{}
}

func (this *Interpreter) closeAtEnd() {
	if this.Closer != nil {
		for _, c := range this.Closer {
			c.Close()
		}
		this.Closer = nil
	}
}

func New() *Interpreter {
	this := Interpreter{
		Stdio: [3]*os.File{os.Stdin, os.Stdout, os.Stderr},
	}
	this.Stdin = os.Stdin
	this.Stdout = os.Stdout
	this.Stderr = os.Stderr
	this.Tag = nil
	return &this
}

func (this *Interpreter) SetStdin(f *os.File) {
	this.Stdio[0] = f
	this.Stdin = f
}
func (this *Interpreter) SetStdout(f *os.File) {
	this.Stdio[1] = f
	this.Stdout = f
}
func (this *Interpreter) SetStderr(f *os.File) {
	this.Stdio[2] = f
	this.Stderr = f
}

func (this *Interpreter) Clone() *Interpreter {
	rv := new(Interpreter)
	rv.Stdio[0] = this.Stdio[0]
	rv.Stdio[1] = this.Stdio[1]
	rv.Stdio[2] = this.Stdio[2]
	rv.Stdin = this.Stdin
	rv.Stdout = this.Stdout
	rv.Stderr = this.Stderr
	rv.HookCount = this.HookCount
	rv.Tag = this.Tag
	rv.Closer = nil
	return rv
}

type ArgsHookT func(it *Interpreter, args []string) []string

var argsHook = func(it *Interpreter, args []string) []string {
	return args
}

func SetArgsHook(argsHook_ ArgsHookT) (rv ArgsHookT) {
	rv, argsHook = argsHook, argsHook_
	return
}

type HookT func(*Interpreter) (NextT, error)

var hook = func(*Interpreter) (NextT, error) {
	return THROUGH, nil
}

func SetHook(hook_ HookT) (rv HookT) {
	rv, hook = hook, hook_
	return
}

var OnCommandNotFound = func(this *Interpreter, err error) error {
	err = &CommandNotFound{this.Args[0], err}
	return err
}

var errorStatusPattern = regexp.MustCompile("^exit status ([0-9]+)")
var ErrorLevel string

func nvl(a *os.File, b *os.File) *os.File {
	if a != nil {
		return a
	} else {
		return b
	}
}

func (this *Interpreter) Spawnvp() (NextT, error) {
	var whatToDo NextT = CONTINUE
	var err error = nil

	if len(this.Args) > 0 {
		whatToDo, err = hook(this)
		if whatToDo == THROUGH {
			this.Path, err = exec.LookPath(this.Args[0])
			if err == nil {
				err = this.Run()
			} else {
				err = OnCommandNotFound(this, err)
			}
			whatToDo = CONTINUE
		}
	}
	this.Stdio[1].Sync()
	this.Stdio[2].Sync()
	return whatToDo, err
}

type result_t struct {
	NextValue NextT
	Error     error
}

func (this *Interpreter) Interpret(text string) (next NextT, err error) {
	next = CONTINUE
	err = nil

	statements, statementsErr := Parse(text)
	if statementsErr != nil {
		return CONTINUE, statementsErr
	}
	if argsHook != nil {
		for _, pipeline := range statements {
			for _, state := range pipeline {
				state.Argv = argsHook(this, state.Argv)
			}
		}
	}
	for _, pipeline := range statements {
		var result chan result_t = nil
		var pipeOut *os.File = nil
		for i := len(pipeline) - 1; i >= 0; i-- {
			state := pipeline[i]

			cmd := new(Interpreter)
			cmd.Tag = this.Tag
			cmd.HookCount = this.HookCount
			cmd.SetStdin(nvl(this.Stdio[0], os.Stdin))
			cmd.SetStdout(nvl(this.Stdio[1], os.Stdout))
			cmd.SetStderr(nvl(this.Stdio[2], os.Stderr))

			var err error = nil

			if state.Term[0] == '|' {
				cmd.SetStdout(pipeOut)
				if state.Term == "|&" {
					cmd.SetStderr(pipeOut)
				}
				cmd.Closer = append(cmd.Closer, pipeOut)
			}

			if i > 0 && pipeline[i-1].Term[0] == '|' {
				var pipeIn *os.File
				pipeIn, pipeOut, err = os.Pipe()
				if err != nil {
					return CONTINUE, err
				}
				cmd.SetStdin(pipeIn)
				cmd.Closer = append(cmd.Closer, pipeIn)
			} else {
				pipeOut = nil
			}

			for _, red := range state.Redirect {
				err = red.OpenOn(cmd)
				if err != nil {
					return CONTINUE, err
				}
			}
			cmd.Args = state.Argv
			if i == len(pipeline)-1 && state.Term != "&" {
				result = make(chan result_t)
				go func() {
					whatToDo, err := cmd.Spawnvp()
					cmd.closeAtEnd()
					result <- result_t{whatToDo, err}
				}()
			} else {
				go func() {
					cmd.Spawnvp()
					cmd.closeAtEnd()
				}()
			}
		}
		if result != nil {
			resultValue := <-result
			if resultValue.Error != nil {
				m := errorStatusPattern.FindStringSubmatch(
					resultValue.Error.Error())
				if m != nil {
					ErrorLevel = m[1]
					resultValue.Error = nil
				} else {
					ErrorLevel = "-1"
				}
			} else {
				ErrorLevel = "0"
			}
			next = resultValue.NextValue
			err = resultValue.Error
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2016 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

// Package prometheus implements a chihaya Server for serving metrics to
// Prometheus.
package prometheus

import (
	"errors"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/tylerb/graceful"
	"gopkg.in/yaml.v2"

	"github.com/chihaya/chihaya"
	"github.com/chihaya/chihaya/server"
	"github.com/chihaya/chihaya/tracker"
)

func init() {
	server.Register("prometheus", constructor)
}

func constructor(srvcfg *chihaya.ServerConfig, tkr *tracker.Tracker) (server.Server, error) {
	cfg, err := NewServerConfig(srvcfg)
	if err != nil {
		return nil, errors.New("prometheus: invalid config: " + err.Error())
	}

	return &Server{
		cfg: cfg,
	}, nil
}

// ServerConfig represents the configuration options for a
// PrometheusServer.
type ServerConfig struct {
	Addr            string        `yaml:"addr"`
	ShutdownTimeout time.Duration `yaml:"shutdown_timeout"`
	ReadTimeout     time.Duration `yaml:"read_timeout"`
	WriteTimeout    time.Duration `yaml:"write_timeout"`
}

// NewServerConfig marshals a chihaya.ServerConfig and unmarshals it
// into a more specific prometheus ServerConfig.
func NewServerConfig(srvcfg *chihaya.ServerConfig) (*ServerConfig, error) {
	bytes, err := yaml.Marshal(srvcfg.Config)
	if err != nil {
		return nil, err
	}

	var cfg ServerConfig
	err = yaml.Unmarshal(bytes, &cfg)
	if err != nil {
		return nil, err
	}

	return &cfg, nil
}

// Server implements a chihaya Server for serving metrics to Prometheus.
type Server struct {
	cfg     *ServerConfig
	grace   *graceful.Server
	stopped bool
}

var _ server.Server = &Server{}

func (s *Server) Start() {
	s.grace = &graceful.Server{
		Server: &http.Server{
			Addr:         s.cfg.Addr,
			Handler:      prometheus.Handler(),
			ReadTimeout:  s.cfg.ReadTimeout,
			WriteTimeout: s.cfg.WriteTimeout,
		},
		Timeout:          s.cfg.ShutdownTimeout,
		NoSignalHandling: true,
	}
}

func (s *Server) Stop() {
	s.grace.Stop(s.cfg.ShutdownTimeout)
	stopChan := s.grace.StopChan()

	// Block until the graceful server shuts down and closes this channel.
	for range stopChan {
	}
}
<commit_msg>server/prom: get rid of unneeded graceful call<commit_after>// Copyright 2016 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.

// Package prometheus implements a chihaya Server for serving metrics to
// Prometheus.
package prometheus

import (
	"errors"
	"net/http"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/tylerb/graceful"
	"gopkg.in/yaml.v2"

	"github.com/chihaya/chihaya"
	"github.com/chihaya/chihaya/server"
	"github.com/chihaya/chihaya/tracker"
)

func init() {
	server.Register("prometheus", constructor)
}

func constructor(srvcfg *chihaya.ServerConfig, tkr *tracker.Tracker) (server.Server, error) {
	cfg, err := NewServerConfig(srvcfg)
	if err != nil {
		return nil, errors.New("prometheus: invalid config: " + err.Error())
	}

	return &Server{
		cfg: cfg,
	}, nil
}

// ServerConfig represents the configuration options for a
// PrometheusServer.
type ServerConfig struct {
	Addr            string        `yaml:"addr"`
	ShutdownTimeout time.Duration `yaml:"shutdown_timeout"`
	ReadTimeout     time.Duration `yaml:"read_timeout"`
	WriteTimeout    time.Duration `yaml:"write_timeout"`
}

// NewServerConfig marshals a chihaya.ServerConfig and unmarshals it
// into a more specific prometheus ServerConfig.
func NewServerConfig(srvcfg *chihaya.ServerConfig) (*ServerConfig, error) {
	bytes, err := yaml.Marshal(srvcfg.Config)
	if err != nil {
		return nil, err
	}

	var cfg ServerConfig
	err = yaml.Unmarshal(bytes, &cfg)
	if err != nil {
		return nil, err
	}

	return &cfg, nil
}

// Server implements a chihaya Server for serving metrics to Prometheus.
type Server struct {
	cfg   *ServerConfig
	grace *graceful.Server
}

var _ server.Server = &Server{}

func (s *Server) Start() {
	s.grace = &graceful.Server{
		Server: &http.Server{
			Addr:         s.cfg.Addr,
			Handler:      prometheus.Handler(),
			ReadTimeout:  s.cfg.ReadTimeout,
			WriteTimeout: s.cfg.WriteTimeout,
		},
		Timeout:          s.cfg.ShutdownTimeout,
		NoSignalHandling: true,
	}
}

func (s *Server) Stop() {
	s.grace.Stop(s.cfg.ShutdownTimeout)
}
<|endoftext|>


<commit_before>package ask

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/byuoitav/common/db"
	"github.com/byuoitav/common/log"
	"github.com/byuoitav/common/nerr"
	"github.com/byuoitav/common/structs"
	"github.com/byuoitav/common/v2/events"
	"github.com/byuoitav/device-monitoring/localsystem"
)

const (
	// TODO change this command name to match whatever command we need
	hardwareInfoCommandID = "HardwareInfo"
)

// DeviceHardwareJob gets hardware information from devices in the room and pushes it up
type DeviceHardwareJob struct{}

// Run runs the job
func (j *DeviceHardwareJob) Run(ctx interface{}, eventWrite chan events.Event) interface{} {
	log.L.Infof("Getting hardware info for devices in room")

	// get list of devices from database
	roomID, err := localsystem.RoomID()
	if err != nil {
		return err.Addf("failed to get hardware info about devices")
	}

	devices, gerr := db.GetDB().GetDevicesByRoom(roomID)
	if gerr != nil {
		return nerr.Translate(gerr).Addf("failed to get hardware info about devices in %s", roomID)
	}

	wg := sync.WaitGroup{}
	hardwareInfo := make(map[string]structs.HardwareInfo)

	for i := range devices {
		// skip the pi's
		if devices[i].Type.ID == "Pi3" {
			continue
		}
		wg.Add(1)

		go func(idx int) {
			defer wg.Done()

			info := getHardwareInfo(&devices[idx])
			if info != nil {
				sendHardwareInfo(devices[idx].ID, info, eventWrite)
				hardwareInfo[devices[idx].ID] = *info
			}
		}(i)
	}

	wg.Wait()

	return hardwareInfo
}

func getHardwareInfo(device *structs.Device) *structs.HardwareInfo {
	if device == nil {
		log.L.Errorf("device to get hardware info from cannot be null")
		return nil
	}

	address := device.GetCommandByID(hardwareInfoCommandID).BuildCommandAddress()
	if len(address) == 0 {
		log.L.Infof("%s doesn't have a %s command, so I can't get any hardware info about it", device.ID, hardwareInfoCommandID)
		return nil
	}

	log.L.Infof("Getting hardware info for %s", device.ID)

	address = strings.Replace(address, ":address", device.Address, 1)

	client := &http.Client{
		Timeout: 20 * time.Second,
	}

	log.L.Debugf("Sending GET request to: %s", address)

	// get hardware info about device
	resp, err := client.Get(address)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}
	defer resp.Body.Close()

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}

	ret := &structs.HardwareInfo{}

	err = json.Unmarshal(bytes, ret)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}

	return ret
}

func sendHardwareInfo(deviceID string, info *structs.HardwareInfo, eventWrite chan events.Event) {
	// push up events about device
	targetDevice := events.GenerateBasicDeviceInfo(deviceID)
	event := events.Event{
		GeneratingSystem: localsystem.MustSystemID(),
		Timestamp:        time.Now(),
		EventTags: []string{
			events.HardwareInfo,
			events.DetailState,
		},
		TargetDevice: targetDevice,
		AffectedRoom: events.GenerateBasicRoomInfo(targetDevice.RoomID),
		Key:          "hardware-info",
		Data:         info,
	}
	eventWrite <- event // dump up all the hardware info

	// reset the data/key
	event.Data = nil
	event.Key = ""

	// push up hostname
	if len(info.Hostname) > 0 {
		event.Key = "hostname"
		event.Value = info.Hostname
		eventWrite <- event
	}

	if len(info.ModelName) > 0 {
		event.Key = "model-name"
		event.Value = info.ModelName
		eventWrite <- event
	}

	if len(info.SerialNumber) > 0 {
		event.Key = "serial-number"
		event.Value = info.SerialNumber
		eventWrite <- event
	}

	if len(info.FirmwareVersion) > 0 {
		event.Key = "firmware-version"
		// TODO what kind of interface{}...?
		event.Value = fmt.Sprintf("%v", info.FirmwareVersion)
		eventWrite <- event
	}

	if len(info.FilterStatus) > 0 {
		event.Key = "filter-status"
		event.Value = info.FilterStatus
		eventWrite <- event
	}

	if len(info.WarningStatus) > 0 {
		event.Key = "warning-status"

		str := ""

		for i := range info.WarningStatus {
			str += info.WarningStatus[i]
		}

		event.Value = str
		eventWrite <- event
	}

	if len(info.ErrorStatus) > 0 {
		event.Key = "error-status"
		str := ""

		for i := range info.ErrorStatus {
			str += info.WarningStatus[i]
		}

		event.Value = str
		eventWrite <- event
	}

	if len(info.PowerStatus) > 0 {
		event.Key = "power-status"
		event.Value = info.PowerStatus
		eventWrite <- event
	}

	if info.TimerInfo != nil {
		event.Key = "timer-info"

		// TODO what kind of interface{}?
		event.Value = fmt.Sprintf("%v", info.TimerInfo)
		eventWrite <- event
	}

	if len(info.NetworkInfo.IPAddress) > 0 {
		event.Key = "ip-address"
		event.Value = info.NetworkInfo.IPAddress
		eventWrite <- event
	}

	if len(info.NetworkInfo.MACAddress) > 0 {
		event.Key = "mac-address"
		event.Value = info.NetworkInfo.MACAddress
		eventWrite <- event
	}

	if len(info.NetworkInfo.Gateway) > 0 {
		event.Key = "default-gateway"
		event.Value = info.NetworkInfo.Gateway
		eventWrite <- event
	}

	if len(info.NetworkInfo.DNS) > 0 {
		event.Key = "dns-addresses"
		builder := strings.Builder{}

		for i := range info.NetworkInfo.DNS {
			builder.WriteString(info.NetworkInfo.DNS[i])

			if i != len(info.NetworkInfo.DNS)-1 {
				builder.WriteString(", ")
			}
		}

		event.Value = builder.String()
		eventWrite <- event
	}
}
<commit_msg>only send detail state for some events<commit_after>package ask

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/byuoitav/common/db"
	"github.com/byuoitav/common/log"
	"github.com/byuoitav/common/nerr"
	"github.com/byuoitav/common/structs"
	"github.com/byuoitav/common/v2/events"
	"github.com/byuoitav/device-monitoring/localsystem"
)

const (
	// TODO change this command name to match whatever command we need
	hardwareInfoCommandID = "HardwareInfo"
)

// DeviceHardwareJob gets hardware information from devices in the room and pushes it up
type DeviceHardwareJob struct{}

// Run runs the job
func (j *DeviceHardwareJob) Run(ctx interface{}, eventWrite chan events.Event) interface{} {
	log.L.Infof("Getting hardware info for devices in room")

	// get list of devices from database
	roomID, err := localsystem.RoomID()
	if err != nil {
		return err.Addf("failed to get hardware info about devices")
	}

	devices, gerr := db.GetDB().GetDevicesByRoom(roomID)
	if gerr != nil {
		return nerr.Translate(gerr).Addf("failed to get hardware info about devices in %s", roomID)
	}

	wg := sync.WaitGroup{}
	hardwareInfo := make(map[string]structs.HardwareInfo)

	for i := range devices {
		// skip the pi's
		if devices[i].Type.ID == "Pi3" {
			continue
		}
		wg.Add(1)

		go func(idx int) {
			defer wg.Done()

			info := getHardwareInfo(&devices[idx])
			if info != nil {
				sendHardwareInfo(devices[idx].ID, info, eventWrite)
				hardwareInfo[devices[idx].ID] = *info
			}
		}(i)
	}

	wg.Wait()

	return hardwareInfo
}

func getHardwareInfo(device *structs.Device) *structs.HardwareInfo {
	if device == nil {
		log.L.Errorf("device to get hardware info from cannot be null")
		return nil
	}

	address := device.GetCommandByID(hardwareInfoCommandID).BuildCommandAddress()
	if len(address) == 0 {
		log.L.Infof("%s doesn't have a %s command, so I can't get any hardware info about it", device.ID, hardwareInfoCommandID)
		return nil
	}

	log.L.Infof("Getting hardware info for %s", device.ID)

	address = strings.Replace(address, ":address", device.Address, 1)

	client := &http.Client{
		Timeout: 20 * time.Second,
	}

	log.L.Debugf("Sending GET request to: %s", address)

	// get hardware info about device
	resp, err := client.Get(address)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}
	defer resp.Body.Close()

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}

	ret := &structs.HardwareInfo{}

	err = json.Unmarshal(bytes, ret)
	if err != nil {
		log.L.Warnf("failed to get hardware info for %s: %s", device.ID, err)
		return nil
	}

	return ret
}

func sendHardwareInfo(deviceID string, info *structs.HardwareInfo, eventWrite chan events.Event) {
	// push up events about device
	targetDevice := events.GenerateBasicDeviceInfo(deviceID)
	event := events.Event{
		GeneratingSystem: localsystem.MustSystemID(),
		Timestamp:        time.Now(),
		EventTags: []string{
			events.HardwareInfo,
		},
		TargetDevice: targetDevice,
		AffectedRoom: events.GenerateBasicRoomInfo(targetDevice.RoomID),
		Key:          "hardware-info",
		Data:         info,
	}
	eventWrite <- event // dump up all the hardware info
	event.Data = nil

	// push up hostname
	if len(info.Hostname) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "hostname"
		tmp.Value = info.Hostname
		eventWrite <- tmp
	}

	if len(info.ModelName) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "model-name"
		tmp.Value = info.ModelName
		eventWrite <- tmp
	}

	if len(info.SerialNumber) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "serial-number"
		tmp.Value = info.SerialNumber
		eventWrite <- tmp
	}

	if len(info.FirmwareVersion) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "firmware-version"
		// TODO what kind of interface{}...?
		tmp.Value = fmt.Sprintf("%v", info.FirmwareVersion)
		eventWrite <- tmp
	}

	if len(info.FilterStatus) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "filter-status"
		tmp.Value = info.FilterStatus
		eventWrite <- tmp
	}

	if len(info.WarningStatus) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "warning-status"

		str := ""

		for i := range info.WarningStatus {
			str += info.WarningStatus[i]
		}

		tmp.Value = str
		eventWrite <- tmp
	}

	if len(info.ErrorStatus) > 0 {
		tmp := event
		tmp.AddToTags(events.DetailState)
		tmp.Key = "error-status"
		str := ""

		for i := range info.ErrorStatus {
			str += info.WarningStatus[i]
		}

		tmp.Value = str
		eventWrite <- tmp
	}

	if len(info.PowerStatus) > 0 {
		event.Key = "power-status"
		event.Value = info.PowerStatus
		eventWrite <- event
	}

	if info.TimerInfo != nil {
		event.Key = "timer-info"

		// TODO what kind of interface{}?
		event.Value = fmt.Sprintf("%v", info.TimerInfo)
		eventWrite <- event
	}

	if len(info.NetworkInfo.IPAddress) > 0 {
		event.Key = "ip-address"
		event.Value = info.NetworkInfo.IPAddress
		eventWrite <- event
	}

	if len(info.NetworkInfo.MACAddress) > 0 {
		event.Key = "mac-address"
		event.Value = info.NetworkInfo.MACAddress
		eventWrite <- event
	}

	if len(info.NetworkInfo.Gateway) > 0 {
		event.Key = "default-gateway"
		event.Value = info.NetworkInfo.Gateway
		eventWrite <- event
	}

	if len(info.NetworkInfo.DNS) > 0 {
		event.Key = "dns-addresses"
		builder := strings.Builder{}

		for i := range info.NetworkInfo.DNS {
			builder.WriteString(info.NetworkInfo.DNS[i])

			if i != len(info.NetworkInfo.DNS)-1 {
				builder.WriteString(", ")
			}
		}

		event.Value = builder.String()
		eventWrite <- event
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package gateway

import (
	"fmt"
	"github.com/thethingsnetwork/core/lorawan/semtech"
	"github.com/thethingsnetwork/core/utils/pointer"
	"io"
	"time"
)

type Forwarder struct {
	Id       [8]byte              // Gateway's Identifier
	alti     int                  // GPS altitude in RX meters
	upnb     uint                 // Number of upstream datagrams sent
	ackn     uint                 // Number of upstream datagrams that were acknowledged
	dwnb     uint                 // Number of downlink datagrams received
	lati     float64              // GPS latitude, North is +
	long     float64              // GPS longitude, East is +
	rxfw     uint                 // Number of radio packets forwarded
	rxnb     uint                 // Number of radio packets received
	adapters []io.ReadWriteCloser // List of downlink adapters
	packets  []semtech.Packet     // Downlink packets received
	commands chan command         // Concurrent access on gateway stats
	Errors   chan error           // Done channel
}

type commandName string
type command struct {
	name commandName
	data interface{}
}

const (
	cmd_ACK     commandName = "Acknowledged"
	cmd_EMIT    commandName = "Emitted"
	cmd_RECVUP  commandName = "Radio Packet Received"
	cmd_RECVDWN commandName = "Dowlink Datagram Received"
	cmd_FWD     commandName = "Forwarded"
	cmd_FLUSH   commandName = "Flush"
	cmd_STATS   commandName = "Stats"
)

// NewForwarder create a forwarder instance bound to a set of routers.
func NewForwarder(id [8]byte, adapters ...io.ReadWriteCloser) (*Forwarder, error) {
	if len(adapters) == 0 {
		return nil, fmt.Errorf("At least one adapter must be supplied")
	}

	fwd := &Forwarder{
		Id:       id,
		alti:     120,
		lati:     53.3702,
		long:     4.8952,
		adapters: adapters,
		commands: make(chan command),
		Errors:   make(chan error, len(adapters)),
	}

	go fwd.handleCommands()

	// Star listening to each adapter Read() method
	for _, adapter := range fwd.adapters {
		go fwd.listenAdapter(adapter)
	}

	return fwd, nil
}

// listenAdapter listen to incoming datagrams from an adapter. Non-valid packets are ignored.
func (fwd Forwarder) listenAdapter(adapter io.ReadWriteCloser) {
	acks := make(map[[3]byte]uint) // adapterIndex | packet.Identifier | packet.Token
	for {
		buf := make([]byte, 1024)
		fmt.Printf("Forwarder listens to downlink datagrams\n")
		n, err := adapter.Read(buf)
		if err != nil {
			fmt.Println(err)
			fwd.Errors <- err
			return // Error on reading, we assume the connection is closed / lost
		}
		fmt.Printf("Forwarder unmarshals datagram %x\n", buf[:n])
		packet, err := semtech.Unmarshal(buf[:n])
		if err != nil {
			fmt.Println(err)
			continue
		}

		token := [3]byte{packet.Identifier, packet.Token[0], packet.Token[1]}
		switch packet.Identifier {
		case semtech.PUSH_ACK, semtech.PULL_ACK:
			if acks[token] > 0 {
				acks[token] -= 1
				fwd.commands <- command{cmd_ACK, nil}
			}
		case semtech.PULL_RESP:
			fwd.commands <- command{cmd_RECVDWN, packet}
		default:
			fmt.Printf("Forwarder ignores contingent packet %+v\n", packet)
		}

	}
}

// handleCommands acts as a mediator between all goroutines that attempt to modify the forwarder
// attributes. All sensitive operations are done by commands send though an appropriate channel.
// This method consume commands from the channel until it's closed.
func (fwd *Forwarder) handleCommands() {
	for cmd := range fwd.commands {
		fmt.Printf("Fowarder executes command: %v\n", cmd.name)
		switch cmd.name {
		case cmd_ACK:
			fwd.ackn += 1
		case cmd_FWD:
			fwd.rxfw += 1
		case cmd_EMIT:
			fwd.upnb += 1
		case cmd_RECVUP:
			fwd.rxnb += 1
		case cmd_RECVDWN:
			fwd.dwnb += 1
			fwd.packets = append(fwd.packets, cmd.data.(semtech.Packet))
		case cmd_FLUSH:
			cmd.data.(chan []semtech.Packet) <- fwd.packets
			fwd.packets = make([]semtech.Packet, 0)
		case cmd_STATS:
			var ackr float64
			if fwd.upnb != 0 {
				ackr = float64(fwd.ackn) / float64(fwd.upnb)
			}

			cmd.data.(chan semtech.Stat) <- semtech.Stat{
				Ackr: &ackr,
				Alti: pointer.Int(fwd.alti),
				Dwnb: pointer.Uint(fwd.dwnb),
				Lati: pointer.Float64(fwd.lati),
				Long: pointer.Float64(fwd.long),
				Rxfw: pointer.Uint(fwd.rxfw),
				Rxnb: pointer.Uint(fwd.rxnb),
				Rxok: pointer.Uint(fwd.rxnb),
				Time: pointer.Time(time.Now()),
				Txnb: pointer.Uint(0),
			}
		}
	}
}

// Forward dispatch a packet to all connected routers.
func (fwd Forwarder) Forward(packet semtech.Packet) error {
	fwd.commands <- command{cmd_RECVUP, nil}
	if packet.Identifier != semtech.PUSH_DATA {
		return fmt.Errorf("Unable to forward with identifier %x", packet.Identifier)
	}

	raw, err := semtech.Marshal(packet)
	if err != nil {
		return err
	}

	for _, adapter := range fwd.adapters {
		n, err := adapter.Write(raw)
		if err != nil {
			return err
		}
		if n < len(raw) {
			return fmt.Errorf("Packet was too long")
		}
		fwd.commands <- command{cmd_EMIT, nil}
	}

	fwd.commands <- command{cmd_FWD, nil}
	return nil
}

// Flush spits out all downlink packet received by the forwarder since the last flush.
func (fwd Forwarder) Flush() []semtech.Packet {
	chpkt := make(chan []semtech.Packet)
	fwd.commands <- command{cmd_FLUSH, chpkt}
	return <-chpkt
}

// Stats computes and return the forwarder statistics since it was created
func (fwd Forwarder) Stats() semtech.Stat {
	chstats := make(chan semtech.Stat)
	fwd.commands <- command{cmd_STATS, chstats}
	return <-chstats
}

// Stop terminate the forwarder activity. Closing all routers connections
func (fwd Forwarder) Stop() error {
	var errors []error

	// Close the uplink adapters
	for _, adapter := range fwd.adapters {
		err := adapter.Close()
		if err != nil {
			errors = append(errors, err)
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("Unable to stop the forwarder: %+v", errors)
	}

	return nil
}
<commit_msg>[simulators.gateway] Add debug variable. To be removed in the future<commit_after>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package gateway

import (
	"fmt"
	"github.com/thethingsnetwork/core/lorawan/semtech"
	"github.com/thethingsnetwork/core/utils/pointer"
	"io"
	"time"
)

type Forwarder struct {
	Id       [8]byte // Gateway's Identifier
	debug    bool
	alti     int                  // GPS altitude in RX meters
	upnb     uint                 // Number of upstream datagrams sent
	ackn     uint                 // Number of upstream datagrams that were acknowledged
	dwnb     uint                 // Number of downlink datagrams received
	lati     float64              // GPS latitude, North is +
	long     float64              // GPS longitude, East is +
	rxfw     uint                 // Number of radio packets forwarded
	rxnb     uint                 // Number of radio packets received
	adapters []io.ReadWriteCloser // List of downlink adapters
	packets  []semtech.Packet     // Downlink packets received
	commands chan command         // Concurrent access on gateway stats
	Errors   chan error           // Done channel
}

type commandName string
type command struct {
	name commandName
	data interface{}
}

const (
	cmd_ACK     commandName = "Acknowledged"
	cmd_EMIT    commandName = "Emitted"
	cmd_RECVUP  commandName = "Radio Packet Received"
	cmd_RECVDWN commandName = "Dowlink Datagram Received"
	cmd_FWD     commandName = "Forwarded"
	cmd_FLUSH   commandName = "Flush"
	cmd_STATS   commandName = "Stats"
)

// NewForwarder create a forwarder instance bound to a set of routers.
func NewForwarder(id [8]byte, adapters ...io.ReadWriteCloser) (*Forwarder, error) {
	if len(adapters) == 0 {
		return nil, fmt.Errorf("At least one adapter must be supplied")
	}

	fwd := &Forwarder{
		Id:       id,
		debug:    false,
		alti:     120,
		lati:     53.3702,
		long:     4.8952,
		adapters: adapters,
		packets:  make([]semtech.Packet, 0),
		commands: make(chan command),
		Errors:   make(chan error, len(adapters)),
	}

	go fwd.handleCommands()

	// Star listening to each adapter Read() method
	for _, adapter := range fwd.adapters {
		go fwd.listenAdapter(adapter)
	}

	return fwd, nil
}

// listenAdapter listen to incoming datagrams from an adapter. Non-valid packets are ignored.
func (fwd Forwarder) listenAdapter(adapter io.ReadWriteCloser) {
	acks := make(map[[3]byte]uint) // adapterIndex | packet.Identifier | packet.Token
	for {
		buf := make([]byte, 1024)
		if fwd.debug {
			fmt.Printf("Forwarder listens to downlink datagrams\n")
		}
		n, err := adapter.Read(buf)
		if err != nil {
			if fwd.debug {
				fmt.Println(err)
			}
			fwd.Errors <- err
			return // Error on reading, we assume the connection is closed / lost
		}
		if fwd.debug {
			fmt.Printf("Forwarder unmarshals datagram %x\n", buf[:n])
		}
		packet, err := semtech.Unmarshal(buf[:n])
		if err != nil {
			if fwd.debug {
				fmt.Println(err)
			}
			continue
		}

		token := [3]byte{packet.Identifier, packet.Token[0], packet.Token[1]}
		switch packet.Identifier {
		case semtech.PUSH_ACK, semtech.PULL_ACK:
			if acks[token] > 0 {
				acks[token] -= 1
				fwd.commands <- command{cmd_ACK, nil}
			}
		case semtech.PULL_RESP:
			fwd.commands <- command{cmd_RECVDWN, packet}
		default:
			if fwd.debug {
				fmt.Printf("Forwarder ignores contingent packet %+v\n", packet)
			}
		}

	}
}

// handleCommands acts as a mediator between all goroutines that attempt to modify the forwarder
// attributes. All sensitive operations are done by commands send though an appropriate channel.
// This method consume commands from the channel until it's closed.
func (fwd *Forwarder) handleCommands() {
	for cmd := range fwd.commands {
		if fwd.debug {
			fmt.Printf("Fowarder executes command: %v\n", cmd.name)
		}

		switch cmd.name {
		case cmd_ACK:
			fwd.ackn += 1
		case cmd_FWD:
			fwd.rxfw += 1
		case cmd_EMIT:
			fwd.upnb += 1
		case cmd_RECVUP:
			fwd.rxnb += 1
		case cmd_RECVDWN:
			fwd.dwnb += 1
			fwd.packets = append(fwd.packets, *cmd.data.(*semtech.Packet))
		case cmd_FLUSH:
			cmd.data.(chan []semtech.Packet) <- fwd.packets
			fwd.packets = make([]semtech.Packet, 0)
		case cmd_STATS:
			var ackr float64
			if fwd.upnb != 0 {
				ackr = float64(fwd.ackn) / float64(fwd.upnb)
			}

			cmd.data.(chan semtech.Stat) <- semtech.Stat{
				Ackr: &ackr,
				Alti: pointer.Int(fwd.alti),
				Dwnb: pointer.Uint(fwd.dwnb),
				Lati: pointer.Float64(fwd.lati),
				Long: pointer.Float64(fwd.long),
				Rxfw: pointer.Uint(fwd.rxfw),
				Rxnb: pointer.Uint(fwd.rxnb),
				Rxok: pointer.Uint(fwd.rxnb),
				Time: pointer.Time(time.Now()),
				Txnb: pointer.Uint(0),
			}
		}
	}
}

// Forward dispatch a packet to all connected routers.
func (fwd Forwarder) Forward(packet semtech.Packet) error {
	fwd.commands <- command{cmd_RECVUP, nil}
	if packet.Identifier != semtech.PUSH_DATA {
		return fmt.Errorf("Unable to forward with identifier %x", packet.Identifier)
	}

	raw, err := semtech.Marshal(packet)
	if err != nil {
		return err
	}

	for _, adapter := range fwd.adapters {
		n, err := adapter.Write(raw)
		if err != nil {
			return err
		}
		if n < len(raw) {
			return fmt.Errorf("Packet was too long")
		}
		fwd.commands <- command{cmd_EMIT, nil}
	}

	fwd.commands <- command{cmd_FWD, nil}
	return nil
}

// Flush spits out all downlink packet received by the forwarder since the last flush.
func (fwd Forwarder) Flush() []semtech.Packet {
	chpkt := make(chan []semtech.Packet)
	fwd.commands <- command{cmd_FLUSH, chpkt}
	return <-chpkt
}

// Stats computes and return the forwarder statistics since it was created
func (fwd Forwarder) Stats() semtech.Stat {
	chstats := make(chan semtech.Stat)
	fwd.commands <- command{cmd_STATS, chstats}
	return <-chstats
}

// Stop terminate the forwarder activity. Closing all routers connections
func (fwd Forwarder) Stop() error {
	var errors []error

	// Close the uplink adapters
	for _, adapter := range fwd.adapters {
		err := adapter.Close()
		if err != nil {
			errors = append(errors, err)
		}
	}

	if len(errors) > 0 {
		return fmt.Errorf("Unable to stop the forwarder: %+v", errors)
	}

	return nil
}
<|endoftext|>


<commit_before>// When using FileStore, we will have yamls files to store the data.

// FIXME:
// Since I am not planning to use this in production (I prefer etcd as store)
// I would NOT be using any optimizations to cache the process file
// contents (ie, result of yaml parser) Please give me a patch (one way to clear
// the cache is by sending some signals to reread the file and update the cache.
// Also we should make sure we reread only the specific files in question).

package rangestore

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

var _config = "cluster.yaml"

type FileStore struct {
	StorePath string
	MaxDepth  int
}

// check whether the StorePath Exists, etc
func ConnectFileStore(dir string, depth int) (f *FileStore, err error) {
	// removing trailing path seperator
	if os.IsPathSeparator(dir[len(dir)-1]) {
		dir = dir[:len(dir)-1]
	}
	var fi os.FileInfo
	// check whether the dir exists
	fi, err = os.Stat(dir)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Path [%s] is not a FileStore directory (ERROR: %s)", dir, err))
	}
	// check whether it is a dir
	if !fi.IsDir() {
		return nil, errors.New(fmt.Sprintf("Path [%s] is not a directory", dir))
	}
	f = &FileStore{StorePath: dir, MaxDepth: depth}
	return f, nil
}

////////////////////
// LOOKUP CLUSTER //
////////////////////

// LOGIC
// -----
// * for the first element in cluster create results array
//   * check whether the cluster is a leaf node
//   * if yes, call KeyLookup, with key == NODES
//   * if not, call listClusters
// * if more elements are there, repeat the above
//   but do an ArraytoSet with the results array
func (f *FileStore) ClusterLookup(cluster *[]string) (*[]string, error) {
	// store the resuls
	var results = make([]string, 0)
	// for each cluster, do a lookup
	// (this will only happen only for nested lookups eg, %%..)
	for _, elem := range *cluster {
		var err error
		isLeaf, err := f.checkIsLeafNode(elem)
		if err != nil {
			return &[]string{}, err
		}
		// if it is a leaf node, we need do a KeyLookup (NODES)
		if isLeaf {
			// by default, lookup for NODES
			result, err := f.KeyLookup(&[]string{elem}, "NODES")
			if err != nil {
				return &[]string{}, err
			}
			results = append(results, *result...)
		} else { // we need to return the children
			result, err := f.listClusters(elem)
			if err != nil {
				return &[]string{}, err
			}
			results = append(results, result...)
		}

	}

	return &results, nil
}

func (f *FileStore) KeyLookup(cluster *[]string, key string) (*[]string, error) {
	// store the resuls
	var results = make([]string, 0)
	// this will most likely be single element arrays
	// can't think of a reason otherwise
	for _, elem := range *cluster {
		// 1. read the config
		// 2. do a key lookup
		// 3. append the result
		content, err := f.readClusterConfig(elem)
		if err != nil {
			return &[]string{}, errors.New(fmt.Sprintf("KeyLookup for [%s] Failed (Error: %s)", elem, err))
		}
		result, err := yamlKeyLookup(content, key)
		if err != nil {
			return &[]string{}, errors.New(fmt.Sprintf("KeyLookup for [%s] Failed (Error: %s)", elem, err))
		}
		results = append(results, *result...)
	}

	return &results, nil
}

////////////////////
// LOOKUP REVERSE //
////////////////////

func (f *FileStore) KeyReverseLookup(key string) (*[]string, error) {
	return &[]string{}, errors.New("KeyReverseLookup Failed, returning empty")
}

func (f *FileStore) KeyReverseLookupAttr(key string, attr string) (*[]string, error) {
	return &[]string{}, errors.New("KeyReverseLookupAttr Failed, returning empty")
}

func (f *FileStore) KeyReverseLookupHint(key string, attr string, hint string) (*[]string, error) {
	return &[]string{}, errors.New("KeyReverseLookupHint Failed, returning empty")
}

////////////////////////
// Internal Functions //
////////////////////////

// given a cluster name, it will convert to cluster
// in the file system
func (f *FileStore) clusterToPath(cluster string) string {
	return fmt.Sprintf("%s/%s", f.StorePath, strings.Replace(cluster, "-", "/", -1))
}

// reads the child clusters of this cluster.
// returns only those nodes for which this cluster is parent
func (f *FileStore) listClusters(cluster string) ([]string, error) {
	var dir = f.clusterToPath(cluster)
	var children = make([]string, 0)
	files, err := ioutil.ReadDir(dir)
	// if there is an error, return err
	if err != nil {
		return []string{}, err
	}
	for _, f := range files {
		if f.IsDir() {
			children = append(children, f.Name())
		}
	}
	return children, nil
}

// Checks whether the cluster is in leaf or not
// It will return error if the cluster doesn't exist,
// false if not a leaf node, true otherwise
func (f *FileStore) checkIsLeafNode(cluster string) (bool, error) {
	var err error
	var dir = f.clusterToPath(cluster)
	var fi os.FileInfo
	// check whether it is a dir
	fi, err = os.Stat(dir)
	if err != nil {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NOT FOUND in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}
	if !fi.IsDir() {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NOT A DIRECTORY in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}

	// now check whether this dir has "cluster.yaml" as its direct child
	_, err = os.Stat(fmt.Sprintf("%s/%s", dir, _config))
	// if err is nil, it means file exists
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NEITHER a LeafNode or a Cluster Dir in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}

	// not a dir
	return true, nil
}

// Given a cluster name, it will read the corresponding cluster config
// and return the file content as a string
func (f *FileStore) readClusterConfig(cluster string) (content []byte, err error) {
	var dir = f.clusterToPath(cluster)
	content, err = ioutil.ReadFile(fmt.Sprintf("%s/%s", dir, _config))
	if err != nil {
		return []byte{}, err
	}

	return content, nil
}
<commit_msg>reverse lookup + merging yaml parsing<commit_after>// When using FileStore, we will have yamls files to store the data.

// FIXME:
// Since I am not planning to use this in production (I prefer etcd as store)
// I would NOT be using any optimizations to cache the process file
// contents (ie, result of yaml parser) Please give me a patch (one way to clear
// the cache is by sending some signals to reread the file and update the cache.
// Also we should make sure we reread only the specific files in question).

package rangestore

import (
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var _config = "cluster.yaml"

type FileStore struct {
	StorePath  string // directory where yamls are stored
	MaxDepth   int    // TODO: we could use this for reverse lookup to limit nested look down
	FastLookup bool   // fast return, will return the first match
}

// check whether the StorePath Exists, etc
func ConnectFileStore(dir string, depth int, fast bool) (f *FileStore, err error) {
	// removing trailing path seperator
	if os.IsPathSeparator(dir[len(dir)-1]) {
		dir = dir[:len(dir)-1]
	}
	var fi os.FileInfo
	// check whether the dir exists
	fi, err = os.Stat(dir)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Path [%s] is not a FileStore directory (ERROR: %s)", dir, err))
	}
	// check whether it is a dir
	if !fi.IsDir() {
		return nil, errors.New(fmt.Sprintf("Path [%s] is not a directory", dir))
	}
	f = &FileStore{StorePath: dir, MaxDepth: depth, FastLookup: fast}
	return f, nil
}

////////////////////
// LOOKUP CLUSTER //
////////////////////

// LOGIC
// -----
// * for the first element in cluster create results array
//   * check whether the cluster is a leaf node
//   * if yes, call KeyLookup, with key == NODES
//   * if not, call listClusters
// * if more elements are there, repeat the above
//   but do an ArraytoSet with the results array
func (f *FileStore) ClusterLookup(cluster *[]string) (*[]string, error) {
	// store the resuls
	var results = make([]string, 0)
	// for each cluster, do a lookup
	// (this will only happen only for nested lookups eg, %%..)
	for _, elem := range *cluster {
		var err error
		isLeaf, err := f.checkIsLeafNode(elem)
		if err != nil {
			return &[]string{}, err
		}
		// if it is a leaf node, we need do a KeyLookup (NODES)
		if isLeaf {
			// by default, lookup for NODES
			result, err := f.KeyLookup(&[]string{elem}, "NODES")
			if err != nil {
				return &[]string{}, err
			}
			results = append(results, *result...)
		} else { // we need to return the children
			result, err := f.listClusters(elem)
			if err != nil {
				return &[]string{}, err
			}
			results = append(results, result...)
		}

	}

	return &results, nil
}

func (f *FileStore) KeyLookup(cluster *[]string, key string) (*[]string, error) {
	// store the resuls
	var results = make([]string, 0)
	// this will most likely be single element arrays
	// can't think of a reason otherwise
	for _, elem := range *cluster {
		// 1. read the config
		// 2. do a key lookup
		// 3. append the result
		content, err := f.readClusterConfig(elem)
		if err != nil {
			return &[]string{}, errors.New(fmt.Sprintf("KeyLookup for [%s] Failed (Error: %s)", elem, err))
		}
		result, err := yamlKeyLookup(content, key)
		if err != nil {
			return &[]string{}, errors.New(fmt.Sprintf("KeyLookup for [%s] Failed (Error: %s)", elem, err))
		}
		results = append(results, *result...)
	}

	return &results, nil
}

////////////////////
// LOOKUP REVERSE //
////////////////////

// same as KeyReverseLookupAttr where attr == NODES
func (f *FileStore) KeyReverseLookup(key string) (*[]string, error) {
	return f.KeyReverseLookupAttr(key, "NODES")
}

// same as KeyReverseLookupAttr where attr == NODES and hint == ""
func (f *FileStore) KeyReverseLookupAttr(key string, attr string) (*[]string, error) {
	return f.KeyReverseLookupHint(key, attr, "")
}

// given a key, it will serach for the cluster where the attr has that key
// hint is to limit the scope of search
func (f *FileStore) KeyReverseLookupHint(key string, attr string, hint string) (*[]string, error) {
	var clusters *[]string
	var err error
	var results = make([]string, 0)
	var seen bool

	clusters, err = f.getAllLeafNodes(hint)
	if err != nil {
		return &results, nil
	}

	for _, elem := range *clusters {
		// get the cluster config
		content, err := f.readClusterConfig(elem)
		if err != nil {
			return &[]string{}, errors.New(fmt.Sprintf("KeyLookup for [%s] Failed (Error: %s)", elem, err))
		}
		// look whether the attr exists
		result, err := yamlKeyLookup(content, attr)
		if err != nil {
			continue // looks like we didn't find the key
		} else {
			for _, i := range *result {
				if i == key {
					results = append(results, elem)
					seen = true
					break
				}
			}
			if seen && f.FastLookup {
				return &results, nil
			}
		}
	}

	return &results, nil
}

////////////////////////
// Internal Functions //
////////////////////////

// given a cluster name, it will convert to cluster
// in the file system
func (f *FileStore) clusterToPath(cluster string) string {
	return fmt.Sprintf("%s/%s", f.StorePath, strings.Replace(cluster, "-", "/", -1))
}

// reads the child clusters of this cluster.
// returns only those nodes for which this cluster is parent
func (f *FileStore) listClusters(cluster string) ([]string, error) {
	var dir = f.clusterToPath(cluster)
	var children = make([]string, 0)
	files, err := ioutil.ReadDir(dir)
	// if there is an error, return err
	if err != nil {
		return []string{}, err
	}
	for _, f := range files {
		if f.IsDir() {
			children = append(children, f.Name())
		}
	}
	return children, nil
}

// Checks whether the cluster is in leaf or not
// It will return error if the cluster doesn't exist,
// false if not a leaf node, true otherwise
func (f *FileStore) checkIsLeafNode(cluster string) (bool, error) {
	var err error
	var dir = f.clusterToPath(cluster)
	var fi os.FileInfo
	// check whether it is a dir
	fi, err = os.Stat(dir)
	if err != nil {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NOT FOUND in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}
	if !fi.IsDir() {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NOT A DIRECTORY in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}

	// now check whether this dir has "cluster.yaml" as its direct child
	_, err = os.Stat(fmt.Sprintf("%s/%s", dir, _config))
	// if err is nil, it means file exists
	if err == nil {
		return true, nil
	} else if os.IsNotExist(err) {
		return false, nil
	} else {
		return false, errors.New(fmt.Sprintf("cluser [%s] is NEITHER a LeafNode or a Cluster Dir in FileStore [%s w.r.t %s] (ERROR: %s)", cluster, dir, f.StorePath, err))
	}

	// not a dir
	return true, nil
}

// Given a cluster name, it will read the corresponding cluster config
// and return the file content as a string
func (f *FileStore) readClusterConfig(cluster string) (content []byte, err error) {
	var dir = f.clusterToPath(cluster)
	content, err = ioutil.ReadFile(fmt.Sprintf("%s/%s", dir, _config))
	if err != nil {
		return []byte{}, err
	}

	return content, nil
}

// Get all the leaf cluster nodes for a given dir
// NOTE: This code is not efficient as "path/filepath" Walk() function
// is not efficient since it does the walk in lexical order
func (f *FileStore) getAllLeafNodes(root string) (*[]string, error) {
	var leafs = make([]string, 0)
	var err error
	// if root is given, append to localize the lookup
	root = f.clusterToPath(root)
	// do a Clean to remove weirdness in path
	trimPath := fmt.Sprintf("%s/", filepath.Clean(f.StorePath))
	// do the walk
	err = filepath.Walk(
		root,
		// append only the name matches _config
		func(path string, fi os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if fi.Name() == _config {
				leafs = append(leafs, strings.Replace(strings.TrimPrefix(filepath.Dir(path), trimPath), "/", "-", -1))
			}
			return nil
		},
	)

	if err != nil {
		return &[]string{}, errors.New(fmt.Sprintf("filepath.Walk Failed for ROOT dir [%s]", root))
	}

	return &leafs, nil
}

// We expect the YAML data to be in key value, where value is
// an array. Incase value is not an array, we will still return
// as an array
func yamlKeyLookup(content []byte, key string) (*[]string, error) {
	var u map[string]interface{}
	var err error
	err = yaml.Unmarshal(content, &u)
	// if unmarshal fails, return early with error
	if err != nil {
		return &[]string{}, err
	}

	// handle KEYS seperately
	// returns all the KEYS of a cluster
	if key == "KEYS" {
		var results = make([]string, 0)
		for k := range u {
			results = append(results, k)
		}
		return &results, nil
	}

	// check whether the map has the key we are looking for
	value, ok := u[key]
	if !ok {
		return &[]string{}, errors.New(fmt.Sprintf("Cannot find Key [%s]", key))
	}

	// try to return result pointer to an array of strings
	switch value.(type) {
	// if it is an array
	case []interface{}:
		var results = make([]string, 0)
		for _, elem := range value.([]interface{}) {
			switch elem.(type) {
			case string:
				results = append(results, elem.(string))
			case int:
				results = append(results, fmt.Sprintf("%d", elem.(int)))
			case bool:
				results = append(results, fmt.Sprintf("%t", elem.(bool)))
			}
		}
		return &results, nil
		// if not an array, make it an array
	case string:
		return &[]string{value.(string)}, nil
	case int:
		return &[]string{fmt.Sprintf("%d", value.(int))}, nil
	case bool:
		return &[]string{fmt.Sprintf("%t", value.(bool))}, nil
	}

	return &[]string{}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"
	"sync"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/vmarmol/vertigo/let/api"
)

type DockerTaskManager struct {
	client *docker.Client
	lock   sync.Mutex
}

var endpoint = "unix:///var/run/docker.sock"

type TaskManager interface {
	RunTask(runspec *api.RunSpec) (containerSpec *api.ContainerSpec, err error)
}

func NewDockerTaskManager() (TaskManager, error) {
	client, err := docker.NewClient(endpoint)
	if err != nil {
		return nil, err
	}
	return &DockerTaskManager{
		client: client,
	}, nil
}

func (self *DockerTaskManager) pull(image string) error {
	self.lock.Lock()
	defer self.lock.Unlock()
	cmd := exec.Command("docker", "pull", image)
	err := cmd.Start()
	if err != nil {
		return err
	}
	return cmd.Wait()
}

func randomUniqString() string {
	var d [8]byte
	io.ReadFull(rand.Reader, d[:])
	str := hex.EncodeToString(d[:])
	return fmt.Sprintf("%x-%v", time.Now().Unix(), str)
}

func (self *DockerTaskManager) RunTask(runspec *api.RunSpec) (containerSpec *api.ContainerSpec, err error) {
	err = self.pull(runspec.Image)
	if err != nil {
		return
	}

	exposedPorts := make(map[docker.Port]struct{}, len(runspec.Ports))
	portBindings := make(map[docker.Port][]docker.PortBinding, len(runspec.Ports))
	for _, port := range runspec.Ports {
		if port.HostPort != port.ContainerPort {
			err = fmt.Errorf("host port != container port: %+v", port)
			return
		}
		dport := docker.Port(fmt.Sprintf("%v/tcp", port.ContainerPort))
		exposedPorts[dport] = struct{}{}
		portBindings[dport] = []docker.PortBinding{
			docker.PortBinding{
				HostPort: fmt.Sprintf("%v", port.HostPort),
			},
		}
	}

	name := randomUniqString()
	env := make([]string, 0, len(runspec.Env))
	for _, e := range runspec.Env {
		env = append(env, e.String())
	}

	cmd := make([]string, 0, 1+len(runspec.Args))
	cmd = append(cmd, runspec.Cmd)
	if len(runspec.Args) > 0 {
		cmd = append(cmd, runspec.Args...)
	}

	opts := docker.CreateContainerOptions{
		Name: name,
		Config: &docker.Config{
			Image:        runspec.Image,
			ExposedPorts: exposedPorts,
			Env:          env,
			Cmd:          cmd,
		},
	}
	container, err := self.client.CreateContainer(opts)
	if err != nil {
		return
	}

	err = self.client.StartContainer(container.ID, &docker.HostConfig{
		PortBindings: portBindings,
	})
	if err != nil {
		return
	}
	containerSpec = &api.ContainerSpec{
		Id: container.ID,
	}
	return
}
<commit_msg>tested<commit_after>package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os/exec"
	"sync"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/vmarmol/vertigo/let/api"
)

type DockerTaskManager struct {
	client *docker.Client
	lock   sync.Mutex
}

var endpoint = "unix:///var/run/docker.sock"

type TaskManager interface {
	RunTask(runspec *api.RunSpec) (containerSpec *api.ContainerSpec, err error)
}

func NewDockerTaskManager() (TaskManager, error) {
	client, err := docker.NewClient(endpoint)
	if err != nil {
		return nil, err
	}
	return &DockerTaskManager{
		client: client,
	}, nil
}

func (self *DockerTaskManager) pull(image string) error {
	self.lock.Lock()
	defer self.lock.Unlock()
	cmd := exec.Command("docker", "pull", image)
	err := cmd.Start()
	if err != nil {
		return err
	}
	return cmd.Wait()
}

func randomUniqString() string {
	var d [8]byte
	io.ReadFull(rand.Reader, d[:])
	str := hex.EncodeToString(d[:])
	return fmt.Sprintf("%x-%v", time.Now().Unix(), str)
}

func (self *DockerTaskManager) RunTask(runspec *api.RunSpec) (containerSpec *api.ContainerSpec, err error) {
	err = self.pull(runspec.Image)
	if err != nil {
		return
	}
	log.Println("pulled image")

	exposedPorts := make(map[docker.Port]struct{}, len(runspec.Ports))
	portBindings := make(map[docker.Port][]docker.PortBinding, len(runspec.Ports))
	for _, port := range runspec.Ports {
		if port.HostPort != port.ContainerPort {
			err = fmt.Errorf("host port != container port: %+v", port)
			return
		}
		dport := docker.Port(fmt.Sprintf("%v/tcp", port.ContainerPort))
		exposedPorts[dport] = struct{}{}
		portBindings[dport] = []docker.PortBinding{
			docker.PortBinding{
				HostPort: fmt.Sprintf("%v", port.HostPort),
			},
		}
	}

	name := randomUniqString()
	env := make([]string, 0, len(runspec.Env))
	for _, e := range runspec.Env {
		env = append(env, e.String())
	}

	cmd := make([]string, 0, 1+len(runspec.Args))
	cmd = append(cmd, runspec.Cmd)
	if len(runspec.Args) > 0 {
		cmd = append(cmd, runspec.Args...)
	}

	opts := docker.CreateContainerOptions{
		Name: name,
		Config: &docker.Config{
			Image:        runspec.Image,
			ExposedPorts: exposedPorts,
			Env:          env,
			Cmd:          cmd,
		},
	}
	log.Printf("creating container %+v\n", opts)
	container, err := self.client.CreateContainer(opts)
	if err != nil {
		return
	}
	log.Printf("created container %+v\n", container)

	err = self.client.StartContainer(container.ID, &docker.HostConfig{
		PortBindings: portBindings,
	})
	if err != nil {
		return
	}
	log.Printf("started container\n")
	containerSpec = &api.ContainerSpec{
		Id: container.ID,
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package runtime

import "runtime/internal/sys"

const (
	_SIG_DFL uintptr = 0
	_SIG_IGN uintptr = 1
)

// Stores the signal handlers registered before Go installed its own.
// These signal handlers will be invoked in cases where Go doesn't want to
// handle a particular signal (e.g., signal occurred on a non-Go thread).
// See sigfwdgo() for more information on when the signals are forwarded.
//
// Signal forwarding is currently available only on Darwin and Linux.
var fwdSig [_NSIG]uintptr

// sigmask represents a general signal mask compatible with the GOOS
// specific sigset types: the signal numbered x is represented by bit x-1
// to match the representation expected by sigprocmask.
type sigmask [(_NSIG + 31) / 32]uint32

// channels for synchronizing signal mask updates with the signal mask
// thread
var (
	disableSigChan  chan uint32
	enableSigChan   chan uint32
	maskUpdatedChan chan struct{}
)

func initsig() {
	// _NSIG is the number of signals on this operating system.
	// sigtable should describe what to do for all the possible signals.
	if len(sigtable) != _NSIG {
		print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
		throw("initsig")
	}

	// First call: basic setup.
	for i := int32(0); i < _NSIG; i++ {
		t := &sigtable[i]
		if t.flags == 0 || t.flags&_SigDefault != 0 {
			continue
		}
		fwdSig[i] = getsig(i)
		// For some signals, we respect an inherited SIG_IGN handler
		// rather than insist on installing our own default handler.
		// Even these signals can be fetched using the os/signal package.
		switch i {
		case _SIGHUP, _SIGINT:
			if getsig(i) == _SIG_IGN {
				t.flags = _SigNotify | _SigIgnored
				continue
			}
		}

		if t.flags&_SigSetStack != 0 {
			setsigstack(i)
			continue
		}

		t.flags |= _SigHandling
		setsig(i, funcPC(sighandler), true)
	}
}

func sigenable(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		ensureSigM()
		enableSigChan <- sig
		<-maskUpdatedChan
		if t.flags&_SigHandling == 0 {
			t.flags |= _SigHandling
			if getsig(int32(sig)) == _SIG_IGN {
				t.flags |= _SigIgnored
			}
			setsig(int32(sig), funcPC(sighandler), true)
		}
	}
}

func sigdisable(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		ensureSigM()
		disableSigChan <- sig
		<-maskUpdatedChan
		if t.flags&_SigHandling != 0 {
			t.flags &^= _SigHandling
			if t.flags&_SigIgnored != 0 {
				setsig(int32(sig), _SIG_IGN, true)
			} else {
				setsig(int32(sig), _SIG_DFL, true)
			}
		}
	}
}

func sigignore(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		t.flags &^= _SigHandling
		setsig(int32(sig), _SIG_IGN, true)
	}
}

func resetcpuprofiler(hz int32) {
	var it itimerval
	if hz == 0 {
		setitimer(_ITIMER_PROF, &it, nil)
	} else {
		it.it_interval.tv_sec = 0
		it.it_interval.set_usec(1000000 / hz)
		it.it_value = it.it_interval
		setitimer(_ITIMER_PROF, &it, nil)
	}
	_g_ := getg()
	_g_.m.profilehz = hz
}

func sigpipe() {
	setsig(_SIGPIPE, _SIG_DFL, false)
	raise(_SIGPIPE)
}

// raisebadsignal is called when a signal is received on a non-Go
// thread, and the Go program does not want to handle it (that is, the
// program has not called os/signal.Notify for the signal).
func raisebadsignal(sig int32) {
	if sig == _SIGPROF {
		// Ignore profiling signals that arrive on non-Go threads.
		return
	}

	var handler uintptr
	if sig >= _NSIG {
		handler = _SIG_DFL
	} else {
		handler = fwdSig[sig]
	}

	// Reset the signal handler and raise the signal.
	// We are currently running inside a signal handler, so the
	// signal is blocked.  We need to unblock it before raising the
	// signal, or the signal we raise will be ignored until we return
	// from the signal handler.  We know that the signal was unblocked
	// before entering the handler, or else we would not have received
	// it.  That means that we don't have to worry about blocking it
	// again.
	unblocksig(sig)
	setsig(sig, handler, false)
	raise(sig)

	// If the signal didn't cause the program to exit, restore the
	// Go signal handler and carry on.
	//
	// We may receive another instance of the signal before we
	// restore the Go handler, but that is not so bad: we know
	// that the Go program has been ignoring the signal.
	setsig(sig, funcPC(sighandler), true)
}

func crash() {
	if GOOS == "darwin" {
		// OS X core dumps are linear dumps of the mapped memory,
		// from the first virtual byte to the last, with zeros in the gaps.
		// Because of the way we arrange the address space on 64-bit systems,
		// this means the OS X core file will be >128 GB and even on a zippy
		// workstation can take OS X well over an hour to write (uninterruptible).
		// Save users from making that mistake.
		if sys.PtrSize == 8 {
			return
		}
	}

	updatesigmask(sigmask{})
	setsig(_SIGABRT, _SIG_DFL, false)
	raise(_SIGABRT)
}

// ensureSigM starts one global, sleeping thread to make sure at least one thread
// is available to catch signals enabled for os/signal.
func ensureSigM() {
	if maskUpdatedChan != nil {
		return
	}
	maskUpdatedChan = make(chan struct{})
	disableSigChan = make(chan uint32)
	enableSigChan = make(chan uint32)
	go func() {
		// Signal masks are per-thread, so make sure this goroutine stays on one
		// thread.
		LockOSThread()
		defer UnlockOSThread()
		// The sigBlocked mask contains the signals not active for os/signal,
		// initially all signals except the essential. When signal.Notify()/Stop is called,
		// sigenable/sigdisable in turn notify this thread to update its signal
		// mask accordingly.
		var sigBlocked sigmask
		for i := range sigBlocked {
			sigBlocked[i] = ^uint32(0)
		}
		for i := range sigtable {
			if sigtable[i].flags&_SigUnblock != 0 {
				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
			}
		}
		updatesigmask(sigBlocked)
		for {
			select {
			case sig := <-enableSigChan:
				if b := sig - 1; b >= 0 {
					sigBlocked[b/32] &^= (1 << (b & 31))
				}
			case sig := <-disableSigChan:
				if b := sig - 1; b >= 0 {
					sigBlocked[b/32] |= (1 << (b & 31))
				}
			}
			updatesigmask(sigBlocked)
			maskUpdatedChan <- struct{}{}
		}
	}()
}
<commit_msg>runtime: fix integer comparison in signal handling<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package runtime

import "runtime/internal/sys"

const (
	_SIG_DFL uintptr = 0
	_SIG_IGN uintptr = 1
)

// Stores the signal handlers registered before Go installed its own.
// These signal handlers will be invoked in cases where Go doesn't want to
// handle a particular signal (e.g., signal occurred on a non-Go thread).
// See sigfwdgo() for more information on when the signals are forwarded.
//
// Signal forwarding is currently available only on Darwin and Linux.
var fwdSig [_NSIG]uintptr

// sigmask represents a general signal mask compatible with the GOOS
// specific sigset types: the signal numbered x is represented by bit x-1
// to match the representation expected by sigprocmask.
type sigmask [(_NSIG + 31) / 32]uint32

// channels for synchronizing signal mask updates with the signal mask
// thread
var (
	disableSigChan  chan uint32
	enableSigChan   chan uint32
	maskUpdatedChan chan struct{}
)

func initsig() {
	// _NSIG is the number of signals on this operating system.
	// sigtable should describe what to do for all the possible signals.
	if len(sigtable) != _NSIG {
		print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
		throw("initsig")
	}

	// First call: basic setup.
	for i := int32(0); i < _NSIG; i++ {
		t := &sigtable[i]
		if t.flags == 0 || t.flags&_SigDefault != 0 {
			continue
		}
		fwdSig[i] = getsig(i)
		// For some signals, we respect an inherited SIG_IGN handler
		// rather than insist on installing our own default handler.
		// Even these signals can be fetched using the os/signal package.
		switch i {
		case _SIGHUP, _SIGINT:
			if getsig(i) == _SIG_IGN {
				t.flags = _SigNotify | _SigIgnored
				continue
			}
		}

		if t.flags&_SigSetStack != 0 {
			setsigstack(i)
			continue
		}

		t.flags |= _SigHandling
		setsig(i, funcPC(sighandler), true)
	}
}

func sigenable(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		ensureSigM()
		enableSigChan <- sig
		<-maskUpdatedChan
		if t.flags&_SigHandling == 0 {
			t.flags |= _SigHandling
			if getsig(int32(sig)) == _SIG_IGN {
				t.flags |= _SigIgnored
			}
			setsig(int32(sig), funcPC(sighandler), true)
		}
	}
}

func sigdisable(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		ensureSigM()
		disableSigChan <- sig
		<-maskUpdatedChan
		if t.flags&_SigHandling != 0 {
			t.flags &^= _SigHandling
			if t.flags&_SigIgnored != 0 {
				setsig(int32(sig), _SIG_IGN, true)
			} else {
				setsig(int32(sig), _SIG_DFL, true)
			}
		}
	}
}

func sigignore(sig uint32) {
	if sig >= uint32(len(sigtable)) {
		return
	}

	t := &sigtable[sig]
	if t.flags&_SigNotify != 0 {
		t.flags &^= _SigHandling
		setsig(int32(sig), _SIG_IGN, true)
	}
}

func resetcpuprofiler(hz int32) {
	var it itimerval
	if hz == 0 {
		setitimer(_ITIMER_PROF, &it, nil)
	} else {
		it.it_interval.tv_sec = 0
		it.it_interval.set_usec(1000000 / hz)
		it.it_value = it.it_interval
		setitimer(_ITIMER_PROF, &it, nil)
	}
	_g_ := getg()
	_g_.m.profilehz = hz
}

func sigpipe() {
	setsig(_SIGPIPE, _SIG_DFL, false)
	raise(_SIGPIPE)
}

// raisebadsignal is called when a signal is received on a non-Go
// thread, and the Go program does not want to handle it (that is, the
// program has not called os/signal.Notify for the signal).
func raisebadsignal(sig int32) {
	if sig == _SIGPROF {
		// Ignore profiling signals that arrive on non-Go threads.
		return
	}

	var handler uintptr
	if sig >= _NSIG {
		handler = _SIG_DFL
	} else {
		handler = fwdSig[sig]
	}

	// Reset the signal handler and raise the signal.
	// We are currently running inside a signal handler, so the
	// signal is blocked.  We need to unblock it before raising the
	// signal, or the signal we raise will be ignored until we return
	// from the signal handler.  We know that the signal was unblocked
	// before entering the handler, or else we would not have received
	// it.  That means that we don't have to worry about blocking it
	// again.
	unblocksig(sig)
	setsig(sig, handler, false)
	raise(sig)

	// If the signal didn't cause the program to exit, restore the
	// Go signal handler and carry on.
	//
	// We may receive another instance of the signal before we
	// restore the Go handler, but that is not so bad: we know
	// that the Go program has been ignoring the signal.
	setsig(sig, funcPC(sighandler), true)
}

func crash() {
	if GOOS == "darwin" {
		// OS X core dumps are linear dumps of the mapped memory,
		// from the first virtual byte to the last, with zeros in the gaps.
		// Because of the way we arrange the address space on 64-bit systems,
		// this means the OS X core file will be >128 GB and even on a zippy
		// workstation can take OS X well over an hour to write (uninterruptible).
		// Save users from making that mistake.
		if sys.PtrSize == 8 {
			return
		}
	}

	updatesigmask(sigmask{})
	setsig(_SIGABRT, _SIG_DFL, false)
	raise(_SIGABRT)
}

// ensureSigM starts one global, sleeping thread to make sure at least one thread
// is available to catch signals enabled for os/signal.
func ensureSigM() {
	if maskUpdatedChan != nil {
		return
	}
	maskUpdatedChan = make(chan struct{})
	disableSigChan = make(chan uint32)
	enableSigChan = make(chan uint32)
	go func() {
		// Signal masks are per-thread, so make sure this goroutine stays on one
		// thread.
		LockOSThread()
		defer UnlockOSThread()
		// The sigBlocked mask contains the signals not active for os/signal,
		// initially all signals except the essential. When signal.Notify()/Stop is called,
		// sigenable/sigdisable in turn notify this thread to update its signal
		// mask accordingly.
		var sigBlocked sigmask
		for i := range sigBlocked {
			sigBlocked[i] = ^uint32(0)
		}
		for i := range sigtable {
			if sigtable[i].flags&_SigUnblock != 0 {
				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
			}
		}
		updatesigmask(sigBlocked)
		for {
			select {
			case sig := <-enableSigChan:
				if b := sig - 1; sig > 0 {
					sigBlocked[b/32] &^= (1 << (b & 31))
				}
			case sig := <-disableSigChan:
				if b := sig - 1; sig > 0 {
					sigBlocked[b/32] |= (1 << (b & 31))
				}
			}
			updatesigmask(sigBlocked)
			maskUpdatedChan <- struct{}{}
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func brainfuck(src string) []uint8 {
	tape := []uint8{0}
	tapeIndex := 0

	srcLength := len(src)

	for srcIndex := 0; srcIndex < srcLength; srcIndex++ {

		switch src[srcIndex] {
		case '>':
			tapeIndex += 1
			if len(tape) <= tapeIndex {
				tape = append(tape, 0)
			}

		case '<':
			if tapeIndex > 0 {
				tapeIndex -= 1
			}

		case '+':
			tape[tapeIndex] += 1

		case '-':
			tape[tapeIndex] -= 1

		case '.':
			fmt.Print(string(tape[tapeIndex]))

		case ',':
			b := make([]byte, 1)
			os.Stdin.Read(b)
			tape[tapeIndex] = b[0]

		case '[':
			if tape[tapeIndex] == 0 {
				depth := 1
				for depth > 0 {
					srcIndex++
					srcCharacter := src[srcIndex]
					if srcCharacter == '[' {
						depth++
					} else if srcCharacter == ']' {
						depth--
					}
				}
			}

		case ']':
			depth := 1
			for depth > 0 {
				srcIndex--
				srcCharacter := src[srcIndex]
				if srcCharacter == '[' {
					depth--
				} else if srcCharacter == ']' {
					depth++
				}
			}
			srcIndex--
		}
	}

	return tape
}

func main() {
	content, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Println("Error reading file")
		fmt.Println(err)
	} else {
		var src = string(content)

		brainfuck(src)
	}
}
<commit_msg>declare looping 'depth' IN the for statement<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func brainfuck(src string) []uint8 {
	tape := []uint8{0}
	tapeIndex := 0

	srcLength := len(src)

	for srcIndex := 0; srcIndex < srcLength; srcIndex++ {

		switch src[srcIndex] {
		case '>':
			tapeIndex += 1
			if len(tape) <= tapeIndex {
				tape = append(tape, 0)
			}

		case '<':
			if tapeIndex > 0 {
				tapeIndex -= 1
			}

		case '+':
			tape[tapeIndex] += 1

		case '-':
			tape[tapeIndex] -= 1

		case '.':
			fmt.Print(string(tape[tapeIndex]))

		case ',':
			b := make([]byte, 1)
			os.Stdin.Read(b)
			tape[tapeIndex] = b[0]

		case '[':
			if tape[tapeIndex] == 0 {
				for depth := 1; depth > 0; {
					srcIndex++
					srcCharacter := src[srcIndex]
					if srcCharacter == '[' {
						depth++
					} else if srcCharacter == ']' {
						depth--
					}
				}
			}

		case ']':
			for depth := 1; depth > 0; {
				srcIndex--
				srcCharacter := src[srcIndex]
				if srcCharacter == '[' {
					depth--
				} else if srcCharacter == ']' {
					depth++
				}
			}
			srcIndex--
		}
	}

	return tape
}

func main() {
	content, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Println("Error reading file")
		fmt.Println(err)
	} else {
		var src = string(content)

		brainfuck(src)
	}
}
<|endoftext|>