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

package gremlin

import (
	"errors"
	"fmt"
	"sort"
	"time"

	"github.com/robertkrimen/otto"
	// Provide underscore JS library.
	_ "github.com/robertkrimen/otto/underscore"

	"github.com/cayleygraph/cayley/clog"
	"github.com/cayleygraph/cayley/graph"
	"github.com/cayleygraph/cayley/query"
)

var ErrKillTimeout = errors.New("query timed out")

type Session struct {
	qs graph.QuadStore

	wk      *worker
	script  *otto.Script
	persist *otto.Otto

	timeout time.Duration
	kill    chan struct{}

	debug      bool
	dataOutput []interface{}

	err error
}

func NewSession(qs graph.QuadStore, timeout time.Duration, persist bool) *Session {
	g := Session{
		qs:      qs,
		wk:      newWorker(qs),
		timeout: timeout,
	}
	if persist {
		g.persist = g.wk.env
	}
	return &g
}

type Result struct {
	metaresult    bool
	err           error
	val           interface{}
	actualResults map[string]graph.Value
}

func (s *Session) Debug(ok bool) {
	s.debug = ok
}

func (s *Session) ShapeOf(query string) (interface{}, error) {
	// TODO(kortschak) It would be nice to be able
	// to return an error for bad queries here.
	s.wk.shape = make(map[string]interface{})
	s.wk.env.Run(query)
	out := s.wk.shape
	s.wk.shape = nil
	return out, nil
}

func (s *Session) Parse(input string) (query.ParseResult, error) {
	script, err := s.wk.env.Compile("", input)
	if err != nil {
		return query.ParseFail, err
	}
	s.script = script
	return query.Parsed, nil
}

func (s *Session) runUnsafe(input interface{}) (_ otto.Value, gerr error) {
	wk := s.wk
	defer func() {
		if r := recover(); r != nil {
			if r == ErrKillTimeout {
				s.err = ErrKillTimeout
				wk.env = s.persist
				return
			} else if err, ok := r.(error); ok {
				gerr = err
			} else {
				gerr = fmt.Errorf("recovered: %v", err)
			}
		}
	}()

	// Use buffered chan to prevent blocking.
	wk.env.Interrupt = make(chan func(), 1)
	s.kill = make(chan struct{})
	wk.kill = s.kill

	done := make(chan struct{})
	defer close(done)
	if s.timeout >= 0 {
		go func() {
			time.Sleep(s.timeout)
			select {
			case <-done:
			default:
				close(s.kill)
				wk.Lock()
				if wk.env != nil {
					wk.env.Interrupt <- func() {
						panic(ErrKillTimeout)
					}
				}
				wk.Unlock()
			}
		}()
	}

	wk.Lock()
	env := wk.env
	wk.Unlock()
	return env.Run(input)
}

func (s *Session) Execute(input string, out chan interface{}, _ int) {
	defer close(out)
	s.err = nil
	s.wk.results = out
	var err error
	var value otto.Value
	if s.script == nil {
		value, err = s.runUnsafe(input)
	} else {
		value, err = s.runUnsafe(s.script)
	}
	out <- &Result{
		metaresult: true,
		err:        err,
		val:        exportArgs([]otto.Value{value})[0],
	}
	s.wk.results = nil
	s.script = nil
	s.wk.Lock()
	s.wk.env = s.persist
	s.wk.Unlock()
}

func (s *Session) Format(result interface{}) string {
	data, ok := result.(*Result)
	if !ok {
		return fmt.Sprintf("Error: unexpected result type: %T\n", result)
	}
	if data.metaresult {
		if data.err != nil {
			return fmt.Sprintf("Error: %v\n", data.err)
		}
		if data.val != nil {
			s := data.val
			switch s.(type) {
			case *pathObject, *graphObject:
				s = "[internal Iterator]"
			}
			return fmt.Sprintln("=>", s)
		}
		return fmt.Sprintln("=>", nil)
	}
	var out string
	out = fmt.Sprintln("****")
	if data.val == nil {
		tags := data.actualResults
		tagKeys := make([]string, len(tags))
		i := 0
		for k := range tags {
			tagKeys[i] = k
			i++
		}
		sort.Strings(tagKeys)
		for _, k := range tagKeys {
			if k == "$_" {
				continue
			}
			out += fmt.Sprintf("%s : %s\n", k, quadValueToString(s.qs.NameOf(tags[k])))
		}
	} else {
		switch export := data.val.(type) {
		case map[string]string:
			for k, v := range export {
				out += fmt.Sprintf("%s : %s\n", k, v)
			}
		case map[string]interface{}:
			for k, v := range export {
				out += fmt.Sprintf("%s : %v\n", k, v)
			}
		default:
			out += fmt.Sprintf("%s\n", data.val)
		}
	}
	return out
}

// Web stuff
func (s *Session) Collate(result interface{}) {
	data, ok := result.(*Result)
	if !ok {
		clog.Errorf("unexpected result type: %T", result)
		return
	}
	if !data.metaresult {
		if data.val == nil {
			obj := make(map[string]interface{})
			tags := data.actualResults
			var tagKeys []string
			for k := range tags {
				tagKeys = append(tagKeys, k)
			}
			sort.Strings(tagKeys)
			for _, k := range tagKeys {
				if name := s.qs.NameOf(tags[k]); name != nil {
					obj[k] = quadValueToNative(name)
				} else {
					delete(obj, k)
				}
			}
			if len(obj) != 0 {
				s.dataOutput = append(s.dataOutput, obj)
			}
		} else {
			s.dataOutput = append(s.dataOutput, data.val)
		}
	}
}

func (s *Session) Results() (interface{}, error) {
	defer s.Clear()
	if s.err != nil {
		return nil, s.err
	}
	select {
	case <-s.kill:
		return nil, ErrKillTimeout
	default:
		return s.dataOutput, nil
	}
}

func (s *Session) Clear() {
	s.dataOutput = nil
}
<commit_msg>gremlin: don't require a session to last as long as the timeout<commit_after>// Copyright 2014 The Cayley Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gremlin

import (
	"errors"
	"fmt"
	"sort"
	"time"

	"github.com/robertkrimen/otto"
	// Provide underscore JS library.
	_ "github.com/robertkrimen/otto/underscore"

	"github.com/cayleygraph/cayley/clog"
	"github.com/cayleygraph/cayley/graph"
	"github.com/cayleygraph/cayley/query"
)

var ErrKillTimeout = errors.New("query timed out")

type Session struct {
	qs graph.QuadStore

	wk      *worker
	script  *otto.Script
	persist *otto.Otto

	timeout time.Duration
	kill    chan struct{}

	debug      bool
	dataOutput []interface{}

	err error
}

func NewSession(qs graph.QuadStore, timeout time.Duration, persist bool) *Session {
	g := Session{
		qs:      qs,
		wk:      newWorker(qs),
		timeout: timeout,
	}
	if persist {
		g.persist = g.wk.env
	}
	return &g
}

type Result struct {
	metaresult    bool
	err           error
	val           interface{}
	actualResults map[string]graph.Value
}

func (s *Session) Debug(ok bool) {
	s.debug = ok
}

func (s *Session) ShapeOf(query string) (interface{}, error) {
	// TODO(kortschak) It would be nice to be able
	// to return an error for bad queries here.
	s.wk.shape = make(map[string]interface{})
	s.wk.env.Run(query)
	out := s.wk.shape
	s.wk.shape = nil
	return out, nil
}

func (s *Session) Parse(input string) (query.ParseResult, error) {
	script, err := s.wk.env.Compile("", input)
	if err != nil {
		return query.ParseFail, err
	}
	s.script = script
	return query.Parsed, nil
}

func (s *Session) runUnsafe(input interface{}) (_ otto.Value, gerr error) {
	wk := s.wk
	defer func() {
		if r := recover(); r != nil {
			if r == ErrKillTimeout {
				s.err = ErrKillTimeout
				wk.env = s.persist
				return
			} else if err, ok := r.(error); ok {
				gerr = err
			} else {
				gerr = fmt.Errorf("recovered: %v", err)
			}
		}
	}()

	// Use buffered chan to prevent blocking.
	wk.env.Interrupt = make(chan func(), 1)
	s.kill = make(chan struct{})
	wk.kill = s.kill

	done := make(chan struct{})
	defer close(done)
	if s.timeout >= 0 {
		go func() {
			select {
			case <-done:
			case <-time.After(s.timeout):
				close(s.kill)
				wk.Lock()
				if wk.env != nil {
					wk.env.Interrupt <- func() {
						panic(ErrKillTimeout)
					}
				}
				wk.Unlock()
			}
		}()
	}

	wk.Lock()
	env := wk.env
	wk.Unlock()
	return env.Run(input)
}

func (s *Session) Execute(input string, out chan interface{}, _ int) {
	defer close(out)
	s.err = nil
	s.wk.results = out
	var err error
	var value otto.Value
	if s.script == nil {
		value, err = s.runUnsafe(input)
	} else {
		value, err = s.runUnsafe(s.script)
	}
	out <- &Result{
		metaresult: true,
		err:        err,
		val:        exportArgs([]otto.Value{value})[0],
	}
	s.wk.results = nil
	s.script = nil
	s.wk.Lock()
	s.wk.env = s.persist
	s.wk.Unlock()
}

func (s *Session) Format(result interface{}) string {
	data, ok := result.(*Result)
	if !ok {
		return fmt.Sprintf("Error: unexpected result type: %T\n", result)
	}
	if data.metaresult {
		if data.err != nil {
			return fmt.Sprintf("Error: %v\n", data.err)
		}
		if data.val != nil {
			s := data.val
			switch s.(type) {
			case *pathObject, *graphObject:
				s = "[internal Iterator]"
			}
			return fmt.Sprintln("=>", s)
		}
		return fmt.Sprintln("=>", nil)
	}
	var out string
	out = fmt.Sprintln("****")
	if data.val == nil {
		tags := data.actualResults
		tagKeys := make([]string, len(tags))
		i := 0
		for k := range tags {
			tagKeys[i] = k
			i++
		}
		sort.Strings(tagKeys)
		for _, k := range tagKeys {
			if k == "$_" {
				continue
			}
			out += fmt.Sprintf("%s : %s\n", k, quadValueToString(s.qs.NameOf(tags[k])))
		}
	} else {
		switch export := data.val.(type) {
		case map[string]string:
			for k, v := range export {
				out += fmt.Sprintf("%s : %s\n", k, v)
			}
		case map[string]interface{}:
			for k, v := range export {
				out += fmt.Sprintf("%s : %v\n", k, v)
			}
		default:
			out += fmt.Sprintf("%s\n", data.val)
		}
	}
	return out
}

// Web stuff
func (s *Session) Collate(result interface{}) {
	data, ok := result.(*Result)
	if !ok {
		clog.Errorf("unexpected result type: %T", result)
		return
	}
	if !data.metaresult {
		if data.val == nil {
			obj := make(map[string]interface{})
			tags := data.actualResults
			var tagKeys []string
			for k := range tags {
				tagKeys = append(tagKeys, k)
			}
			sort.Strings(tagKeys)
			for _, k := range tagKeys {
				if name := s.qs.NameOf(tags[k]); name != nil {
					obj[k] = quadValueToNative(name)
				} else {
					delete(obj, k)
				}
			}
			if len(obj) != 0 {
				s.dataOutput = append(s.dataOutput, obj)
			}
		} else {
			s.dataOutput = append(s.dataOutput, data.val)
		}
	}
}

func (s *Session) Results() (interface{}, error) {
	defer s.Clear()
	if s.err != nil {
		return nil, s.err
	}
	select {
	case <-s.kill:
		return nil, ErrKillTimeout
	default:
		return s.dataOutput, nil
	}
}

