github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/providers/octodns/octoyaml/js.go (about)

     1  package octoyaml
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  
     8  	"github.com/StackExchange/dnscontrol/models"
     9  	"github.com/StackExchange/dnscontrol/pkg/transform"
    10  
    11  	"github.com/robertkrimen/otto"
    12  	// load underscore js into vm by default
    13  
    14  	_ "github.com/robertkrimen/otto/underscore" // required by otto
    15  )
    16  
    17  // ExecuteJavascript accepts a javascript string and runs it, returning the resulting dnsConfig.
    18  func ExecuteJavascript(script string, devMode bool) (*models.DNSConfig, error) {
    19  	vm := otto.New()
    20  
    21  	vm.Set("require", require)
    22  	vm.Set("REV", reverse)
    23  
    24  	helperJs := GetHelpers(true)
    25  	// run helper script to prime vm and initialize variables
    26  	if _, err := vm.Run(helperJs); err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	// run user script
    31  	if _, err := vm.Run(script); err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	// export conf as string and unmarshal
    36  	value, err := vm.Run(`JSON.stringify(conf)`)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	str, err := value.ToString()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	conf := &models.DNSConfig{}
    45  	if err = json.Unmarshal([]byte(str), conf); err != nil {
    46  		return nil, err
    47  	}
    48  	return conf, nil
    49  }
    50  
    51  // GetHelpers returns the filename of helpers.js, or the esc'ed version.
    52  func GetHelpers(devMode bool) string {
    53  	d, err := ioutil.ReadFile("../pkg/js/helpers.js")
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	return string(d)
    58  }
    59  
    60  func require(call otto.FunctionCall) otto.Value {
    61  	if len(call.ArgumentList) != 1 {
    62  		throw(call.Otto, "require takes exactly one argument")
    63  	}
    64  	file := call.Argument(0).String()
    65  	fmt.Printf("requiring: %s\n", file)
    66  	data, err := ioutil.ReadFile(file)
    67  	if err != nil {
    68  		throw(call.Otto, err.Error())
    69  	}
    70  	_, err = call.Otto.Run(string(data))
    71  	if err != nil {
    72  		throw(call.Otto, err.Error())
    73  	}
    74  	return otto.TrueValue()
    75  }
    76  
    77  func throw(vm *otto.Otto, str string) {
    78  	panic(vm.MakeCustomError("Error", str))
    79  }
    80  
    81  func reverse(call otto.FunctionCall) otto.Value {
    82  	if len(call.ArgumentList) != 1 {
    83  		throw(call.Otto, "REV takes exactly one argument")
    84  	}
    85  	dom := call.Argument(0).String()
    86  	rev, err := transform.ReverseDomainName(dom)
    87  	if err != nil {
    88  		throw(call.Otto, err.Error())
    89  	}
    90  	v, _ := otto.ToValue(rev)
    91  	return v
    92  }