// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *ToHTTPGetRequest) Run() {
	var respPath, msgPath string

	var respTree, msgTree *jee.TokenTree
	var err error
	for {
		select {
		case ruleI := <-b.inrule:
			respPath, err = util.ParseString(ruleI, "RespPath")
			respTree, err = util.BuildTokenTree(respPath)
			if err != nil {
				b.Error(err)
				break
			}
			msgPath, err = util.ParseString(ruleI, "MsgPath")
			msgTree, err = util.BuildTokenTree(msgPath)
			if err != nil {
				b.Error(err)
				break
			}
		case <-b.quit:
			return
		case msg := <-b.in:
			if respTree == nil {
				continue
			}
			if msgTree == nil {
				continue
			}
			cI, err := jee.Eval(respTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			c, ok := cI.(blocks.MsgChan)
			if !ok {
				b.Error(errors.New("response path must point to a channel"))
				continue
			}
			m, err := jee.Eval(msgTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			c <- m
		case responseChan := <-b.queryrule:
			// deal with a query request
			responseChan <- map[string]interface{}{
				"RespPath": respPath,
				"MsgPath":  msgPath,
			}
		}
	}
}
Beispiel #2
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *Set) Run() {
	var path string
	set := make(map[interface{}]bool)
	var tree *jee.TokenTree
	var err error
	for {
		select {
		case ruleI := <-b.inrule:
			// set a parameter of the block
			path, err = util.ParseString(ruleI, "Path")
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				break
			}
		case <-b.quit:
			// quit the block
			return
		case msg := <-b.add:
			if tree == nil {
				continue
			}
			v, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			if _, ok := v.(string); !ok {
				b.Error(errors.New("can only build sets of strings"))
				continue
			}
			set[v] = true
			// deal with inbound data
		case msg := <-b.isMember:
			if tree == nil {
				continue
			}
			v, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			_, ok := set[v]
			b.out <- map[string]interface{}{
				"isMember": ok,
			}
		case c := <-b.cardinality:
			c <- map[string]interface{}{
				"cardinality": len(set),
			}
		case c := <-b.queryrule:
			// deal with a query request
			c <- map[string]interface{}{
				"Path": path,
			}

		}
	}
}
Beispiel #3
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *DeDupe) Run() {
	var path string
	set := make(map[interface{}]bool)
	var tree *jee.TokenTree
	var err error
	for {
		select {
		case ruleI := <-b.inrule:
			// set a parameter of the block
			path, err = util.ParseString(ruleI, "Path")
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				break
			}
		case <-b.quit:
			// quit the block
			return
			// deal with inbound data
		case msg := <-b.in:
			if tree == nil {
				continue
			}
			v, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				break
			}

			if _, ok := v.(string); !ok {
				b.Error(errors.New("can only dedupe sets of strings"))
				continue
			}

			_, ok := set[v]
			// emit the incoming message if it isn't found in the set
			if !ok {
				b.out <- msg
				set[v] = true // and add it to the set
			}
		case c := <-b.queryrule:
			// deal with a query request
			c <- map[string]interface{}{
				"Path": path,
			}

		}
	}
}
Beispiel #4
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *MovingAverage) Run() {
	var tree *jee.TokenTree
	var path, windowString string
	var err error
	window := time.Duration(0)
	waitTimer := time.NewTimer(100 * time.Millisecond)

	pq := &PriorityQueue{}
	heap.Init(pq)

	for {
		select {
		case ruleI := <-b.inrule:
			// set a parameter of the block
			path, err = util.ParseString(ruleI, "Path")
			if err != nil {
				b.Error(err)
			}
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				break
			}
			windowString, err = util.ParseString(ruleI, "Window")
			if err != nil {
				b.Error(err)
			}
			window, err = time.ParseDuration(windowString)
			if err != nil {
				b.Error(err)
			}
		case <-b.quit:
			// quit the block
			return
		case msg := <-b.in:
			// deal with inbound data
			if tree == nil {
				break
			}
			val, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			// TODO make this a type swtich and convert anything we can to a
			// float
			val, ok := val.(float64)
			if !ok {
				b.Error(errors.New("trying to put a non-float into the moving average"))
				continue
			}
			queueMessage := &PQMessage{
				val: val,
				t:   time.Now(),
			}
			heap.Push(pq, queueMessage)
		case <-b.inpoll:
			// deal with a poll request
			outMsg := map[string]interface{}{
				"Average": pqAverage(pq),
			}
			b.out <- outMsg
		case c := <-b.queryavg:
			outMsg := map[string]interface{}{
				"Average": pqAverage(pq),
			}
			c <- outMsg
		case c := <-b.queryrule:
			// deal with a query request
			c <- map[string]interface{}{
				"Path":   path,
				"Window": windowString,
			}
		case <-waitTimer.C:
		}
		for {
			pqMsg, diff := pq.PeekAndShift(time.Now(), window)
			if pqMsg == nil {
				// either the queue is empty, or it's not time to emit
				if diff == 0 {
					// then the queue is empty. Pause for 5 seconds before checking again
					diff = time.Duration(500) * time.Millisecond
				}
				waitTimer.Reset(diff)
				break
			}
		}
	}
}
func (b *KullbackLeibler) Run() {
	var qtree, ptree *jee.TokenTree
	var qpath, ppath string
	var err error
	for {
		select {
		case ruleI := <-b.inrule:
			qpath, err = util.ParseString(ruleI, "QPath")
			if err != nil {
				b.Error(err)
			}
			qtree, err = util.BuildTokenTree(qpath)
			ppath, err = util.ParseString(ruleI, "PPath")
			if err != nil {
				b.Error(err)
			}
			ptree, err = util.BuildTokenTree(ppath)
		case c := <-b.queryrule:
			c <- map[string]interface{}{
				"QPath": qpath,
				"PPath": ppath,
			}
		case <-b.quit:
			return
		case msg := <-b.in:
			if ptree == nil {
				continue
			}
			if qtree == nil {
				continue
			}
			pI, err := jee.Eval(ptree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			qI, err := jee.Eval(qtree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			p, ok := newHistogram(pI)
			if !ok {
				b.Error(errors.New("p is not a Histogram"))
				continue
			}
			q, ok := newHistogram(qI)
			if !ok {
				b.Error(errors.New("q is not a Histogram"))
				continue
			}
			q.normalise(p)
			p.normalise(q)
			kl := 0.0
			for k, pi := range p {
				kl += math.Log(pi/q[k]) * pi
			}
			b.out <- map[string]interface{}{
				"KL": kl,
			}
		}
	}
}
Beispiel #6
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *Cache) Run() {
	var keyPath, valuePath, ttlString string
	var ttl time.Duration
	values := make(map[string]item)
	ttlQueue := &PriorityQueue{}

	var keyTree, valueTree *jee.TokenTree
	var err error
	emitTick := time.NewTimer(500 * time.Millisecond)
	for {
		select {
		case <-emitTick.C:

		case ruleI := <-b.inrule:
			keyPath, err = util.ParseString(ruleI, "KeyPath")
			keyTree, err = util.BuildTokenTree(keyPath)
			if err != nil {
				b.Error(err)
				break
			}
			valuePath, err = util.ParseString(ruleI, "ValuePath")
			valueTree, err = util.BuildTokenTree(valuePath)
			if err != nil {
				b.Error(err)
				break
			}
			ttlString, err = util.ParseString(ruleI, "TimeToLive")
			if err != nil {
				b.Error(err)
				break
			}
			ttl, err = time.ParseDuration(ttlString)
			if err != nil {
				b.Error(err)
				break
			}
		case <-b.quit:
			return
		case msg := <-b.lookup:
			if keyTree == nil {
				continue
			}
			kI, err := jee.Eval(keyTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			k, ok := kI.(string)
			if !ok {
				b.Error(errors.New("key must be a string"))
				continue
			}
			i, ok := values[k]
			var v interface{}
			if ok {
				v = i.value
				now := time.Now()
				i.lastSeen = now
				queueMessage := &PQMessage{
					val: k,
					t:   now,
				}
				heap.Push(ttlQueue, queueMessage)
			}
			b.out <- map[string]interface{}{
				"key":   k,
				"value": v,
			}
		case msg := <-b.in:
			if keyTree == nil {
				continue
			}
			if valueTree == nil {
				continue
			}
			kI, err := jee.Eval(keyTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			k, ok := kI.(string)
			if !ok {
				b.Error(errors.New("key must be a string"))
				continue
			}
			v, err := jee.Eval(valueTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			now := time.Now()
			values[k] = item{
				value:    v,
				lastSeen: now,
			}
			queueMessage := &PQMessage{
				val: k,
				t:   now,
			}
			heap.Push(ttlQueue, queueMessage)
		case responseChan := <-b.queryrule:
			// deal with a query request
			responseChan <- map[string]interface{}{
				"KeyPath":    keyPath,
				"ValuePath":  valuePath,
				"TimeToLive": ttlString,
			}
		}
		now := time.Now()
		for {
			itemI, diff := ttlQueue.PeekAndShift(now, ttl)
			if itemI == nil {
				// then the queue is empty. don't check again for 5s
				if diff == 0 {
					diff = time.Duration(500) * time.Millisecond
				}
				emitTick.Reset(diff)
				break
			}
			i := itemI.(*PQMessage)
			k := i.val.(string)
			if i.t.Equal(values[k].lastSeen) {
				delete(values, k)
			}
		}
	}
}
Beispiel #7
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *Timeseries) Run() {

	var err error
	//var path, lagStr string
	var path string
	var tree *jee.TokenTree
	//var lag time.Duration
	var data tsData
	var numSamples float64

	// defaults
	numSamples = 1

	for {
		select {
		case ruleI := <-b.inrule:
			// set a parameter of the block
			rule, ok := ruleI.(map[string]interface{})
			if !ok {
				b.Error(errors.New("could not assert rule to map"))
			}
			path, err = util.ParseString(rule, "Path")
			if err != nil {
				b.Error(err)
				continue
			}
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				continue
			}
			/*
				lagStr, err = util.ParseString(rule, "Lag")
				if err != nil {
					b.Error(err)
					continue
				}
				lag, err = time.ParseDuration(lagStr)
				if err != nil {
					b.Error(err)
					continue
				}
			*/
			numSamples, err = util.ParseFloat(rule, "NumSamples")
			if err != nil {
				b.Error(err)
				continue
			}
			data = tsData{
				Values: make([]tsDataPoint, int(numSamples)),
			}

		case <-b.quit:
			// quit * time.Second the block
			return
		case msg := <-b.in:
			if tree == nil {
				continue
			}
			if data.Values == nil {
				continue
			}
			// deal with inbound data
			v, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				continue
			}
			var val float64
			switch v := v.(type) {
			case float32:
				val = float64(v)
			case int:
				val = float64(v)
			case float64:
				val = v
			}

			//t := float64(time.Now().Add(-lag).Unix())
			t := float64(time.Now().Unix())

			d := tsDataPoint{
				Timestamp: t,
				Value:     val,
			}
			data.Values = append(data.Values[1:], d)
		case MsgChan := <-b.queryrule:
			// deal with a query request
			MsgChan <- map[string]interface{}{
				//"Window":     lagStr,
				"Path":       path,
				"NumSamples": numSamples,
			}
		case MsgChan := <-b.querystate:
			out := map[string]interface{}{
				"timeseries": data,
			}
			MsgChan <- out
		case <-b.inpoll:
			outArray := make([]interface{}, len(data.Values))
			for i, d := range data.Values {
				di := map[string]interface{}{
					"timestamp": d.Timestamp,
					"value":     d.Value,
				}
				outArray[i] = di
			}
			out := map[string]interface{}{
				"timeseries": outArray,
			}
			b.out <- out
		}
	}
}
Beispiel #8
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *Cache) Run() {
	var keyPath, valuePath, ttlString string
	var ttl time.Duration
	cache := make(map[string]item)
	ttlQueue := &PriorityQueue{}

	var keyTree, valueTree *jee.TokenTree
	var err error
	emitTick := time.NewTimer(500 * time.Millisecond)
	for {
		select {
		case <-emitTick.C:

		case ruleI := <-b.inrule:
			keyPath, err = util.ParseString(ruleI, "KeyPath")
			keyTree, err = util.BuildTokenTree(keyPath)
			if err != nil {
				b.Error(err)
				break
			}
			valuePath, err = util.ParseString(ruleI, "ValuePath")
			valueTree, err = util.BuildTokenTree(valuePath)
			if err != nil {
				b.Error(err)
				break
			}
			ttlString, err = util.ParseString(ruleI, "TimeToLive")
			if err != nil {
				b.Error(err)
				break
			}
			ttl, err = time.ParseDuration(ttlString)
			if err != nil {
				b.Error(err)
				break
			}
		case <-b.quit:
			return

		case msg := <-b.lookup:
			if keyTree == nil {
				continue
			}
			kI, err := jee.Eval(keyTree, msg)
			if err != nil {
				b.Error(err)
				continue
			}
			k, ok := kI.(string)
			if !ok {
				b.Error(err)
				continue
			}
			out, err := extractAndUpdate(k, cache, ttlQueue)
			if err != nil {
				b.Error(err)
				continue
			}
			b.out <- out
		case q := <-b.querylookup:
			k, ok := q.Params["key"]
			if !ok {
				b.Error(errors.New("Must specify a key to lookup"))
			}
			for _, ki := range k {
				out, err := extractAndUpdate(ki, cache, ttlQueue)
				if err != nil {
					b.Error(err)
					continue
				}
				q.RespChan <- out
			}

		case responseChan := <-b.keys:
			keys := make([]string, len(cache))
			i := 0
			for key := range cache {
				keys[i] = key
				i++
			}

			responseChan <- map[string]interface{}{
				"keys": keys,
			}

		case responseChan := <-b.values:
			values := make([]interface{}, len(cache))
			i := 0
			for _, item := range cache {
				values[i] = item
				i++
			}
			responseChan <- map[string]interface{}{
				"values": values,
			}

		case responseChan := <-b.dump:
			responseChan <- map[string]interface{}{
				"dump": cache,
			}

		case msg := <-b.in:
			if keyTree == nil {
				continue
			}
			if valueTree == nil {
				continue
			}
			kI, err := jee.Eval(keyTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			k, ok := kI.(string)
			if !ok {
				b.Error(errors.New("key must be a string"))
				continue
			}
			v, err := jee.Eval(valueTree, msg)
			if err != nil {
				b.Error(err)
				break
			}
			now := time.Now()
			cache[k] = item{
				value:    v,
				lastSeen: now,
			}

			queueMessage := &PQMessage{
				val: k,
				t:   now,
			}
			heap.Push(ttlQueue, queueMessage)
		case responseChan := <-b.queryrule:
			// deal with a query request
			responseChan <- map[string]interface{}{
				"KeyPath":    keyPath,
				"ValuePath":  valuePath,
				"TimeToLive": ttlString,
			}
		}
		now := time.Now()
		for {
			itemI, diff := ttlQueue.PeekAndShift(now, ttl)
			if itemI == nil {
				// then the queue is empty. don't check again for 5s
				if diff == 0 {
					diff = time.Duration(500) * time.Millisecond
				}
				emitTick.Reset(diff)
				break
			}
			i := itemI.(*PQMessage)
			k := i.val.(string)
			if i.t.Equal(cache[k].lastSeen) {
				delete(cache, k)
			}
		}
	}
}
Beispiel #9
0
func (b *FFT) Run() {

	var err error
	var path string
	var tree *jee.TokenTree

	for {
		select {
		case ruleI := <-b.inrule:
			rule, ok := ruleI.(map[string]interface{})
			if !ok {
				b.Error(errors.New("could not assert rule to map"))
			}
			path, err = util.ParseString(rule, "Path")
			if err != nil {
				b.Error(err)
				continue
			}
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				continue
			}
		case <-b.quit:
			return
		case msg := <-b.in:
			if tree == nil {
				continue
			}
			vI, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				continue
			}
			v, ok := vI.([]interface{})
			if !ok {
				b.Error(errors.New("could not assert timeseries to an array"))
				continue
			}
			values := make([]tsDataPoint, len(v))
			for i, vi := range v {
				value, ok := vi.(map[string]interface{})
				if !ok {
					b.Error(errors.New("could not assert value to map"))
					continue
				}
				tI, ok := value["timestamp"]
				if !ok {
					b.Error(errors.New("could not find timestamp in value"))
					continue
				}
				t, ok := tI.(float64)
				if !ok {
					b.Error(errors.New("could not assert timestamp to float"))
					continue
				}
				yI, ok := value["value"]
				if !ok {
					b.Error(errors.New("could not assert timeseries value to float"))
					continue
				}
				y, ok := yI.(float64)
				values[i] = tsDataPoint{
					Timestamp: t,
					Value:     y,
				}
			}
			data := tsData{
				Values: values,
			}
			out := map[string]interface{}{
				"fft": buildFFT(data),
			}
			b.out <- out
		case respChan := <-b.queryrule:
			respChan <- map[string]interface{}{
				"Path": path,
			}
		}
	}
}
Beispiel #10
0
// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *Histogram) Run() {
	var tree *jee.TokenTree
	var path string
	waitTimer := time.NewTimer(100 * time.Millisecond)
	window := time.Duration(0)

	histogram := map[string]*PriorityQueue{}
	emptyByte := make([]byte, 0)