func (s *Session) Clear() {
	s.dataOutput = nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package fft

import (
	"math"
	"runtime"
	"testing"

	"github.com/mjibson/go-dsp/dsputils"
)

const (
	sqrt2_2 = math.Sqrt2 / 2
)

type fftTest struct {
	in  []float64
	out []complex128
}

var fftTests = []fftTest{
	// impulse responses
	{
		[]float64{1},
		[]complex128{complex(1, 0)},
	},
	{
		[]float64{1, 0},
		[]complex128{complex(1, 0), complex(1, 0)},
	},
	{
		[]float64{1, 0, 0, 0},
		[]complex128{complex(1, 0), complex(1, 0), complex(1, 0), complex(1, 0)},
	},
	{
		[]float64{1, 0, 0, 0, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0)},
	},

	// shifted impulse response
	{
		[]float64{0, 1},
		[]complex128{complex(1, 0), complex(-1, 0)},
	},
	{
		[]float64{0, 1, 0, 0},
		[]complex128{complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
	},
	{
		[]float64{0, 1, 0, 0, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(sqrt2_2, -sqrt2_2),
			complex(0, -1),
			complex(-sqrt2_2, -sqrt2_2),
			complex(-1, 0),
			complex(-sqrt2_2, sqrt2_2),
			complex(0, 1),
			complex(sqrt2_2, sqrt2_2)},
	},

	// other
	{
		[]float64{1, 2, 3, 4},
		[]complex128{
			complex(10, 0),
			complex(-2, 2),
			complex(-2, 0),
			complex(-2, -2)},
	},
	{
		[]float64{1, 3, 5, 7},
		[]complex128{
			complex(16, 0),
			complex(-4, 4),
			complex(-4, 0),
			complex(-4, -4)},
	},
	{
		[]float64{1, 2, 3, 4, 5, 6, 7, 8},
		[]complex128{
			complex(36, 0),
			complex(-4, 9.65685425),
			complex(-4, 4),
			complex(-4, 1.65685425),
			complex(-4, 0),
			complex(-4, -1.65685425),
			complex(-4, -4),
			complex(-4, -9.65685425)},
	},

	// non power of 2 lengths
	{
		[]float64{1, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0)},
	},
	{
		[]float64{1, 2, 3},
		[]complex128{
			complex(6, 0),
			complex(-1.5, 0.8660254),
			complex(-1.5, -0.8660254)},
	},
	{
		[]float64{1, 1, 1},
		[]complex128{
			complex(3, 0),
			complex(0, 0),
			complex(0, 0)},
	},
}

type fft2Test struct {
	in  [][]float64
	out [][]complex128
}

var fft2Tests = []fft2Test{
	{
		[][]float64{{1, 2, 3}, {3, 4, 5}},
		[][]complex128{
			{complex(18, 0), complex(-3, 1.73205081), complex(-3, -1.73205081)},
			{complex(-6, 0), complex(0, 0), complex(0, 0)}},
	},
	{
		[][]float64{{0.1, 0.2, 0.3, 0.4, 0.5}, {1, 2, 3, 4, 5}, {3, 2, 1, 0, -1}},
		[][]complex128{
			{complex(21.5, 0), complex(-0.25, 0.34409548), complex(-0.25, 0.08122992), complex(-0.25, -0.08122992), complex(-0.25, -0.34409548)},
			{complex(-8.5, -8.66025404), complex(5.70990854, 4.6742225), complex(1.15694356, 4.41135694), complex(-1.65694356, 4.24889709), complex(-6.20990854, 3.98603154)},
			{complex(-8.5, 8.66025404), complex(-6.20990854, -3.98603154), complex(-1.65694356, -4.24889709), complex(1.15694356, -4.41135694), complex(5.70990854, -4.6742225)}},
	},
}

type fftnTest struct {
	in  []float64
	dim []int
	out []complex128
}

var fftnTests = []fftnTest{
	{
		[]float64{4, 2, 3, 8, 5, 6, 7, 2, 13, 24, 13, 17},
		[]int{2, 2, 3},
		[]complex128{
			complex(104, 0), complex(12.5, 14.72243186), complex(12.5, -14.72243186),
			complex(-42, 0), complex(-10.5, 6.06217783), complex(-10.5, -6.06217783),

			complex(-48, 0), complex(-4.5, -11.25833025), complex(-4.5, 11.25833025),
			complex(22, 0), complex(8.5, -6.06217783), complex(8.5, 6.06217783)},
	},
}

type reverseBitsTest struct {
	in  uint
	sz  uint
	out uint
}

var reverseBitsTests = []reverseBitsTest{
	{0, 1, 0},
	{1, 2, 2},
	{1, 4, 8},
	{2, 4, 4},
	{3, 4, 12},
}

func TestFFT(t *testing.T) {
	for _, ft := range fftTests {
		v := FFTReal(ft.in)
		if !dsputils.PrettyCloseC(v, ft.out) {
			t.Error("FFT error\ninput:", ft.in, "\noutput:", v, "\nexpected:", ft.out)
		}

		vi := IFFT(ft.out)
		if !dsputils.PrettyCloseC(vi, dsputils.ToComplex(ft.in)) {
			t.Error("IFFT error\ninput:", ft.out, "\noutput:", vi, "\nexpected:", dsputils.ToComplex(ft.in))
		}
	}
}

func TestFFT2(t *testing.T) {
	for _, ft := range fft2Tests {
		v := FFT2Real(ft.in)
		if !dsputils.PrettyClose2(v, ft.out) {
			t.Error("FFT2 error\ninput:", ft.in, "\noutput:", v, "\nexpected:", ft.out)
		}

		vi := IFFT2(ft.out)
		if !dsputils.PrettyClose2(vi, dsputils.ToComplex2(ft.in)) {
			t.Error("IFFT2 error\ninput:", ft.out, "\noutput:", vi, "\nexpected:", dsputils.ToComplex2(ft.in))
		}
	}
}

func TestFFTN(t *testing.T) {
	for _, ft := range fftnTests {
		m := dsputils.MakeMatrix(dsputils.ToComplex(ft.in), ft.dim)
		o := dsputils.MakeMatrix(ft.out, ft.dim)
		v := FFTN(m)
		if !v.PrettyClose(o) {
			t.Error("FFTN error\ninput:", m, "\noutput:", v, "\nexpected:", o)
		}

		vi := IFFTN(o)
		if !vi.PrettyClose(m) {
			t.Error("IFFTN error\ninput:", o, "\noutput:", vi, "\nexpected:", m)
		}
	}
}

func TestReverseBits(t *testing.T) {
	for _, rt := range reverseBitsTests {
		v := reverseBits(rt.in, rt.sz)

		if v != rt.out {
			t.Error("reverse bits error\ninput:", rt.in, "\nsize:", rt.sz, "\noutput:", v, "\nexpected:", rt.out)
		}
	}
}

func TestFFTMulti(t *testing.T) {
	N := 1 << 8
	a := make([]complex128, N)
	for i := 0; i < N; i++ {
		a[i] = complex(float64(i)/float64(N), 0)
	}

	FFT(a)
}

