Example #1
0
func convertValToMap(v *otto.Value) map[string]interface{} {
	if v.IsDefined() && v.IsObject() {
		options, _ := v.Export()
		return options.(map[string]interface{})
	}
	return make(map[string]interface{})
}
// find the node from the based ont the hash passed in
// the hash needs to at least have a {name: }property
func (js *JavascriptBuilder) findNode(token string, in otto.Value) (n Node, err error) {
	var (
		givenOptions map[string]interface{}
		ok           bool
		name         string
	)

	e, err := in.Export()
	if err != nil {
		return n, err
	}

	// accept both a json hash and a string as an argument.
	// if the arg is a hash, then we should extract the name,
	// and pull the node from the yaml, and then merge the given options
	// over top of the options presented in the config node.
	//
	// if the arg is a string, then use that string as the name
	// and pull the config node
	switch arg := e.(type) {
	case map[string]interface{}:
		givenOptions = arg
		if name, ok = givenOptions["name"].(string); ok {
			// merge the two maps
			tmpMap := make(map[string]interface{})
			for k, v := range js.config.Nodes[name] {
				tmpMap[k] = v
			}
			for k, v := range givenOptions {
				tmpMap[k] = v
			}
			givenOptions = tmpMap
		} else { // we don't have a name, so lets generate one.
			u, err := uuid.NewV4()
			if err != nil {
				return n, fmt.Errorf("%s error. unable to create uuid (%s)", token, err.Error())
			}
			name = u.String()
			givenOptions["name"] = name
		}
	case string:
		name = arg
		givenOptions, ok = js.config.Nodes[name]
		if !ok {
			return n, fmt.Errorf("%s error. unable to find node '%s'", token, name)
		}
	}

	if token == "transform" {
		// this is a little bit of magic so that transformers (which are added by the transform fn get the right kind)
		givenOptions["type"] = "transformer"
	}

	kind, ok := givenOptions["type"].(string)
	if !ok {
		return n, fmt.Errorf("%s: hash requires a type field, but no type given", token)
	}

	return NewNode(name, kind, givenOptions)
}
Example #3
0
//GetBool gets bool from otto value
func GetBool(value otto.Value) (bool, error) {
	rawBool, _ := value.Export()
	result, ok := rawBool.(bool)
	if !ok {
		return false, fmt.Errorf(wrongArgumentType, rawBool, "bool")
	}
	return result, nil
}
Example #4
0
//GetTransaction gets Transaction from otto value
func GetTransaction(value otto.Value) (transaction.Transaction, error) {
	rawTransaction, _ := value.Export()
	result, ok := rawTransaction.(transaction.Transaction)
	if !ok {
		return nil, fmt.Errorf(wrongArgumentType, rawTransaction, "Transaction")
	}
	return result, nil
}
Example #5
0
//GetAuthorization gets Transaction from otto value
func GetAuthorization(value otto.Value) (schema.Authorization, error) {
	rawAuthorization, _ := value.Export()
	result, ok := rawAuthorization.(schema.Authorization)
	if !ok {
		return nil, fmt.Errorf(wrongArgumentType, rawAuthorization, "Authorization")
	}
	return result, nil
}
Example #6
0
//GetString gets string from otto value
func GetString(value otto.Value) (string, error) {
	rawString, _ := value.Export()
	result, ok := rawString.(string)
	if !ok {
		return "", fmt.Errorf(wrongArgumentType, rawString, "string")
	}
	return result, nil
}
Example #7
0
//GetStringList gets []string  from otto value
func GetStringList(value otto.Value) ([]string, error) {
	rawSlice, _ := value.Export()
	rawResult, ok := rawSlice.([]string)
	if !ok {
		return make([]string, 0), fmt.Errorf(wrongArgumentType, rawSlice, "array of strings")
	}
	return rawResult, nil
}
Example #8
0
func (f *JSFilter) Filter(ev *message.Event) (*message.Event, error) {
	var dropped bool
	f.vm.Set("$", map[string]interface{}{
		"env": f.conf.Env,
		"event": map[string]interface{}{
			"tag":    ev.Tag,
			"time":   ev.Time,
			"record": ev.Record,
		},
		"drop": func(call otto.FunctionCall) otto.Value {
			dropped = true
			return otto.Value{}
		},
		"emit": func(call otto.FunctionCall) (ret otto.Value) {
			var record otto.Value
			var t time.Time
			tag := call.Argument(0).String()
			if !call.Argument(2).IsDefined() {
				record = call.Argument(1)
				t = time.Now()
			} else {
				record = call.Argument(2)
				v, err := call.Argument(1).Export()
				if err != nil {
					f.env.Log.Warningf("Failed to get time: %v", err)
					return
				}
				var ok bool
				t, ok = v.(time.Time)
				if !ok {
					f.env.Log.Warningf("Failed to get time: unsupported type %T", v)
					return
				}
			}
			rec, err := record.Export()
			if err != nil {
				f.env.Log.Warningf("Failed to get record: %v", err)
				return
			}
			typedRec, ok := rec.(map[string]interface{})
			if !ok {
				f.env.Log.Warningf("Failed to get record: Unsupported type %T", rec)
				return
			}
			f.env.Emit(message.NewEventWithTime(tag, t, typedRec))
			return
		},
	})
	_, err := f.vm.Run(f.script)
	if err != nil {
		return nil, err
	} else if dropped {
		return nil, nil
	}
	return ev, nil
}
Example #9
0
//GetMap gets map[string]interface{} from otto value
func GetMap(value otto.Value) (map[string]interface{}, error) {
	rawMap, _ := value.Export()
	result, ok := rawMap.(map[string]interface{})
	if !ok {
		return map[string]interface{}{}, fmt.Errorf(wrongArgumentType, rawMap, "Object")
	}
	for key, value := range result {
		result[key] = ConvertOttoToGo(value)
	}
	return result, nil
}
Example #10
0
// Converts a JS string or array into a Go string array.
func ottoValueToStringArray(value otto.Value) []string {
	nativeValue, _ := value.Export()

	result := base.ValueToStringArray(nativeValue)

	if result == nil && !value.IsNull() && !value.IsUndefined() {
		base.Warn("SyncRunner: Non-string, non-array passed to JS callback: %s", value)
	}

	return result
}
Example #11
0
//GetList gets []interface{} from otto value
func GetList(value otto.Value) ([]interface{}, error) {
	rawSlice, err := value.Export()
	result := make([]interface{}, 0)
	if rawSlice == nil || err != nil {
		return result, err
	}
	typeOfSlice := reflect.TypeOf(rawSlice)
	if typeOfSlice.Kind() != reflect.Array && typeOfSlice.Kind() != reflect.Slice {
		return result, fmt.Errorf(wrongArgumentType, value, "array")
	}
	list := reflect.ValueOf(rawSlice)
	for i := 0; i < list.Len(); i++ {
		result = append(result, ConvertOttoToGo(list.Index(i).Interface()))
	}

	return result, err
}
func ottoValueToStringArray(value otto.Value) []string {
	{
		value, _ := value.Export()
		switch value := value.(type) {
		case string:
			return []string{value}
		case []interface{}:
			result := make([]string, 0, len(value))
			for _, item := range value {
				if value, ok := item.(string); ok {
					result = append(result, value)
				}
			}
			return result
		}
	}
	return nil
}
Example #13
0
func objToHeader(data *otto.Value, header http.Header) {
	dataMap, _ := data.Export()
	for key, val := range dataMap.(map[string]interface{}) {
		switch val.(type) {
		case string:
			{
				header.Add(key, val.(string))
				break
			}
		case []interface{}:
			{
				for _, headerVal := range val.([]interface{}) {
					header.Add(key, headerVal.(string))
				}
				break
			}
		}
	}
}
Example #14
0
func buildIteratorFromValue(val otto.Value, ts graph.TripleStore) graph.Iterator {
	if val.IsNull() || val.IsUndefined() {
		return ts.GetNodesAllIterator()
	}
	if val.IsPrimitive() {
		thing, _ := val.Export()
		switch v := thing.(type) {
		case string:
			it := ts.MakeFixed()
			it.AddValue(ts.GetIdFor(v))
			return it
		default:
			glog.Errorln("Trying to build unknown primitive value.")
		}
	}
	switch val.Class() {
	case "Object":
		return buildIteratorTree(val.Object(), ts)
	case "Array":
		// Had better be an array of strings
		strings := makeListOfStringsFromArrayValue(val.Object())
		it := ts.MakeFixed()
		for _, x := range strings {
			it.AddValue(ts.GetIdFor(x))
		}
		return it
	case "Number":
		fallthrough
	case "Boolean":
		fallthrough
	case "Date":
		fallthrough
	case "String":
		it := ts.MakeFixed()
		str, _ := val.ToString()
		it.AddValue(ts.GetIdFor(str))
		return it
	default:
		glog.Errorln("Trying to handle unsupported Javascript value.")
		return graph.NewNullIterator()
	}
}
Example #15
0
//GetStringList gets []string  from otto value
func GetStringList(value otto.Value) ([]string, error) {
	var ok bool
	var rawSlice []interface{}
	var stringSlice []string

	rawData, _ := value.Export()
	rawSlice, ok = rawData.([]interface{})

	if ok && len(rawSlice) == 0 {
		return []string{}, nil
	}

	stringSlice, ok = rawData.([]string)

	if !ok {
		return make([]string, 0), fmt.Errorf(wrongArgumentType, rawData, "array of strings")
	}

	return stringSlice, nil
}
// Converts a JS array into a Go string array.
func ottoArrayToStrings(array otto.Value) []string {
	goValue, err := array.Export()
	if err != nil {
		return nil
	}
	if result, ok := goValue.([]string); ok {
		return result
	}
	goArray, ok := goValue.([]interface{})
	if !ok || len(goArray) == 0 {
		return nil
	}
	result := make([]string, 0, len(goArray))
	for _, item := range goArray {
		if str, ok := item.(string); ok {
			result = append(result, str)
		}
	}
	return result
}
Example #17
0
func buildIteratorFromValue(val otto.Value, qs graph.QuadStore) graph.Iterator {
	if val.IsNull() || val.IsUndefined() {
		return qs.NodesAllIterator()
	}
	if val.IsPrimitive() {
		thing, _ := val.Export()
		switch v := thing.(type) {
		case string:
			it := qs.FixedIterator()
			it.Add(qs.ValueOf(v))
			return it
		default:
			glog.Errorln("Trying to build unknown primitive value.")
		}
	}
	switch val.Class() {
	case "Object":
		return buildIteratorTree(val.Object(), qs)
	case "Array":
		// Had better be an array of strings
		strings := stringsFrom(val.Object())
		it := qs.FixedIterator()
		for _, x := range strings {
			it.Add(qs.ValueOf(x))
		}
		return it
	case "Number":
		fallthrough
	case "Boolean":
		fallthrough
	case "Date":
		fallthrough
	case "String":
		it := qs.FixedIterator()
		it.Add(qs.ValueOf(val.String()))
		return it
	default:
		glog.Errorln("Trying to handle unsupported Javascript value.")
		return iterator.NewNull()
	}
}
Example #18
0
// Converts a JS string or array into a Go string array.
func ottoValueToStringArray(value otto.Value) []string {
	nativeValue, _ := value.Export()
	switch nativeValue := nativeValue.(type) {
	case string:
		return []string{nativeValue}
	case []string:
		return nativeValue
	case []interface{}:
		result := make([]string, 0, len(nativeValue))
		for _, item := range nativeValue {
			if str, ok := item.(string); ok {
				result = append(result, str)
			}
		}
		return result
	default:
		if !value.IsNull() && !value.IsUndefined() {
			base.Warn("SyncRunner: Non-string, non-array passed to JS callback: %s", value)
		}
		return nil
	}
}
Example #19
0
func buildPathFromValue(val otto.Value) (out []interface{}) {
	if val.IsNull() || val.IsUndefined() {
		return nil
	}
	if val.IsPrimitive() {
		thing, _ := val.Export()
		switch v := thing.(type) {
		case string:
			out = append(out, v)
			return
		default:
			clog.Errorf("Trying to build unknown primitive value.")
		}
	}
	switch val.Class() {
	case "Object":
		out = append(out, buildPathFromObject(val.Object()))
		return
	case "Array":
		// Had better be an array of strings
		for _, x := range stringsFrom(val.Object()) {
			out = append(out, x)
		}
		return
	case "Number":
		fallthrough
	case "Boolean":
		fallthrough
	case "Date":
		fallthrough
	case "String":
		out = append(out, val.String())
		return
	default:
		clog.Errorf("Trying to handle unsupported Javascript value.")
		return nil
	}
}
func (t *Transformer) transformOne(msg *message.Msg) (*message.Msg, error) {

	var (
		doc    interface{}
		value  otto.Value
		outDoc otto.Value
		result interface{}
		err    error
	)

	// short circuit for deletes and commands
	if msg.Op == message.Command {
		return msg, nil
	}

	now := time.Now().Nanosecond()
	fullDoc := map[string]interface{}{
		"data": msg.Data,
		"ts":   msg.Timestamp,
		"op":   msg.Op.String(),
	}
	if msg.IsMap() {
		if doc, err = mejson.Marshal(msg.Data); err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		fullDoc["data"] = doc
	}

	if value, err = t.vm.ToValue(fullDoc); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	// now that we have finished casting our map to a bunch of different types,
	// lets run our transformer on the document
	beforeVM := time.Now().Nanosecond()
	if outDoc, err = t.vm.Call(`module.exports`, nil, value); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	if result, err = outDoc.Export(); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	afterVM := time.Now().Nanosecond()

	fullDoc, ok := result.(map[string]interface{})
	if !ok {
		t.pipe.Err <- t.transformerError(ERROR, fmt.Errorf("returned doc was not a map[string]interface{}"), msg)
		return msg, fmt.Errorf("returned doc was not a map[string]interface{}")
	}

	msg.Op = message.OpTypeFromString(fullDoc["op"].(string))
	msg.Timestamp = fullDoc["ts"].(int64)
	switch data := fullDoc["data"].(type) {
	case otto.Value:
		exported, err := data.Export()
		if err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		d, err := mejson.Unmarshal(exported.(map[string]interface{}))
		if err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		msg.Data = map[string]interface{}(d)
	case map[string]interface{}:
		d, err := mejson.Unmarshal(data)
		if err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		msg.Data = map[string]interface{}(d)
	default:
		msg.Data = data
	}

	if t.debug {
		then := time.Now().Nanosecond()
		fmt.Printf("document transformed in %dus.  %d to marshal, %d in the vm, %d to unmarshal\n", (then-now)/1000, (beforeVM-now)/1000, (afterVM-beforeVM)/1000, (then-afterVM)/1000)
	}

	return msg, nil
}
Example #21
0
func (R *RuleEngine) Execute(fact *Fact, extf func(*Fact)) {
	R.Otto.Set("LOG", func(call otto.FunctionCall) otto.Value {
		log.Println(call.Argument(0).ToString())
		return otto.UndefinedValue()
	})
	complete := false
	(*fact)["result"] = true
	session := copyFact(*fact)
	lastSession := copyFact(*fact)
	index := 0
	RESTART := func() {
		index = 0
	}
	NEXT := func() {
		if R.IgnoreFactChanges || lastSession.equals(session) {
			index += 1
		} else {
			lastSession = copyFact(*session)
			RESTART()
		}
	}
	STOP := func() {
		complete = true
		RESTART()
	}
	WHEN := func(ruleIndex int, outcome bool) {
		if outcome {
			if val, ok := R.ActiveRules[ruleIndex]["consequence"]; ok {
				if _consequence, ok := val.(string); ok {
					var err error
					if err = R.Otto.Set("RESTART", func(call otto.FunctionCall) otto.Value {
						RESTART()
						return otto.UndefinedValue()
					}); err != nil {
						log.Fatal(err.Error())
					}
					if err = R.Otto.Set("STOP", func(call otto.FunctionCall) otto.Value {
						STOP()
						return otto.UndefinedValue()
					}); err != nil {
						log.Fatal(err.Error())
					}
					if err = R.Otto.Set("NEXT", func(call otto.FunctionCall) otto.Value {
						NEXT()
						return otto.UndefinedValue()
					}); err != nil {
						log.Fatal(err.Error())
					}
					if _, err := R.Otto.Run(fmt.Sprintf("var F = %v;", toJSON(session))); err != nil {
						log.Fatal(err.Error())
					}
					if _, err = R.Otto.Run(_consequence); err != nil {
						log.Fatal(err.Error())
					}
					var (
						oval otto.Value
						ival interface{}
						fval map[string]interface{}
						f    Fact
					)
					if oval, err = R.Otto.Get("F"); err != nil {
						log.Fatal(err.Error())
					}
					if ival, err = oval.Export(); err != nil {
						log.Fatal(err.Error())
					}
					if fval, ok = ival.(map[string]interface{}); !ok {
						log.Fatal("WHEN: F is not a Fact")
					}
					f = Fact(fval)
					session = &f
				} else {
					log.Fatal("WHEN: consequence not a string")
				}
			} else {
				log.Fatal("WHEN: rule has no field 'consequence'")
			}
		} else {
			NEXT()
		}
	}
	for index < len(R.ActiveRules) {
		if complete {
			break
		}
		if value, ok := R.ActiveRules[index]["condition"]; ok {
			if _condition, ok := value.(string); ok {
				var err error
				when := func(call otto.FunctionCall) otto.Value {
					if len(call.ArgumentList) == 1 && call.Argument(0).IsBoolean() {
						var b bool
						if b, err = call.Argument(0).ToBoolean(); err != nil {
							log.Fatal(err.Error())
						} else {
							WHEN(index, b)
						}
					} else {
						log.Fatal("Execute: WHEN called with wrong argument(s)")
					}
					return otto.UndefinedValue()
				}
				if err := R.Otto.Set("WHEN", when); err != nil {
					log.Fatal(err.Error())
				}
				if _, err = R.Otto.Run(fmt.Sprintf("var F = %v;", toJSON(session))); err != nil {
					log.Fatal(err.Error())
				}
				if _, err = R.Otto.Run(_condition); err != nil {
					log.Fatal(err.Error())
				}
				var (
					oval otto.Value
					ival interface{}
					fval map[string]interface{}
					f    Fact
				)
				if oval, err = R.Otto.Get("F"); err != nil {
					log.Fatal(err.Error())
				}
				if ival, err = oval.Export(); err != nil {
					log.Fatal(err.Error())
				}
				if fval, ok = ival.(map[string]interface{}); !ok {
					log.Fatal("Execute: F is not a Fact")
				}
				f = Fact(fval)
				session = &f
			} else {
				log.Fatal("Execute: condition not a string")
			}
		} else {
			log.Fatal("Execute: rule has no field 'condition'")
		}
	}
	extf(session)
}
Example #22
0
func (t *Transformer) transformOne(msg *message.Msg) (*message.Msg, error) {

	var (
		doc    interface{}
		value  otto.Value
		outDoc otto.Value
		result interface{}
		err    error
	)

	// short circuit for deletes and commands
	if msg.Op == message.Command {
		return msg, nil
	}

	now := time.Now().Nanosecond()
	currMsg := map[string]interface{}{
		"data": msg.Data,
		"ts":   msg.Timestamp,
		"op":   msg.Op.String(),
		"ns":   msg.Namespace,
	}
	if msg.IsMap() {
		if doc, err = mejson.Marshal(msg.Data); err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		currMsg["data"] = doc
	}

	if value, err = t.vm.ToValue(currMsg); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	// now that we have finished casting our map to a bunch of different types,
	// lets run our transformer on the document
	beforeVM := time.Now().Nanosecond()
	if outDoc, err = t.vm.Call(`module.exports`, nil, value); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	if result, err = outDoc.Export(); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	afterVM := time.Now().Nanosecond()

	if err = t.toMsg(result, msg); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, err
	}

	if t.debug {
		then := time.Now().Nanosecond()
		fmt.Printf("document transformed in %dus.  %d to marshal, %d in the vm, %d to unmarshal\n", (then-now)/1000, (beforeVM-now)/1000, (afterVM-beforeVM)/1000, (then-afterVM)/1000)
	}

	return msg, nil
}
Example #23
0
func (t *Transformer) transformOne(msg *message.Msg) (*message.Msg, error) {

	var (
		doc    interface{}
		value  otto.Value
		outDoc otto.Value
		result interface{}
		err    error
	)

	// short circuit for deletes and commands
	if msg.Op == message.Delete || msg.Op == message.Command {
		return msg, nil
	}

	now := time.Now().Nanosecond()
	if msg.IsMap() {
		if doc, err = mejson.Marshal(msg.Data); err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
	} else {
		doc = msg.Data
	}

	if value, err = t.vm.ToValue(doc); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	// now that we have finished casting our map to a bunch of different types,
	// lets run our transformer on the document
	beforeVM := time.Now().Nanosecond()
	if outDoc, err = t.vm.Call(`module.exports`, nil, value); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	if result, err = outDoc.Export(); err != nil {
		t.pipe.Err <- t.transformerError(ERROR, err, msg)
		return msg, nil
	}

	afterVM := time.Now().Nanosecond()

	switch r := result.(type) {
	case map[string]interface{}:
		doc, err := mejson.Unmarshal(r)
		if err != nil {
			t.pipe.Err <- t.transformerError(ERROR, err, msg)
			return msg, nil
		}
		msg.Data = map[string]interface{}(doc)
	default:
		msg.Data = r
	}

	if t.debug {
		then := time.Now().Nanosecond()
		fmt.Printf("document transformed in %dus.  %d to marshal, %d in the vm, %d to unmarshal\n", (then-now)/1000, (beforeVM-now)/1000, (afterVM-beforeVM)/1000, (then-afterVM)/1000)
	}

	return msg, nil
}