MainLoop:
	for {
		select {
		case ruleI := <-b.inrule:
			// window
			windowString, err := util.ParseString(ruleI, "Window")
			if err != nil {
				b.Error(err)
			}
			window, err = time.ParseDuration(windowString)
			if err != nil {
				b.Error(err)
			}
			path, err = util.ParseString(ruleI, "Path")
			tree, err = util.BuildTokenTree(path)
			if err != nil {
				b.Error(err)
				break
			}

		case <-b.quit:
			// quit the block
			return
		case msg := <-b.in:
			if tree == nil {
				continue
			}
			v, err := jee.Eval(tree, msg)
			if err != nil {
				b.Error(err)
				break
			}

			var valueString string

			switch v := v.(type) {
			default:
				b.Error(errors.New("unexpected value type"))
				continue MainLoop
			case string:
				valueString = v
			case int:
				valueString = strconv.Itoa(v)
			case bool:
				valueString = strconv.FormatBool(v)
			case float64:
				valueString = strconv.FormatFloat(v, 'g', -1, 64)
			}

			if pq, ok := histogram[valueString]; ok {
				queueMessage := &PQMessage{
					val: &emptyByte,
					t:   time.Now(),
				}
				heap.Push(pq, queueMessage)
			} else {
				pq := &PriorityQueue{}
				heap.Init(pq)
				histogram[valueString] = pq
				queueMessage := &PQMessage{
					val: &emptyByte,
					t:   time.Now(),
				}
				heap.Push(pq, queueMessage)
			}
		case <-waitTimer.C:

		case <-b.inpoll:
			// deal with a poll request
			data := buildHistogram(histogram)
			b.out <- data
		case MsgChan := <-b.queryrule:
			// deal with a query request
			out := map[string]interface{}{
				"Window": window.String(),
				"Path":   path,
			}
			MsgChan <- out
		case MsgChan := <-b.historule:
			data := buildHistogram(histogram)
			MsgChan <- data
		}
		for _, pq := range histogram {
			for {
				pqMsg, diff := pq.PeekAndShift(time.Now(), window)
				if pqMsg == nil {
					// either the queue is empty, or it's not time to emit
					if diff == 0 {
						// then the queue is empty. Pause for 5 seconds before checking again
						diff = time.Duration(500) * time.Millisecond
					}
					waitTimer.Reset(diff)
					break
				}
			}
		}
	}
}