// run with: go test -test.bench="."
func BenchmarkFFT(b *testing.B) {
	b.StopTimer()

	runtime.GOMAXPROCS(runtime.NumCPU())

	N := 1 << 20
	a := make([]complex128, N)
	for i := 0; i < N; i++ {
		a[i] = complex(float64(i)/float64(N), 0)
	}

	EnsureRadix2Factors(N)

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		FFT(a)
	}
}
<commit_msg>Added example usage of FFTReal.<commit_after>/*
 * Copyright (c) 2011 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package fft

import (
	"fmt"
	"math"
	"math/cmplx"
	"runtime"
	"testing"

	"github.com/mjibson/go-dsp/dsputils"
)

const (
	sqrt2_2 = math.Sqrt2 / 2
)

type fftTest struct {
	in  []float64
	out []complex128
}

var fftTests = []fftTest{
	// impulse responses
	{
		[]float64{1},
		[]complex128{complex(1, 0)},
	},
	{
		[]float64{1, 0},
		[]complex128{complex(1, 0), complex(1, 0)},
	},
	{
		[]float64{1, 0, 0, 0},
		[]complex128{complex(1, 0), complex(1, 0), complex(1, 0), complex(1, 0)},
	},
	{
		[]float64{1, 0, 0, 0, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0)},
	},

	// shifted impulse response
	{
		[]float64{0, 1},
		[]complex128{complex(1, 0), complex(-1, 0)},
	},
	{
		[]float64{0, 1, 0, 0},
		[]complex128{complex(1, 0), complex(0, -1), complex(-1, 0), complex(0, 1)},
	},
	{
		[]float64{0, 1, 0, 0, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(sqrt2_2, -sqrt2_2),
			complex(0, -1),
			complex(-sqrt2_2, -sqrt2_2),
			complex(-1, 0),
			complex(-sqrt2_2, sqrt2_2),
			complex(0, 1),
			complex(sqrt2_2, sqrt2_2)},
	},

	// other
	{
		[]float64{1, 2, 3, 4},
		[]complex128{
			complex(10, 0),
			complex(-2, 2),
			complex(-2, 0),
			complex(-2, -2)},
	},
	{
		[]float64{1, 3, 5, 7},
		[]complex128{
			complex(16, 0),
			complex(-4, 4),
			complex(-4, 0),
			complex(-4, -4)},
	},
	{
		[]float64{1, 2, 3, 4, 5, 6, 7, 8},
		[]complex128{
			complex(36, 0),
			complex(-4, 9.65685425),
			complex(-4, 4),
			complex(-4, 1.65685425),
			complex(-4, 0),
			complex(-4, -1.65685425),
			complex(-4, -4),
			complex(-4, -9.65685425)},
	},

	// non power of 2 lengths
	{
		[]float64{1, 0, 0, 0, 0},
		[]complex128{
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0),
			complex(1, 0)},
	},
	{
		[]float64{1, 2, 3},
		[]complex128{
			complex(6, 0),
			complex(-1.5, 0.8660254),
			complex(-1.5, -0.8660254)},
	},
	{
		[]float64{1, 1, 1},
		[]complex128{
			complex(3, 0),
			complex(0, 0),
			complex(0, 0)},
	},
}

type fft2Test struct {
	in  [][]float64
	out [][]complex128
}

var fft2Tests = []fft2Test{
	{
		[][]float64{{1, 2, 3}, {3, 4, 5}},
		[][]complex128{
			{complex(18, 0), complex(-3, 1.73205081), complex(-3, -1.73205081)},
			{complex(-6, 0), complex(0, 0), complex(0, 0)}},
	},
	{
		[][]float64{{0.1, 0.2, 0.3, 0.4, 0.5}, {1, 2, 3, 4, 5}, {3, 2, 1, 0, -1}},
		[][]complex128{
			{complex(21.5, 0), complex(-0.25, 0.34409548), complex(-0.25, 0.08122992), complex(-0.25, -0.08122992), complex(-0.25, -0.34409548)},
			{complex(-8.5, -8.66025404), complex(5.70990854, 4.6742225), complex(1.15694356, 4.41135694), complex(-1.65694356, 4.24889709), complex(-6.20990854, 3.98603154)},
			{complex(-8.5, 8.66025404), complex(-6.20990854, -3.98603154), complex(-1.65694356, -4.24889709), complex(1.15694356, -4.41135694), complex(5.70990854, -4.6742225)}},
	},
}

type fftnTest struct {
	in  []float64
	dim []int
	out []complex128
}

var fftnTests = []fftnTest{
	{
		[]float64{4, 2, 3, 8, 5, 6, 7, 2, 13, 24, 13, 17},
		[]int{2, 2, 3},
		[]complex128{
			complex(104, 0), complex(12.5, 14.72243186), complex(12.5, -14.72243186),
			complex(-42, 0), complex(-10.5, 6.06217783), complex(-10.5, -6.06217783),

			complex(-48, 0), complex(-4.5, -11.25833025), complex(-4.5, 11.25833025),
			complex(22, 0), complex(8.5, -6.06217783), complex(8.5, 6.06217783)},
	},
}

type reverseBitsTest struct {
	in  uint
	sz  uint
	out uint
}

var reverseBitsTests = []reverseBitsTest{
	{0, 1, 0},
	{1, 2, 2},
	{1, 4, 8},
	{2, 4, 4},
	{3, 4, 12},
}

func TestFFT(t *testing.T) {
	for _, ft := range fftTests {
		v := FFTReal(ft.in)
		if !dsputils.PrettyCloseC(v, ft.out) {
			t.Error("FFT error\ninput:", ft.in, "\noutput:", v, "\nexpected:", ft.out)
		}

		vi := IFFT(ft.out)
		if !dsputils.PrettyCloseC(vi, dsputils.ToComplex(ft.in)) {
			t.Error("IFFT error\ninput:", ft.out, "\noutput:", vi, "\nexpected:", dsputils.ToComplex(ft.in))
		}
	}
}

func TestFFT2(t *testing.T) {
	for _, ft := range fft2Tests {
		v := FFT2Real(ft.in)
		if !dsputils.PrettyClose2(v, ft.out) {
			t.Error("FFT2 error\ninput:", ft.in, "\noutput:", v, "\nexpected:", ft.out)
		}

		vi := IFFT2(ft.out)
		if !dsputils.PrettyClose2(vi, dsputils.ToComplex2(ft.in)) {
			t.Error("IFFT2 error\ninput:", ft.out, "\noutput:", vi, "\nexpected:", dsputils.ToComplex2(ft.in))
		}
	}
}

func TestFFTN(t *testing.T) {
	for _, ft := range fftnTests {
		m := dsputils.MakeMatrix(dsputils.ToComplex(ft.in), ft.dim)
		o := dsputils.MakeMatrix(ft.out, ft.dim)
		v := FFTN(m)
		if !v.PrettyClose(o) {
			t.Error("FFTN error\ninput:", m, "\noutput:", v, "\nexpected:", o)
		}

		vi := IFFTN(o)
		if !vi.PrettyClose(m) {
			t.Error("IFFTN error\ninput:", o, "\noutput:", vi, "\nexpected:", m)
		}
	}
}

func TestReverseBits(t *testing.T) {
	for _, rt := range reverseBitsTests {
		v := reverseBits(rt.in, rt.sz)

		if v != rt.out {
			t.Error("reverse bits error\ninput:", rt.in, "\nsize:", rt.sz, "\noutput:", v, "\nexpected:", rt.out)
		}
	}
}

func TestFFTMulti(t *testing.T) {
	N := 1 << 8
	a := make([]complex128, N)
	for i := 0; i < N; i++ {
		a[i] = complex(float64(i)/float64(N), 0)
	}

	FFT(a)
}

// run with: go test -test.bench="."
func BenchmarkFFT(b *testing.B) {
	b.StopTimer()

	runtime.GOMAXPROCS(runtime.NumCPU())

	N := 1 << 20
	a := make([]complex128, N)
	for i := 0; i < N; i++ {
		a[i] = complex(float64(i)/float64(N), 0)
	}

	EnsureRadix2Factors(N)

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		FFT(a)
	}
}

// This example is adapted from Richard Lyon's "Understanding Digital Signal Processing," section 3.1.1.
func ExampleFFTReal() {
	numSamples := 8

	// Equation 3-10.
	x := func(n int) float64 {
		wave0 := math.Sin(2.0 * math.Pi * float64(n) / 8.0)
		wave1 := 0.5 * math.Sin(2*math.Pi*float64(n)/4.0+3.0*math.Pi/4.0)
		return wave0 + wave1
	}

	// Discretize our function by sampling at 8 points.
	a := make([]float64, numSamples)
	for i := 0; i < numSamples; i++ {
		a[i] = x(i)
	}

	X := FFTReal(a)

	// Print the magnitude and phase at each frequency.
	for i := 0; i < numSamples; i++ {
		r, θ := cmplx.Polar(X[i])
		θ *= 360.0 / (2 * math.Pi)
		if dsputils.Float64Equal(r, 0) {
			θ = 0 // (When the magnitude is close to 0, the angle is meaningless)
		}
		fmt.Printf("X(%d) = %.1f ∠ %.1f°\n", i, r, θ)
	}

	// Output:
	// X(0) = 0.0 ∠ 0.0°
	// X(1) = 4.0 ∠ -90.0°
	// X(2) = 2.0 ∠ 45.0°
	// X(3) = 0.0 ∠ 0.0°
	// X(4) = 0.0 ∠ 0.0°
	// X(5) = 0.0 ∠ 0.0°
	// X(6) = 2.0 ∠ -45.0°
	// X(7) = 4.0 ∠ 90.0°
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/creasty/gin-contrib/app_error"
	"github.com/creasty/gin-contrib/recovery"
	"github.com/gin-gonic/gin"

	"github.com/torinos-io/api/server/middleware"
	"github.com/torinos-io/api/server/route"
	system_route "github.com/torinos-io/api/server/route/system"
	hb_service "github.com/torinos-io/api/service/hb_service"
	"github.com/torinos-io/api/type/system"
)

func drawRoutes(r *gin.Engine, appContext *system.AppContext) {
	r.Use(recovery.WrapWithCallback(func(c *gin.Context, body []byte, err interface{}) {
		hb_service.NotifyGinError(err, body, c)
	}))
	r.Use(app_error.WrapWithCallback(func(c *gin.Context, body []byte, err error) {
		hb_service.NotifyGinError(err, body, c)
	}))
	r.Use(middleware.SetAppContextWrapper(appContext))

	{
		r.GET("/ping", route.Ping)
	}

	{
		r := r.Group("/system")
		r.Use(gin.BasicAuth(gin.Accounts{
			appContext.Config.BasicAuthUsername: appContext.Config.BasicAuthPassword,
		}))

		r.GET("/appinfo", system_route.GetAppInfo)
	}
}
<commit_msg>Create root handler<commit_after>package server

import (
	"github.com/creasty/gin-contrib/app_error"
	"github.com/creasty/gin-contrib/recovery"
	"github.com/gin-gonic/gin"

	"github.com/torinos-io/api/server/middleware"
	"github.com/torinos-io/api/server/route"
	system_route "github.com/torinos-io/api/server/route/system"
	hb_service "github.com/torinos-io/api/service/hb_service"
	"github.com/torinos-io/api/type/system"
)

func drawRoutes(r *gin.Engine, appContext *system.AppContext) {
	r.Use(recovery.WrapWithCallback(func(c *gin.Context, body []byte, err interface{}) {
		hb_service.NotifyGinError(err, body, c)
	}))
	r.Use(app_error.WrapWithCallback(func(c *gin.Context, body []byte, err error) {
		hb_service.NotifyGinError(err, body, c)
	}))
	r.Use(middleware.SetAppContextWrapper(appContext))

	{
		r.GET("/", route.Ping)
		r.GET("/ping", route.Ping)
	}

	{
		r := r.Group("/system")
		r.Use(gin.BasicAuth(gin.Accounts{
			appContext.Config.BasicAuthUsername: appContext.Config.BasicAuthPassword,
		}))

		r.GET("/appinfo", system_route.GetAppInfo)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package server

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/miekg/dns"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	prometheusPort      = os.Getenv("PROMETHEUS_PORT")
	prometheusPath      = os.Getenv("PROMETHEUS_PATH")
	prometheusNamespace = os.Getenv("PROMETHEUS_NAMESPACE")
	prometheusSubsystem = os.Getenv("PROMETHEUS_SUBSYSTEM")
)

var (
	promDnssecOkCount        prometheus.Counter
	promExternalRequestCount *prometheus.CounterVec
	promRequestCount         *prometheus.CounterVec
	promErrorCount           *prometheus.CounterVec
	promCacheSize            *prometheus.GaugeVec
	promCacheMiss            *prometheus.CounterVec
	promRequestDuration      *prometheus.HistogramVec
	promResponseSize         *prometheus.HistogramVec
)

func Metrics() {
	if prometheusPath == "" {
		prometheusPath = "/metrics"
	}
	if prometheusSubsystem == "" {
		prometheusSubsystem = "skydns"
	}

	promExternalRequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_external_count",
		Help:      "Counter of external DNS requests.",
	}, []string{"type"}) // recursive, stub, lookup
	prometheus.MustRegister(promExternalRequestCount)

	promRequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_count",
		Help:      "Counter of DNS requests made.",
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promRequestCount)

	promDnssecOkCount = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_dnssec_ok_count",
		Help:      "Counter of DNSSEC requests.",
	})
	prometheus.MustRegister(promDnssecOkCount) // Maybe more bits here?

	promErrorCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_error_count",
		Help:      "Counter of DNS requests resulting in an error.",
	}, []string{"error"}) // nxdomain, nodata, truncated, refused, overflow
	prometheus.MustRegister(promErrorCount)

	// Caches
	promCacheSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "cache_total_size",
		Help:      "The total size of all elements in the cache.",
	}, []string{"type"}) // response, signature
	prometheus.MustRegister(promCacheSize)

	promCacheMiss = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_cache_miss_count",
		Help:      "Counter of DNS requests that result in a cache miss.",
	}, []string{"type"}) // response, signature
	prometheus.MustRegister(promCacheMiss)

	promRequestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_duration",
		Help:      "Histogram of the time (in seconds) each request took to resolve.",
		Buckets:   append([]float64{0.001, 0.003}, prometheus.DefBuckets...),
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promRequestDuration)

	promResponseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_response_size",
		Help:      "Size of the returns response in bytes.",
		// Powers of 2 up to the maximum size.
		Buckets: []float64{0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536},
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promResponseSize)

	if prometheusPort == "" {
		return
	}

	_, err := strconv.Atoi(prometheusPort)
	if err != nil {
		log.Fatalf("skydns: bad port for prometheus: %s", prometheusPort)
	}

	http.Handle(prometheusPath, prometheus.Handler())
	go func() {
		log.Fatalf("skydns: %s", http.ListenAndServe(":"+prometheusPort, nil))
	}()
	log.Printf("skydns: metrics enabled on :%s%s", prometheusPort, prometheusPath)
}

// metricSizeAndDuration sets the size and duration metrics.
func metricSizeAndDuration(resp *dns.Msg, start time.Time, tcp bool) {
	net := "udp"
	if tcp {
		net = "tcp"
	}
	promRequestDuration.WithLabelValues(net).Observe(float64(time.Since(start)) / float64(time.Second))
	promResponseSize.WithLabelValues(net).Observe(float64(resp.Len()))
}

// Counter is the metric interface used by this package
type Counter interface {
	Inc(i int64)
}

type nopCounter struct{}

func (nopCounter) Inc(_ int64) {}

// These are the old stat variables defined by this package. This
// used by graphite.
var (
	// Pondering deletion in favor of the better and more
	// maintained (by me) prometheus reporting.

	StatsForwardCount     Counter = nopCounter{}
	StatsStubForwardCount Counter = nopCounter{}
	StatsLookupCount      Counter = nopCounter{}
	StatsRequestCount     Counter = nopCounter{}
	StatsDnssecOkCount    Counter = nopCounter{}
	StatsNameErrorCount   Counter = nopCounter{}
	StatsNoDataCount      Counter = nopCounter{}

	StatsDnssecCacheMiss Counter = nopCounter{}
)
<commit_msg>Msg can be nil, guard for that<commit_after>// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package server

import (
	"log"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/miekg/dns"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	prometheusPort      = os.Getenv("PROMETHEUS_PORT")
	prometheusPath      = os.Getenv("PROMETHEUS_PATH")
	prometheusNamespace = os.Getenv("PROMETHEUS_NAMESPACE")
	prometheusSubsystem = os.Getenv("PROMETHEUS_SUBSYSTEM")
)

var (
	promDnssecOkCount        prometheus.Counter
	promExternalRequestCount *prometheus.CounterVec
	promRequestCount         *prometheus.CounterVec
	promErrorCount           *prometheus.CounterVec
	promCacheSize            *prometheus.GaugeVec
	promCacheMiss            *prometheus.CounterVec
	promRequestDuration      *prometheus.HistogramVec
	promResponseSize         *prometheus.HistogramVec
)

func Metrics() {
	if prometheusPath == "" {
		prometheusPath = "/metrics"
	}
	if prometheusSubsystem == "" {
		prometheusSubsystem = "skydns"
	}

	promExternalRequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_external_count",
		Help:      "Counter of external DNS requests.",
	}, []string{"type"}) // recursive, stub, lookup
	prometheus.MustRegister(promExternalRequestCount)

	promRequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_count",
		Help:      "Counter of DNS requests made.",
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promRequestCount)

	promDnssecOkCount = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_dnssec_ok_count",
		Help:      "Counter of DNSSEC requests.",
	})
	prometheus.MustRegister(promDnssecOkCount) // Maybe more bits here?

	promErrorCount = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_error_count",
		Help:      "Counter of DNS requests resulting in an error.",
	}, []string{"error"}) // nxdomain, nodata, truncated, refused, overflow
	prometheus.MustRegister(promErrorCount)

	// Caches
	promCacheSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "cache_total_size",
		Help:      "The total size of all elements in the cache.",
	}, []string{"type"}) // response, signature
	prometheus.MustRegister(promCacheSize)

	promCacheMiss = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_cache_miss_count",
		Help:      "Counter of DNS requests that result in a cache miss.",
	}, []string{"type"}) // response, signature
	prometheus.MustRegister(promCacheMiss)

	promRequestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_request_duration",
		Help:      "Histogram of the time (in seconds) each request took to resolve.",
		Buckets:   append([]float64{0.001, 0.003}, prometheus.DefBuckets...),
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promRequestDuration)

	promResponseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: prometheusNamespace,
		Subsystem: prometheusSubsystem,
		Name:      "dns_response_size",
		Help:      "Size of the returns response in bytes.",
		// Powers of 2 up to the maximum size.
		Buckets: []float64{0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536},
	}, []string{"type"}) // udp, tcp
	prometheus.MustRegister(promResponseSize)

	if prometheusPort == "" {
		return
	}

	_, err := strconv.Atoi(prometheusPort)
	if err != nil {
		log.Fatalf("skydns: bad port for prometheus: %s", prometheusPort)
	}

	http.Handle(prometheusPath, prometheus.Handler())
	go func() {
		log.Fatalf("skydns: %s", http.ListenAndServe(":"+prometheusPort, nil))
	}()
	log.Printf("skydns: metrics enabled on :%s%s", prometheusPort, prometheusPath)
}

// metricSizeAndDuration sets the size and duration metrics.
func metricSizeAndDuration(resp *dns.Msg, start time.Time, tcp bool) {
	net := "udp"
	rlen := float64(0)
	if tcp {
		net = "tcp"
	}
	if resp != nil {
		rlen = float64(resp.Len())
	}
	promRequestDuration.WithLabelValues(net).Observe(float64(time.Since(start)) / float64(time.Second))
	promResponseSize.WithLabelValues(net).Observe(rlen)
}

// Counter is the metric interface used by this package
type Counter interface {
	Inc(i int64)
}

type nopCounter struct{}

func (nopCounter) Inc(_ int64) {}

// These are the old stat variables defined by this package. This
// used by graphite.
var (
	// Pondering deletion in favor of the better and more
	// maintained (by me) prometheus reporting.

	StatsForwardCount     Counter = nopCounter{}
	StatsStubForwardCount Counter = nopCounter{}
	StatsLookupCount      Counter = nopCounter{}
	StatsRequestCount     Counter = nopCounter{}
	StatsDnssecOkCount    Counter = nopCounter{}
	StatsNameErrorCount   Counter = nopCounter{}
	StatsNoDataCount      Counter = nopCounter{}

	StatsDnssecCacheMiss Counter = nopCounter{}
)
<|endoftext|>


<commit_before>/**
 * Copyright 2016 IBM Corp.
 *
 * 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 session

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/softlayer/softlayer-go/datatypes"
	"github.com/softlayer/softlayer-go/sl"
)

type RestTransport struct{}

// DoRequest - Implementation of the TransportHandler interface for handling
// calls to the REST endpoint.
func (r *RestTransport) DoRequest(sess *Session, service string, method string, args []interface{}, options *sl.Options, pResult interface{}) error {
	restMethod := httpMethod(method, args)

	// Parse any method parameters and determine the HTTP method
	var parameters []byte
	if len(args) > 0 {
		// parse the parameters
		parameters, _ = json.Marshal(
			map[string]interface{}{
				"parameters": args,
			})
	}

	path := buildPath(service, method, options)

	resp, code, err := makeHTTPRequest(
		sess,
		path,
		restMethod,
		bytes.NewBuffer(parameters),
		options)

	if err != nil {
		return sl.Error{Wrapped: err}
	}

	if code < 200 || code > 299 {
		e := sl.Error{StatusCode: code}

		err = json.Unmarshal(resp, &e)

		// If unparseable, wrap the json error
		if err != nil {
			e.Wrapped = err
			e.Message = err.Error()
		}

		return e
	}

	// Some APIs that normally return a collection, omit the []'s when the API returns a single value
	returnType := reflect.TypeOf(pResult).String()
	if strings.Index(returnType, "[]") == 1 && strings.Index(string(resp), "[") != 0 {
		resp = []byte("[" + string(resp) + "]")
	}

	// At this point, all that's left to do is parse the return value to the appropriate type, and return
	// any parse errors (or nil if successful)

	err = nil
	switch pResult.(type) {
	case *[]uint8:
		// exclude quotes
		*pResult.(*[]uint8) = resp[1 : len(resp)-1]
	case *datatypes.Void:
	case *uint:
		var val uint64
		val, err = strconv.ParseUint(string(resp), 0, 64)
		if err == nil {
			*pResult.(*uint) = uint(val)
		}
	case *bool:
		*pResult.(*bool), err = strconv.ParseBool(string(resp))
	case *string:
		*pResult.(*string) = string(resp)
	default:
		// Must be a json representation of one of the many softlayer datatypes
		err = json.Unmarshal(resp, pResult)
	}

	if err != nil {
		err = sl.Error{Message: err.Error(), Wrapped: err}
	}

	return err
}

func buildPath(service string, method string, options *sl.Options) string {
	path := service

	if options.Id != nil {
		path = path + "/" + strconv.Itoa(*options.Id)
	}

	// omit the API method name if the method represents one of the basic REST methods
	if method != "getObject" && method != "deleteObject" && method != "createObject" &&
		method != "createObjects" && method != "editObject" && method != "editObjects" {
		path = path + "/" + method
	}

	return path + ".json"
}

func encodeQuery(opts *sl.Options) string {
	query := new(url.URL).Query()

	if opts.Mask != "" {
		query.Add("objectMask", opts.Mask)
	}

	if opts.Filter != "" {
		query.Add("objectFilter", opts.Filter)
	}

	// resultLimit=<offset>,<limit>
	// If offset unspecified, default to 0
	if opts.Limit != nil {
		startOffset := 0
		if opts.Offset != nil {
			startOffset = *opts.Offset
		}

		query.Add("resultLimit", fmt.Sprintf("%d,%d", startOffset, *opts.Limit))
	}

	return query.Encode()
}

func makeHTTPRequest(session *Session, path string, requestType string, requestBody *bytes.Buffer, options *sl.Options) ([]byte, int, error) {
	client := http.DefaultClient
	client.Timeout = DefaultTimeout
	if session.Timeout != 0 {
		client.Timeout = session.Timeout
	}

	var url string
	if session.Endpoint == "" {
		url = url + DefaultEndpoint
	} else {
		url = url + session.Endpoint
	}
	url = fmt.Sprintf("%s/%s", strings.TrimRight(url, "/"), path)
	req, err := http.NewRequest(requestType, url, requestBody)
	if err != nil {
		return nil, 0, err
	}

	req.SetBasicAuth(session.UserName, session.APIKey)

	req.URL.RawQuery = encodeQuery(options)

	if session.Debug {
		log.Println("[DEBUG] Request URL: ", requestType, req.URL)
		log.Println("[DEBUG] Parameters: ", requestBody.String())
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, 520, err
	}

	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, resp.StatusCode, err
	}

	if session.Debug {
		log.Println("[DEBUG] Response: ", string(responseBody))
	}
	return responseBody, resp.StatusCode, nil
}

func httpMethod(name string, args []interface{}) string {
	if name == "deleteObject" {
		return "DELETE"
	} else if name == "editObject" || name == "editObjects" {
		return "PUT"
	} else if name == "createObject" || name == "createObjects" || len(args) > 0 {
		return "POST"
	}

	return "GET"
}
<commit_msg>REST transport: Support user id and portal token in authorization header<commit_after>/**
 * Copyright 2016 IBM Corp.
 *
 * 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 session

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/softlayer/softlayer-go/datatypes"
	"github.com/softlayer/softlayer-go/sl"
)

type RestTransport struct{}

// DoRequest - Implementation of the TransportHandler interface for handling
// calls to the REST endpoint.
func (r *RestTransport) DoRequest(sess *Session, service string, method string, args []interface{}, options *sl.Options, pResult interface{}) error {
	restMethod := httpMethod(method, args)

	// Parse any method parameters and determine the HTTP method
	var parameters []byte
	if len(args) > 0 {
		// parse the parameters
		parameters, _ = json.Marshal(
			map[string]interface{}{
				"parameters": args,
			})
	}

	path := buildPath(service, method, options)

	resp, code, err := makeHTTPRequest(
		sess,
		path,
		restMethod,
		bytes.NewBuffer(parameters),
		options)

	if err != nil {
		return sl.Error{Wrapped: err}
	}

	if code < 200 || code > 299 {
		e := sl.Error{StatusCode: code}

		err = json.Unmarshal(resp, &e)

		// If unparseable, wrap the json error
		if err != nil {
			e.Wrapped = err
			e.Message = err.Error()
		}

		return e
	}

	// Some APIs that normally return a collection, omit the []'s when the API returns a single value
	returnType := reflect.TypeOf(pResult).String()
	if strings.Index(returnType, "[]") == 1 && strings.Index(string(resp), "[") != 0 {
		resp = []byte("[" + string(resp) + "]")
	}

	// At this point, all that's left to do is parse the return value to the appropriate type, and return
	// any parse errors (or nil if successful)

	err = nil
	switch pResult.(type) {
	case *[]uint8:
		// exclude quotes
		*pResult.(*[]uint8) = resp[1 : len(resp)-1]
	case *datatypes.Void:
	case *uint:
		var val uint64
		val, err = strconv.ParseUint(string(resp), 0, 64)
		if err == nil {
			*pResult.(*uint) = uint(val)
		}
	case *bool:
		*pResult.(*bool), err = strconv.ParseBool(string(resp))
	case *string:
		*pResult.(*string) = string(resp)
	default:
		// Must be a json representation of one of the many softlayer datatypes
		err = json.Unmarshal(resp, pResult)
	}

	if err != nil {
		err = sl.Error{Message: err.Error(), Wrapped: err}
	}

	return err
}

func buildPath(service string, method string, options *sl.Options) string {
	path := service

	if options.Id != nil {
		path = path + "/" + strconv.Itoa(*options.Id)
	}

	// omit the API method name if the method represents one of the basic REST methods
	if method != "getObject" && method != "deleteObject" && method != "createObject" &&
		method != "createObjects" && method != "editObject" && method != "editObjects" {
		path = path + "/" + method
	}

	return path + ".json"
}

func encodeQuery(opts *sl.Options) string {
	query := new(url.URL).Query()

	if opts.Mask != "" {
		query.Add("objectMask", opts.Mask)
	}

	if opts.Filter != "" {
		query.Add("objectFilter", opts.Filter)
	}

	// resultLimit=<offset>,<limit>
	// If offset unspecified, default to 0
	if opts.Limit != nil {
		startOffset := 0
		if opts.Offset != nil {
			startOffset = *opts.Offset
		}

		query.Add("resultLimit", fmt.Sprintf("%d,%d", startOffset, *opts.Limit))
	}

	return query.Encode()
}

func makeHTTPRequest(session *Session, path string, requestType string, requestBody *bytes.Buffer, options *sl.Options) ([]byte, int, error) {
	client := http.DefaultClient
	client.Timeout = DefaultTimeout
	if session.Timeout != 0 {
		client.Timeout = session.Timeout
	}

	var url string
	if session.Endpoint == "" {
		url = url + DefaultEndpoint
	} else {
		url = url + session.Endpoint
	}
	url = fmt.Sprintf("%s/%s", strings.TrimRight(url, "/"), path)
	req, err := http.NewRequest(requestType, url, requestBody)
	if err != nil {
		return nil, 0, err
	}

	if session.APIKey != "" {
		req.SetBasicAuth(session.UserName, session.APIKey)
	} else {
		req.SetBasicAuth(fmt.Sprintf("%d", session.UserId), session.AuthToken)
	}

	req.URL.RawQuery = encodeQuery(options)

	if session.Debug {
		log.Println("[DEBUG] Request URL: ", requestType, req.URL)
		log.Println("[DEBUG] Parameters: ", requestBody.String())
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, 520, err
	}

	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, resp.StatusCode, err
	}

	if session.Debug {
		log.Println("[DEBUG] Response: ", string(responseBody))
	}
	return responseBody, resp.StatusCode, nil
}

func httpMethod(name string, args []interface{}) string {
	if name == "deleteObject" {
		return "DELETE"
	} else if name == "editObject" || name == "editObjects" {
		return "PUT"
	} else if name == "createObject" || name == "createObjects" || len(args) > 0 {
		return "POST"
	}

	return "GET"
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	functions "github.com/iron-io/functions_go"
	"github.com/urfave/cli"
	"golang.org/x/crypto/ssh/terminal"
)

type routesCmd struct {
	*functions.RoutesApi
}

func routes() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	return cli.Command{
		Name:      "routes",
		Usage:     "list routes",
		ArgsUsage: "fnctl routes",
		Action:    r.list,
		Subcommands: []cli.Command{
			{
				Name:      "call",
				Usage:     "call a route",
				ArgsUsage: "appName /path",
				Action:    r.call,
				Flags:     runflags(),
			},
			{
				Name:      "create",
				Usage:     "create a route",
				ArgsUsage: "appName /path image/name",
				Action:    r.create,
				Flags: []cli.Flag{
					cli.Int64Flag{
						Name:  "memory",
						Usage: "memory in MiB",
						Value: 128,
					},
					cli.StringFlag{
						Name:  "type",
						Usage: "route type - sync or async",
						Value: "sync",
					},
					cli.StringSliceFlag{
						Name:  "config",
						Usage: "route configuration",
					},
				},
			},
			{
				Name:      "delete",
				Usage:     "delete a route",
				ArgsUsage: "appName /path",
				Action:    r.delete,
			},
		},
	}
}

func call() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	return cli.Command{
		Name:      "call",
		Usage:     "call a remote function",
		ArgsUsage: "appName /path",
		Flags:     runflags(),
		Action:    r.call,
	}
}

func (a *routesCmd) list(c *cli.Context) error {
	if c.Args().First() == "" {
		return errors.New("error: routes listing takes one argument, an app name")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	wrapper, _, err := a.AppsAppRoutesGet(appName)
	if err != nil {
		return fmt.Errorf("error getting routes: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
	fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
	for _, route := range wrapper.Routes {
		u, err := url.Parse("../")
		u.Path = path.Join(u.Path, "r", appName, route.Path)
		if err != nil {
			return fmt.Errorf("error parsing functions route path: %v", err)
		}

		fmt.Fprint(w, route.Path, "\t", route.Image, "\t", baseURL.ResolveReference(u).String(), "\n")
	}
	w.Flush()

	return nil
}

func (a *routesCmd) call(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a route")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)

	u, err := url.Parse("../")
	u.Path = path.Join(u.Path, "r", appName, route)

	var content io.Reader
	if !terminal.IsTerminal(int(os.Stdin.Fd())) {
		content = os.Stdin
	}

	req, err := http.NewRequest("POST", baseURL.ResolveReference(u).String(), content)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	envAsHeader(req, c.StringSlice("e"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}

	io.Copy(os.Stdout, resp.Body)
	return nil
}

func envAsHeader(req *http.Request, selectedEnv []string) {
	detectedEnv := os.Environ()
	if len(selectedEnv) > 0 {
		detectedEnv = selectedEnv
	}

	for _, e := range detectedEnv {
		kv := strings.Split(e, "=")
		name := kv[0]
		req.Header.Set(name, os.Getenv(name))
	}
}

func (a *routesCmd) create(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes creation takes three arguments: an app name, a route path and an image")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	image := c.Args().Get(2)
	if image == "" {
		ff, err := findFuncfile()
		if err != nil {
			if _, ok := err.(*notFoundError); ok {
				return errors.New("error: image name is missing or no function file found")
			} else {
				return err
			}
		}
		image = ff.FullName()
	}

	body := functions.RouteWrapper{
		Route: functions.Route{
			AppName: appName,
			Path:    route,
			Image:   image,
			Memory:  c.Int64("memory"),
			Type_:   c.String("type"),
			Config:  extractEnvConfig(c.StringSlice("config")),
		},
	}

	wrapper, _, err := a.AppsAppRoutesPost(appName, body)
	if err != nil {
		return fmt.Errorf("error creating route: %v", err)
	}
	if wrapper.Route.Path == "" || wrapper.Route.Image == "" {
		return fmt.Errorf("could not create this route (%s at %s), check if route path is correct", route, appName)
	}

	fmt.Println(wrapper.Route.Path, "created with", wrapper.Route.Image)
	return nil
}

func (a *routesCmd) delete(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a path")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	_, err := a.AppsAppRoutesRouteDelete(appName, route)
	if err != nil {
		return fmt.Errorf("error deleting route: %v", err)
	}

	fmt.Println(route, "deleted")
	return nil
}
<commit_msg>fnctl: heroku-like configuration for routes (#287)<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	functions "github.com/iron-io/functions_go"
	"github.com/urfave/cli"
	"golang.org/x/crypto/ssh/terminal"
)

type routesCmd struct {
	*functions.RoutesApi
}

func routes() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	return cli.Command{
		Name:      "routes",
		Usage:     "list routes",
		ArgsUsage: "fnctl routes",
		Action:    r.list,
		Subcommands: []cli.Command{
			{
				Name:      "call",
				Usage:     "call a route",
				ArgsUsage: "appName /path",
				Action:    r.call,
				Flags:     runflags(),
			},
			{
				Name:      "create",
				Usage:     "create a route",
				ArgsUsage: "appName /path image/name",
				Action:    r.create,
				Flags: []cli.Flag{
					cli.Int64Flag{
						Name:  "memory",
						Usage: "memory in MiB",
						Value: 128,
					},
					cli.StringFlag{
						Name:  "type",
						Usage: "route type - sync or async",
						Value: "sync",
					},
					cli.StringSliceFlag{
						Name:  "config",
						Usage: "route configuration",
					},
				},
			},
			{
				Name:      "delete",
				Usage:     "delete a route",
				ArgsUsage: "appName /path",
				Action:    r.delete,
			},
			{
				Name:   "config",
				Usage:  "operate a route configuration set",
				Action: r.configList,
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "shell",
						Usage: "output in shell format",
					},
					cli.BoolFlag{
						Name:  "json",
						Usage: "output in JSON format",
					},
				},
				Subcommands: []cli.Command{
					{
						Name:        "set",
						Description: "store a configuration key for this route",
						Usage:       "<app> <key> <value>",
						Action:      r.configSet,
					},
					{
						Name:        "unset",
						Description: "remove a configuration key for this route",
						Usage:       "<app> <key> <value>",
						Action:      r.configUnset,
					},
				},
			},
		},
	}
}

func call() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	return cli.Command{
		Name:      "call",
		Usage:     "call a remote function",
		ArgsUsage: "appName /path",
		Flags:     runflags(),
		Action:    r.call,
	}
}

func (a *routesCmd) list(c *cli.Context) error {
	if c.Args().First() == "" {
		return errors.New("error: routes listing takes one argument, an app name")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	wrapper, _, err := a.AppsAppRoutesGet(appName)
	if err != nil {
		return fmt.Errorf("error getting routes: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
	fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
	for _, route := range wrapper.Routes {
		u, err := url.Parse("../")
		u.Path = path.Join(u.Path, "r", appName, route.Path)
		if err != nil {
			return fmt.Errorf("error parsing functions route path: %v", err)
		}

		fmt.Fprint(w, route.Path, "\t", route.Image, "\t", baseURL.ResolveReference(u).String(), "\n")
	}
	w.Flush()

	return nil
}

func (a *routesCmd) call(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a route")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)

	u, err := url.Parse("../")
	u.Path = path.Join(u.Path, "r", appName, route)

	var content io.Reader
	if !terminal.IsTerminal(int(os.Stdin.Fd())) {
		content = os.Stdin
	}

	req, err := http.NewRequest("POST", baseURL.ResolveReference(u).String(), content)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	envAsHeader(req, c.StringSlice("e"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}

	io.Copy(os.Stdout, resp.Body)
	return nil
}

func envAsHeader(req *http.Request, selectedEnv []string) {
	detectedEnv := os.Environ()
	if len(selectedEnv) > 0 {
		detectedEnv = selectedEnv
	}

	for _, e := range detectedEnv {
		kv := strings.Split(e, "=")
		name := kv[0]
		req.Header.Set(name, os.Getenv(name))
	}
}

func (a *routesCmd) create(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes creation takes three arguments: an app name, a route path and an image")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	image := c.Args().Get(2)
	if image == "" {
		ff, err := findFuncfile()
		if err != nil {
			if _, ok := err.(*notFoundError); ok {
				return errors.New("error: image name is missing or no function file found")
			} else {
				return err
			}
		}
		image = ff.FullName()
	}

	body := functions.RouteWrapper{
		Route: functions.Route{
			AppName: appName,
			Path:    route,
			Image:   image,
			Memory:  c.Int64("memory"),
			Type_:   c.String("type"),
			Config:  extractEnvConfig(c.StringSlice("config")),
		},
	}

	wrapper, _, err := a.AppsAppRoutesPost(appName, body)
	if err != nil {
		return fmt.Errorf("error creating route: %v", err)
	}
	if wrapper.Route.Path == "" || wrapper.Route.Image == "" {
		return fmt.Errorf("could not create this route (%s at %s), check if route path is correct", route, appName)
	}

	fmt.Println(wrapper.Route.Path, "created with", wrapper.Route.Image)
	return nil
}

func (a *routesCmd) delete(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a path")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	_, err := a.AppsAppRoutesRouteDelete(appName, route)
	if err != nil {
		return fmt.Errorf("error deleting route: %v", err)
	}

	fmt.Println(route, "deleted")
	return nil
}

func (a *routesCmd) configList(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: route configuration description takes two arguments: an app name and a route")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	wrapper, _, err := a.AppsAppRoutesRouteGet(appName, route)
	if err != nil {
		return fmt.Errorf("error loading route information: %v", err)
	}

	config := wrapper.Route.Config
	if len(config) == 0 {
		return errors.New("this route has no configurations")
	}

	if c.Bool("json") {
		if err := json.NewEncoder(os.Stdout).Encode(config); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	} else if c.Bool("shell") {
		for k, v := range config {
			fmt.Print("export ", k, "=", v, "\n")
		}
	} else {
		fmt.Println(wrapper.Route.AppName, wrapper.Route.Path, "configuration:")
		w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, ' ', 0)
		for k, v := range config {
			fmt.Fprint(w, k, ":\t", v, "\n")
		}
		w.Flush()
	}
	return nil
}

func (a *routesCmd) configSet(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" {
		return errors.New("error: route configuration setting takes four arguments: an app name, a route, a key and a value")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	key := c.Args().Get(2)
	value := c.Args().Get(3)

	wrapper, _, err := a.AppsAppRoutesRouteGet(appName, route)
	if err != nil {
		return fmt.Errorf("error creating app: %v", err)
	}

	config := wrapper.Route.Config

	if config == nil {
		config = make(map[string]string)
	}

	config[key] = value
	wrapper.Route.Config = config

	if _, err := a.AppsAppRoutesRouteDelete(appName, route); err != nil {
		return fmt.Errorf("error deleting to force update route: %v", err)
	}

	if _, _, err := a.AppsAppRoutesPost(appName, *wrapper); err != nil {
		return fmt.Errorf("error updating route configuration: %v", err)
	}

	fmt.Println(wrapper.Route.AppName, wrapper.Route.Path, "updated", key, "with", value)
	return nil
}

func (a *routesCmd) configUnset(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" {
		return errors.New("error: route configuration setting takes four arguments: an app name, a route and a key")
	}

	if err := resetBasePath(&a.Configuration); err != nil {
		return fmt.Errorf("error setting endpoint: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	key := c.Args().Get(2)

	wrapper, _, err := a.AppsAppRoutesRouteGet(appName, route)
	if err != nil {
		return fmt.Errorf("error creating app: %v", err)
	}

	config := wrapper.Route.Config

	if config == nil {
		config = make(map[string]string)
	}

	if _, ok := config[key]; !ok {
		return fmt.Errorf("configuration key %s not found", key)
	}

	delete(config, key)
	wrapper.Route.Config = config

	if _, err := a.AppsAppRoutesRouteDelete(appName, route); err != nil {
		return fmt.Errorf("error deleting to force update route: %v", err)
	}

	if _, _, err := a.AppsAppRoutesPost(appName, *wrapper); err != nil {
		return fmt.Errorf("error updating route configuration: %v", err)
	}

	fmt.Println(wrapper.Route.AppName, wrapper.Route.Path, "removed", key)
	return nil
}
<|endoftext|>


<commit_before>package moon

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"sort"
	"strconv"
	"strings"
)

type nodeType int

const (
	n_error nodeType = iota
	n_root
	n_comment
	n_assignment
	n_string
	n_number
	n_list
	n_object
	n_variable
)

var indent = "  "

type node interface {
	Type() nodeType
	parse(*parser) error
	pretty(io.Writer, string) error
	eval(map[string]interface{}) (interface{}, error)
}

type rootNode struct {
	children []node
}

func newRootNode() node {
	return &rootNode{children: make([]node, 0, 8)}
}

func (n *rootNode) Type() nodeType {
	return n_root
}

func (n *rootNode) parse(p *parser) error {
	for {
		t := p.next()
		switch t.t {
		case t_error:
			return fmt.Errorf("parse error: saw lex error while parsing root node: %v", t)
		case t_eof:
			return nil
		case t_comment:
			n.addChild(&commentNode{t.s})
		case t_name, t_variable:
			nn := &assignmentNode{name: t.s}
			if err := nn.parse(p); err != nil {
				return err
			}
			n.addChild(nn)
		default:
			return fmt.Errorf("parse error: unexpected token type %v while parsing root node", t.t)
		}
	}
}

func (n *rootNode) addChild(child node) {
	if n.children == nil {
		n.children = make([]node, 0, 8)
	}
	n.children = append(n.children, child)
}

func (n *rootNode) String() string {
	var buf bytes.Buffer
	buf.WriteString("{")
	for _, child := range n.children {
		fmt.Fprintf(&buf, "%s, ", child)
	}
	if buf.Len() > 1 {
		buf.Truncate(buf.Len() - 2)
	}
	buf.WriteString("}")
	return buf.String()
}

func (n *rootNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sroot:\n", prefix)
	for _, child := range n.children {
		if err := child.pretty(w, prefix+indent); err != nil {
			return err
		}
	}
	return nil
}

func (n *rootNode) eval(ctx map[string]interface{}) (interface{}, error) {
	for _, child := range n.children {
		if _, err := child.eval(ctx); err != nil {
			return nil, err
		}
	}
	return nil, nil
}

type commentNode struct {
	body string
}

func (n *commentNode) Type() nodeType {
	return n_comment
}

func (n *commentNode) parse(p *parser) error {
	return nil
}

func (n *commentNode) String() string {
	return fmt.Sprintf("{comment: %s}", n.body)
}

func (n *commentNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%scomment:\n", prefix)
	r := bufio.NewReader(strings.NewReader(n.body))
	for {
		line, err := r.ReadString('\n')
		if err == io.EOF {
			if line != "" {
				fmt.Fprintf(w, "%s%s%s\n", prefix, indent, line)
			}
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintf(w, "%s%s%s\n", prefix, indent, line)
	}
	return nil
}

func (n *commentNode) eval(ctx map[string]interface{}) (interface{}, error) {
	return nil, nil
}

type assignmentNode struct {
	name  string
	value node
}

func (n *assignmentNode) Type() nodeType {
	return n_assignment
}

func (n *assignmentNode) parse(p *parser) error {
	t := p.next()
	switch t.t {
	case t_error:
		return fmt.Errorf("parse error: saw lex error while parsing assignment node: %v", t.s)
	case t_eof:
		return fmt.Errorf("parse error: unexpected eof in assignment node")
	case t_object_separator:
	default:
		return fmt.Errorf("parse error: unexpected %v token after name, expected =", t.t)
	}

	v, err := p.parseValue()
	if err != nil {
		return err
	}
	n.value = v
	return nil
}

func (n *assignmentNode) String() string {
	return fmt.Sprintf("{assign: name=%s, val=%v}", n.name, n.value)
}

func (n *assignmentNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sassign:\n", prefix)
	fmt.Fprintf(w, "%s%sname:\n", prefix, indent)
	fmt.Fprintf(w, "%s%s%s%s\n", prefix, indent, indent, n.name)
	fmt.Fprintf(w, "%s%svalue:\n", prefix, indent)
	if err := n.value.pretty(w, prefix+indent+indent); err != nil {
		return err
	}
	return nil
}

func (n *assignmentNode) eval(ctx map[string]interface{}) (interface{}, error) {
	if _, ok := ctx[n.name]; ok {
		return nil, fmt.Errorf("invalid re-declaration: %s", n.name)
	}
	v, err := n.value.eval(ctx)
	if err != nil {
		return nil, err
	}
	ctx[n.name] = v
	return nil, nil
}

func (n *assignmentNode) isHidden() bool {
	return strings.HasPrefix(n.name, ".")
}

type stringNode string

func (s *stringNode) Type() nodeType {
	return n_string
}

func (s *stringNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_string {
		return fmt.Errorf("unexpected %s while looking for string token", t.t)
	}
	*s = stringNode(t.s)
	return nil
}

func (s *stringNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sstring:\n", prefix)
	_, err := fmt.Fprintf(w, "%s%s%s\n", prefix, indent, string(*s))
	return err
}

func (s *stringNode) eval(ctx map[string]interface{}) (interface{}, error) {
	return string(*s), nil
}

type numberType int

const (
	num_int numberType = iota
	num_float
	num_complex
)

type numberNode struct {
	t numberType
	c complex128
	i int
	f float64
}

func (n *numberNode) Type() nodeType {
	return n_number
}

func (n *numberNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_real_number {
		return fmt.Errorf("unexpected %s token while parsing number", t.t)
	}

	if p.peek().t == t_imaginary_number {
		n.t = num_complex
		s := t.s + p.next().s
		if _, err := fmt.Sscan(s, &n.c); err != nil {
			return fmt.Errorf("ungood imaginary number format %s: %s", s, err)
		}
		return nil
	}

	i, err := strconv.ParseInt(t.s, 0, 64)
	if err == nil {
		n.t = num_int
		n.i = int(i)
		return nil
	}

	f, err := strconv.ParseFloat(t.s, 64)
	if err == nil {
		n.t = num_float
		n.f = f
		return nil
	}

	return fmt.Errorf("this token broke the number parser: %s", t)
}

func (n *numberNode) pretty(w io.Writer, prefix string) error {
	v, err := n.eval(nil)
	if err != nil {
		return err
	}
	fmt.Fprintf(w, "%snumber:\n%s%s%v\n", prefix, prefix, indent, v)
	return nil
}

func (n *numberNode) eval(ctx map[string]interface{}) (interface{}, error) {
	switch n.t {
	case num_int:
		return n.i, nil
	case num_float:
		return n.f, nil
	case num_complex:
		return n.c, nil
	default:
		panic("whoerps")
	}
}

type listNode []node

func (l *listNode) Type() nodeType {
	return n_list
}

func (l *listNode) parse(p *parser) error {
	if p.peek().t == t_list_end {
		p.next()
		return nil
	}

	if n, err := p.parseValue(); err != nil {
		return err
	} else {
		*l = append(*l, n)
	}

	switch t := p.peek(); t.t {
	case t_list_end:
		p.next()
		return nil
	default:
		return l.parse(p)
	}
}

func (l *listNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%slist:\n", prefix)
	for _, n := range *l {
		if err := n.pretty(w, prefix+indent); err != nil {
			return err
		}
	}
	return nil
}

func (l *listNode) eval(ctx map[string]interface{}) (interface{}, error) {
	out := make([]interface{}, 0, len(*l))
	for _, n := range *l {
		v, err := n.eval(ctx)
		if err != nil {
			return nil, err
		}
		out = append(out, v)
	}
	return out, nil
}

type objectNode map[string]node

func (o *objectNode) Type() nodeType {
	return n_object
}

func (o *objectNode) parse(p *parser) error {
	if p.peek().t == t_object_end {
		p.next()
		return nil
	}
	if err := p.ensureNext(t_name, "looking for object field name in parseObject"); err != nil {
		return err
	}
	field_name := p.next().s
	if err := p.ensureNext(t_object_separator, "looking for object separator in parseObject"); err != nil {
		return err
	}
	p.next()

	if n, err := p.parseValue(); err != nil {
		return err
	} else {
		(*o)[field_name] = n
	}

	switch t := p.peek(); t.t {
	case t_object_end:
		p.next()
		return nil
	default:
		return o.parse(p)
	}
}

func (o *objectNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sobject:\n", prefix)
	keys := make([]string, 0, len(*o))
	for key := range *o {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, key := range keys {
		fmt.Fprintf(w, "%s%s:\n", prefix+indent, key)
		err := (*o)[key].pretty(w, prefix+indent+indent)
		if err != nil {
			return err
		}
	}
	return nil
}

func (o *objectNode) eval(ctx map[string]interface{}) (interface{}, error) {
	out := make(map[string]interface{}, len(*o))
	for name, node := range *o {
		v, err := node.eval(ctx)
		if err != nil {
			return nil, err
		}
		out[name] = v
	}
	return out, nil
}

type variableNode struct {
	name string
}

func (v *variableNode) Type() nodeType {
	return n_variable
}

func (v *variableNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_variable {
		return fmt.Errorf("unexpected %s token when parsing variable", t.t)
	}
	v.name = t.s
	return nil
}

func (v *variableNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%svariable:\n", prefix)
	fmt.Fprintf(w, "%s%s\n", prefix+indent, v.name)
	return nil
}

func (v *variableNode) eval(ctx map[string]interface{}) (interface{}, error) {
	value, ok := ctx[v.name]
	if !ok {
		return nil, fmt.Errorf("undefined variable: %s", *v)
	}
	return value, nil
}
<commit_msg>define a context type<commit_after>package moon

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"sort"
	"strconv"
	"strings"
)

type nodeType int

const (
	n_error nodeType = iota
	n_root
	n_comment
	n_assignment
	n_string
	n_number
	n_list
	n_object
	n_variable
)

var indent = "  "

type context map[string]interface{}

type node interface {
	Type() nodeType
	parse(*parser) error
	pretty(io.Writer, string) error
	eval(context) (interface{}, error)
}

type rootNode struct {
	children []node
}

func newRootNode() node {
	return &rootNode{children: make([]node, 0, 8)}
}

func (n *rootNode) Type() nodeType {
	return n_root
}

func (n *rootNode) parse(p *parser) error {
	for {
		t := p.next()
		switch t.t {
		case t_error:
			return fmt.Errorf("parse error: saw lex error while parsing root node: %v", t)
		case t_eof:
			return nil
		case t_comment:
			n.addChild(&commentNode{t.s})
		case t_name, t_variable:
			nn := &assignmentNode{name: t.s}
			if err := nn.parse(p); err != nil {
				return err
			}
			n.addChild(nn)
		default:
			return fmt.Errorf("parse error: unexpected token type %v while parsing root node", t.t)
		}
	}
}

func (n *rootNode) addChild(child node) {
	if n.children == nil {
		n.children = make([]node, 0, 8)
	}
	n.children = append(n.children, child)
}

func (n *rootNode) String() string {
	var buf bytes.Buffer
	buf.WriteString("{")
	for _, child := range n.children {
		fmt.Fprintf(&buf, "%s, ", child)
	}
	if buf.Len() > 1 {
		buf.Truncate(buf.Len() - 2)
	}
	buf.WriteString("}")
	return buf.String()
}

func (n *rootNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sroot:\n", prefix)
	for _, child := range n.children {
		if err := child.pretty(w, prefix+indent); err != nil {
			return err
		}
	}
	return nil
}

func (n *rootNode) eval(ctx context) (interface{}, error) {
	for _, child := range n.children {
		if _, err := child.eval(ctx); err != nil {
			return nil, err
		}
	}
	return nil, nil
}

type commentNode struct {
	body string
}

func (n *commentNode) Type() nodeType {
	return n_comment
}

func (n *commentNode) parse(p *parser) error {
	return nil
}

func (n *commentNode) String() string {
	return fmt.Sprintf("{comment: %s}", n.body)
}

func (n *commentNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%scomment:\n", prefix)
	r := bufio.NewReader(strings.NewReader(n.body))
	for {
		line, err := r.ReadString('\n')
		if err == io.EOF {
			if line != "" {
				fmt.Fprintf(w, "%s%s%s\n", prefix, indent, line)
			}
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintf(w, "%s%s%s\n", prefix, indent, line)
	}
	return nil
}

func (n *commentNode) eval(ctx context) (interface{}, error) {
	return nil, nil
}

type assignmentNode struct {
	name  string
	value node
}

func (n *assignmentNode) Type() nodeType {
	return n_assignment
}

func (n *assignmentNode) parse(p *parser) error {
	t := p.next()
	switch t.t {
	case t_error:
		return fmt.Errorf("parse error: saw lex error while parsing assignment node: %v", t.s)
	case t_eof:
		return fmt.Errorf("parse error: unexpected eof in assignment node")
	case t_object_separator:
	default:
		return fmt.Errorf("parse error: unexpected %v token after name, expected =", t.t)
	}

	v, err := p.parseValue()
	if err != nil {
		return err
	}
	n.value = v
	return nil
}

func (n *assignmentNode) String() string {
	return fmt.Sprintf("{assign: name=%s, val=%v}", n.name, n.value)
}

func (n *assignmentNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sassign:\n", prefix)
	fmt.Fprintf(w, "%s%sname:\n", prefix, indent)
	fmt.Fprintf(w, "%s%s%s%s\n", prefix, indent, indent, n.name)
	fmt.Fprintf(w, "%s%svalue:\n", prefix, indent)
	if err := n.value.pretty(w, prefix+indent+indent); err != nil {
		return err
	}
	return nil
}

func (n *assignmentNode) eval(ctx context) (interface{}, error) {
	if _, ok := ctx[n.name]; ok {
		return nil, fmt.Errorf("invalid re-declaration: %s", n.name)
	}
	v, err := n.value.eval(ctx)
	if err != nil {
		return nil, err
	}
	ctx[n.name] = v
	return nil, nil
}

func (n *assignmentNode) isHidden() bool {
	return strings.HasPrefix(n.name, ".")
}

type stringNode string

func (s *stringNode) Type() nodeType {
	return n_string
}

func (s *stringNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_string {
		return fmt.Errorf("unexpected %s while looking for string token", t.t)
	}
	*s = stringNode(t.s)
	return nil
}

func (s *stringNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sstring:\n", prefix)
	_, err := fmt.Fprintf(w, "%s%s%s\n", prefix, indent, string(*s))
	return err
}

func (s *stringNode) eval(ctx context) (interface{}, error) {
	return string(*s), nil
}

type numberType int

const (
	num_int numberType = iota
	num_float
	num_complex
)

type numberNode struct {
	t numberType
	c complex128
	i int
	f float64
}

func (n *numberNode) Type() nodeType {
	return n_number
}

func (n *numberNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_real_number {
		return fmt.Errorf("unexpected %s token while parsing number", t.t)
	}

	if p.peek().t == t_imaginary_number {
		n.t = num_complex
		s := t.s + p.next().s
		if _, err := fmt.Sscan(s, &n.c); err != nil {
			return fmt.Errorf("ungood imaginary number format %s: %s", s, err)
		}
		return nil
	}

	i, err := strconv.ParseInt(t.s, 0, 64)
	if err == nil {
		n.t = num_int
		n.i = int(i)
		return nil
	}

	f, err := strconv.ParseFloat(t.s, 64)
	if err == nil {
		n.t = num_float
		n.f = f
		return nil
	}

	return fmt.Errorf("this token broke the number parser: %s", t)
}

func (n *numberNode) pretty(w io.Writer, prefix string) error {
	v, err := n.eval(nil)
	if err != nil {
		return err
	}
	fmt.Fprintf(w, "%snumber:\n%s%s%v\n", prefix, prefix, indent, v)
	return nil
}

func (n *numberNode) eval(ctx context) (interface{}, error) {
	switch n.t {
	case num_int:
		return n.i, nil
	case num_float:
		return n.f, nil
	case num_complex:
		return n.c, nil
	default:
		panic("whoerps")
	}
}

type listNode []node

func (l *listNode) Type() nodeType {
	return n_list
}

func (l *listNode) parse(p *parser) error {
	if p.peek().t == t_list_end {
		p.next()
		return nil
	}

	if n, err := p.parseValue(); err != nil {
		return err
	} else {
		*l = append(*l, n)
	}

	switch t := p.peek(); t.t {
	case t_list_end:
		p.next()
		return nil
	default:
		return l.parse(p)
	}
}

func (l *listNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%slist:\n", prefix)
	for _, n := range *l {
		if err := n.pretty(w, prefix+indent); err != nil {
			return err
		}
	}
	return nil
}

func (l *listNode) eval(ctx context) (interface{}, error) {
	out := make([]interface{}, 0, len(*l))
	for _, n := range *l {
		v, err := n.eval(ctx)
		if err != nil {
			return nil, err
		}
		out = append(out, v)
	}
	return out, nil
}

type objectNode map[string]node

func (o *objectNode) Type() nodeType {
	return n_object
}

func (o *objectNode) parse(p *parser) error {
	if p.peek().t == t_object_end {
		p.next()
		return nil
	}
	if err := p.ensureNext(t_name, "looking for object field name in parseObject"); err != nil {
		return err
	}
	field_name := p.next().s
	if err := p.ensureNext(t_object_separator, "looking for object separator in parseObject"); err != nil {
		return err
	}
	p.next()

	if n, err := p.parseValue(); err != nil {
		return err
	} else {
		(*o)[field_name] = n
	}

	switch t := p.peek(); t.t {
	case t_object_end:
		p.next()
		return nil
	default:
		return o.parse(p)
	}
}

func (o *objectNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%sobject:\n", prefix)
	keys := make([]string, 0, len(*o))
	for key := range *o {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, key := range keys {
		fmt.Fprintf(w, "%s%s:\n", prefix+indent, key)
		err := (*o)[key].pretty(w, prefix+indent+indent)
		if err != nil {
			return err
		}
	}
	return nil
}

func (o *objectNode) eval(ctx context) (interface{}, error) {
	out := make(map[string]interface{}, len(*o))
	for name, node := range *o {
		v, err := node.eval(ctx)
		if err != nil {
			return nil, err
		}
		out[name] = v
	}
	return out, nil
}

type variableNode struct {
	name string
}

func (v *variableNode) Type() nodeType {
	return n_variable
}

func (v *variableNode) parse(p *parser) error {
	t := p.next()
	if t.t != t_variable {
		return fmt.Errorf("unexpected %s token when parsing variable", t.t)
	}
	v.name = t.s
	return nil
}

func (v *variableNode) pretty(w io.Writer, prefix string) error {
	fmt.Fprintf(w, "%svariable:\n", prefix)
	fmt.Fprintf(w, "%s%s\n", prefix+indent, v.name)
	return nil
}

func (v *variableNode) eval(ctx context) (interface{}, error) {
	value, ok := ctx[v.name]
	if !ok {
		return nil, fmt.Errorf("undefined variable: %s", *v)
	}
	return value, nil
}
<|endoftext|>


<commit_before>package main

import (
	"sync/atomic"

	"delay"

	"stm32/hal/raw/tim"
)

type counter struct {
	t *tim.TIM_Periph
}

func (c *counter) Init(t *tim.TIM_Periph) {
	c.t = t
	t.CKD().Store(2 << tim.CKDn)
	// Connect CC1 to TI1, setup input filter.
	t.CCMR1.StoreBits(tim.CC1S|tim.IC1F, 1<<tim.CC1Sn|0xf<<tim.IC1Fn)
	// Set falling edge detection, enable CC1.
	t.CCER.SetBits(tim.CC1P)
	// Set external clock mode 1, clock from filtered TI1.
	t.SMCR.StoreBits(tim.SMS|tim.TS, 7<<tim.SMSn|5<<tim.TSn)
	// Use CC2 to generate an interrupt after first count.
	t.CCR2.Store(1)
	t.DIER.Store(tim.CC2IE)
	t.CEN().Set()
}

func (c *counter) Load() int {
	return int(c.t.CNT.Load())
}

func (c *counter) LoadAndReset() int {
	cnt := int(c.t.CNT.Load())
	c.t.EGR.Store(tim.UG)
	return cnt
}

func (c *counter) ClearIF() {
	c.t.SR.Store(0)
}

type waterHeaterControl struct {
	pwm           PulsePWM3
	cnt           counter
	tempResp      chan int
	scale         int
	desiredTemp16 int // °C/16
	lastPWM       int
	tempSensor    Sensor
}

func (w *waterHeaterControl) TempSensor() *Sensor {
	return &w.tempSensor
}

func (w *waterHeaterControl) DesiredTemp16() int {
	return atomic.LoadInt(&w.desiredTemp16)
}

func (w *waterHeaterControl) SetDesiredTemp16(temp16 int) {
	atomic.StoreInt(&w.desiredTemp16, temp16)
}

func (w *waterHeaterControl) LastPower() int {
	pwmMax := w.pwm.Max()
	return 24 * atomic.LoadInt(&w.lastPWM) / pwmMax
}

func (w *waterHeaterControl) Init(timPWM, timCnt *tim.TIM_Periph, pclk uint) {
	setupPulsePWM(timPWM, pclk, 500, 9999)
	w.pwm.Init(timPWM)
	w.cnt.Init(timCnt)
	w.tempResp = make(chan int, 1)
	w.SetDesiredTemp16(41 * 16) // °C/16
	w.scale = w.pwm.Max() / 1200
}

var water waterHeaterControl

func waterCntISR() {
	water.cnt.ClearIF()
	water.pwm.Pulse()
}

func waterPWMISR() {
	water.pwm.ClearIF()
	cnt := water.cnt.LoadAndReset()

	const coldWaterTemp16 = 15 * 16 // Typical input water temp. [°C/16]
	desiredTemp16 := atomic.LoadInt(&water.desiredTemp16)
	delta16 := desiredTemp16 - coldWaterTemp16

	if dev := water.tempSensor.Load(); dev.Type() != 0 {
		select {
		case owd.Cmd <- TempCmd{Dev: dev, Resp: water.tempResp}:
		default:
		}
		select {
		case temp16 := <-water.tempResp:
			if temp16 == InvalidTemp {
				break
			}
			delta16 += desiredTemp16 - temp16
		default:
			ledBlue.Set()
			delay.Loop(5e4)
			ledBlue.Clear()
		}
	}
	if delta16 < 0 {
		delta16 = 0
	} else if delta16 > 50*16 {
		delta16 = 50 * 16
	}
	pwm16 := delta16 * cnt * water.scale
	if pwm16 < 0 {
		pwm16 = 0
		ledBlue.Set()
		delay.Loop(5e4)
		ledBlue.Clear()
	}
	pwm := pwm16 / 16
	water.pwm.Set(pwm)
	atomic.StoreInt(&water.lastPWM, pwm)
}
<commit_msg>examples/l1-discovery/heating: Use dTemp/dt as correction to mesured temp.<commit_after>package main

import (
	"sync/atomic"

	"delay"

	"stm32/hal/raw/tim"
)

type counter struct {
	t *tim.TIM_Periph
}

func (c *counter) Init(t *tim.TIM_Periph) {
	c.t = t
	t.CKD().Store(2 << tim.CKDn)
	// Connect CC1 to TI1, setup input filter.
	t.CCMR1.StoreBits(tim.CC1S|tim.IC1F, 1<<tim.CC1Sn|0xf<<tim.IC1Fn)
	// Set falling edge detection, enable CC1.
	t.CCER.SetBits(tim.CC1P)
	// Set external clock mode 1, clock from filtered TI1.
	t.SMCR.StoreBits(tim.SMS|tim.TS, 7<<tim.SMSn|5<<tim.TSn)
	// Use CC2 to generate an interrupt after first count.
	t.CCR2.Store(1)
	t.DIER.Store(tim.CC2IE)
	t.CEN().Set()
}

func (c *counter) Load() int {
	return int(c.t.CNT.Load())
}

func (c *counter) LoadAndReset() int {
	cnt := int(c.t.CNT.Load())
	c.t.EGR.Store(tim.UG)
	return cnt
}

func (c *counter) ClearIF() {
	c.t.SR.Store(0)
}

type waterHeaterControl struct {
	pwm           PulsePWM3
	cnt           counter
	tempResp      chan int
	scale         int
	desiredTemp16 int // °C/16
	lastTemp16    int
	lastPWM       int
	tempSensor    Sensor
}

func (w *waterHeaterControl) TempSensor() *Sensor {
	return &w.tempSensor
}

func (w *waterHeaterControl) DesiredTemp16() int {
	return atomic.LoadInt(&w.desiredTemp16)
}

func (w *waterHeaterControl) SetDesiredTemp16(temp16 int) {
	atomic.StoreInt(&w.desiredTemp16, temp16)
}

func (w *waterHeaterControl) LastPower() int {
	pwmMax := w.pwm.Max()
	return 24 * atomic.LoadInt(&w.lastPWM) / pwmMax
}

const waterPWMPeriod = 500 // ms

func (w *waterHeaterControl) Init(timPWM, timCnt *tim.TIM_Periph, pclk uint) {
	setupPulsePWM(timPWM, pclk, waterPWMPeriod, 9999)
	w.pwm.Init(timPWM)
	w.cnt.Init(timCnt)
	w.tempResp = make(chan int, 1)
	w.SetDesiredTemp16(41 * 16) // °C/16
	w.lastTemp16 = 20 * 16      // °C/16
	w.scale = w.pwm.Max() / 1200
}

var water waterHeaterControl

func waterCntISR() {
	water.cnt.ClearIF()
	water.pwm.Pulse()
}

func waterPWMISR() {
	water.pwm.ClearIF()
	cnt := water.cnt.LoadAndReset()

	const coldWaterTemp16 = 15 * 16 // Typical input water temp. [°C/16]
	desiredTemp16 := atomic.LoadInt(&water.desiredTemp16)
	delta16 := desiredTemp16 - coldWaterTemp16

	if dev := water.tempSensor.Load(); dev.Type() != 0 {
		select {
		case owd.Cmd <- TempCmd{Dev: dev, Resp: water.tempResp}:
		default:
		}
		select {
		case temp16 := <-water.tempResp:
			if temp16 == InvalidTemp {
				break
			}
			dTemp16 := temp16 - water.lastTemp16
			water.lastTemp16 = temp16
			// Use dTemp/dt as correction to temp16.
			delta16 += desiredTemp16 - (temp16 + 128*dTemp16/waterPWMPeriod)
		default:
			ledBlue.Set()
			delay.Loop(5e4)
			ledBlue.Clear()
		}
	}
	if delta16 < 0 {
		delta16 = 0
	} else if delta16 > 50*16 {
		delta16 = 50 * 16
	}
	pwm16 := delta16 * cnt * water.scale
	if pwm16 < 0 {
		pwm16 = 0
		ledBlue.Set()
		delay.Loop(5e4)
		ledBlue.Clear()
	}
	pwm := pwm16 / 16
	water.pwm.Set(pwm)
	atomic.StoreInt(&water.lastPWM, pwm)
}
<|endoftext|>


<commit_before>// run

// Copyright 2015 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.

// Test control flow

package main

// nor_ssa calculates NOR(a, b).
// It is implemented in a way that generates
// phi control values.
func nor_ssa(a, b bool) bool {
	var c bool
	if a {
		c = true
	}
	if b {
		c = true
	}
	if c {
		return false
	}
	return true
}

func testPhiControl() {
	tests := [...][3]bool{ // a, b, want
		{false, false, true},
		{true, false, false},
		{false, true, false},
		{true, true, false},
	}
	for _, test := range tests {
		a, b := test[0], test[1]
		got := nor_ssa(a, b)
		want := test[2]
		if want != got {
			print("nor(", a, ", ", b, ")=", want, " got ", got, "\n")
			failed = true
		}
	}
}

func emptyRange_ssa(b []byte) bool {
	for _, x := range b {
		_ = x
	}
	return true
}

func testEmptyRange() {
	if !emptyRange_ssa([]byte{}) {
		println("emptyRange_ssa([]byte{})=false, want true")
		failed = true
	}
}

func switch_ssa(a int) int {
	ret := 0
	switch a {
	case 5:
		ret += 5
	case 4:
		ret += 4
	case 3:
		ret += 3
	case 2:
		ret += 2
	case 1:
		ret += 1
	}
	return ret

}

func fallthrough_ssa(a int) int {
	ret := 0
	switch a {
	case 5:
		ret++
		fallthrough
	case 4:
		ret++
		fallthrough
	case 3:
		ret++
		fallthrough
	case 2:
		ret++
		fallthrough
	case 1:
		ret++
	}
	return ret

}

func testFallthrough() {
	for i := 0; i < 6; i++ {
		if got := fallthrough_ssa(i); got != i {
			println("fallthrough_ssa(i) =", got, "wanted", i)
		}
	}
}

func testSwitch() {
	for i := 0; i < 6; i++ {
		if got := switch_ssa(i); got != i {
			println("switch_ssa(i) =", got, "wanted", i)
		}
	}
}

var failed = false

func main() {
	testPhiControl()
	testEmptyRange()

	testSwitch()
	testFallthrough()

	if failed {
		panic("failed")
	}
}
<commit_msg>[dev.ssa] cmd/compile: make test panic on failure<commit_after>// run

// Copyright 2015 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.

// Test control flow

package main

// nor_ssa calculates NOR(a, b).
// It is implemented in a way that generates
// phi control values.
func nor_ssa(a, b bool) bool {
	var c bool
	if a {
		c = true
	}
	if b {
		c = true
	}
	if c {
		return false
	}
	return true
}

func testPhiControl() {
	tests := [...][3]bool{ // a, b, want
		{false, false, true},
		{true, false, false},
		{false, true, false},
		{true, true, false},
	}
	for _, test := range tests {
		a, b := test[0], test[1]
		got := nor_ssa(a, b)
		want := test[2]
		if want != got {
			print("nor(", a, ", ", b, ")=", want, " got ", got, "\n")
			failed = true
		}
	}
}

func emptyRange_ssa(b []byte) bool {
	for _, x := range b {
		_ = x
	}
	return true
}

func testEmptyRange() {
	if !emptyRange_ssa([]byte{}) {
		println("emptyRange_ssa([]byte{})=false, want true")
		failed = true
	}
}

func switch_ssa(a int) int {
	ret := 0
	switch a {
	case 5:
		ret += 5
	case 4:
		ret += 4
	case 3:
		ret += 3
	case 2:
		ret += 2
	case 1:
		ret += 1
	}
	return ret

}

func fallthrough_ssa(a int) int {
	ret := 0
	switch a {
	case 5:
		ret++
		fallthrough
	case 4:
		ret++
		fallthrough
	case 3:
		ret++
		fallthrough
	case 2:
		ret++
		fallthrough
	case 1:
		ret++
	}
	return ret

}

func testFallthrough() {
	for i := 0; i < 6; i++ {
		if got := fallthrough_ssa(i); got != i {
			println("fallthrough_ssa(i) =", got, "wanted", i)
			failed = true
		}
	}
}

func testSwitch() {
	for i := 0; i < 6; i++ {
		if got := switch_ssa(i); got != i {
			println("switch_ssa(i) =", got, "wanted", i)
			failed = true
		}
	}
}

var failed = false

func main() {
	testPhiControl()
	testEmptyRange()

	testSwitch()
	testFallthrough()

	if failed {
		panic("failed")
	}
}
<|endoftext|>