<commit_before>package main

import "C"
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"github.com/akavel/winq"
)

const (
	IRSDK_MEMMAPFILENAME     = "Local\\IRSDKMemMapFileName"
	IRSDK_DATAVALIDEVENTNAME = "Local\\IRSDKDataValidEvent"
	SECTION_MAP_READ         = 4
	FILE_MAP_READ            = SECTION_MAP_READ
	INT_MAX                  = 2147483647
	SYNCHRONIZE              = 1048576

	IRSDK_MAX_BUFS   = 4
	IRSDK_MAX_STRING = 32
	// descriptions can be longer than max_string!
	IRSDK_MAX_DESC = 64

	irsdk_stConnected = 1
	TIMEOUT           = time.Duration(30) // timeout after 30 seconds with no communication
)

const (
	// 1 byte
	irsdk_char = iota
	irsdk_bool = iota

	// 4 bytes
	irsdk_int      = iota
	irsdk_bitField = iota
	irsdk_float    = iota

	// 8 bytes
	irsdk_double = iota
)

type irsdk_varBuf struct {
	TickCount C.int    // used to detect changes in data
	BufOffset C.int    // offset from header
	Pad       [2]C.int // (16 byte align)
}

type irsdk_header struct {
	Ver      C.int // api version 1 for now
	Status   C.int // bitfield using irsdk_StatusField
	TickRate C.int // ticks per second (60 or 360 etc)

	// session information, updated periodicaly
	SessionInfoUpdate C.int // Incremented when session info changes
	SessionInfoLen    C.int // Length in bytes of session info string
	SessionInfoOffset C.int // Session info, encoded in YAML format

	// State data, output at tickRate

	NumVars         C.int // length of array pointed to by varHeaderOffset
	VarHeaderOffset C.int // offset to irsdk_varHeader[numVars] array, Describes the variables recieved in varBuf

	NumBuf C.int // <= IRSDK_MAX_BUFS (3 for now)
	BufLen C.int // length in bytes for one line
	Pad    [1]C.int
	VarBuf [IRSDK_MAX_BUFS]irsdk_varBuf
}

type irsdk_varHeader struct {
	Type   C.int // irsdk_VarType
	Offset C.int // offset fron start of buffer row
	Count  C.int // number of entrys (array)
	// so length in bytes would be irsdk_VarTypeBytes[type] * count
	Pad [1]C.int // (16 byte align)

	Name [IRSDK_MAX_STRING]byte
	Desc [IRSDK_MAX_DESC]byte
	Unit [IRSDK_MAX_STRING]byte // something like "kg/m^2"
}

func irsdk_getVarHeaderPtr() *irsdk_varHeader {
	// if isInitialized {
	// 	varHeaderoffset := unsafe.Sizeof(pHeader.varHeaderOffset)
	// 	varHeader := (*irsdk_varHeader)(unsafe.Pointer(pSharedMem) + varHeaderoffset)

	// 	fmt.Printf("%+v\n", varHeader)
	// 	fmt.Println(string(varHeader.name[:10]))
	// 	return nil
	// }
	return nil
}

// func irsdk_getVarHeaderEntry(index int) *irsdk_varHeader {
// 	if isInitialized {
// 		if index >= 0 && index < (int)(pHeader.numVars) {

// 			varHeader := (*irsdk_varHeader)((unsafe.Pointer((uintptr(pSharedMem) + unsafe.Sizeof(pHeader.varHeaderOffset)))))
// 			fmt.Printf("%+v\n", varHeader.name)
// 			fmt.Println(string(varHeader.name[:10]))
// 			fmt.Println(string(varHeader.desc[:10]))
// 			fmt.Println(string(varHeader.unit[:10]))
// 			return nil
// 			// return &((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset))[index];
// 		}
// 	}
// 	return nil
// }

var pHeader *irsdk_header
var isInitialized bool
var lastValidTime time.Time
var timeout time.Duration
var pSharedMem []byte
var sharedMemPtr uintptr
var lastTickCount = INT_MAX

func main() {
	// _, err := irsdk_startup()
	// if err != nil {
	// 	log.Fatal(err)
	// }

	for i := 0; i < 90000; i++ {
		data, success := irsdk_getNewData()
		fmt.Println("success: ", success)
		fmt.Println("len(data): ", len(data))
	}

	return

	// fmt.Println("connected: ", irsdk_isConnected())
	// byteArray := irsdk_getSessionInfoStr()
	// s := string(byteArray[:])
	// fmt.Println("irsdk_getSessionInfoStr: ", s)

}

func irsdk_startup() (bool, error) {
	var try winq.Try

	hMemMapFile := try.N("OpenFileMappingW", FILE_MAP_READ, false, syscall.StringToUTF16Ptr(IRSDK_MEMMAPFILENAME))
	if try.Err != nil {
		return false, try.Err
	}

	sharedMemPtr = try.N("MapViewOfFile", hMemMapFile, syscall.FILE_MAP_READ, 0, 0, 0)

	err := updateSharedMem()
	if err != nil {
		return false, err
	}

	hDataValidEvent := try.N("OpenEvent", SYNCHRONIZE, false, syscall.StringToUTF16Ptr(IRSDK_DATAVALIDEVENTNAME))

	if hDataValidEvent > 0 {
		isInitialized = true
		return isInitialized, nil
	}

	return false, nil
}

func irsdk_getSessionInfoStr() []byte {
	if isInitialized {
		return pSharedMem[pHeader.SessionInfoOffset:pHeader.SessionInfoLen]
	}
	return nil
}

func irsdk_isConnected() bool {
	if isInitialized {
		elapsed := time.Now().Sub(lastValidTime)
		fmt.Println("elapsed: ", elapsed)
		fmt.Println("timeout: ", timeout)
		fmt.Println("pHeader.status&irsdk_stConnected: ", pHeader.Status&irsdk_stConnected)
		if (pHeader.Status&irsdk_stConnected) > 0 && (elapsed < timeout) {
			return true
		}
	}

	return false
}

// func irsdk_varHeader *irsdk_getVarHeaderPtr()
// {
// 	if(isInitialized)
// 	{
// 		return ((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset));
// 	}
// 	return NULL;
// }

func irsdk_getNewData() ([]byte, bool) {
	var data []byte
	returnData := true

	if !isInitialized {
		success, _ := irsdk_startup()
		if !success {
			return nil, false
		}
	}

	// if sim is not active, then no new data
	if (int(pHeader.Status) & irsdk_stConnected) == 0 {
		lastTickCount = INT_MAX
		return nil, false
	}

	latest := 0
	for i := 0; i < int(pHeader.NumBuf); i++ {
		fmt.Println("i: ", i)
		fmt.Println("pHeader.VarBuf[latest].TickCount: ", pHeader.VarBuf[latest].TickCount)
		fmt.Println("pHeader.VarBuf[i].TickCount: ", pHeader.VarBuf[i].TickCount)
		if pHeader.VarBuf[latest].TickCount < pHeader.VarBuf[i].TickCount {
			latest = i
		}
	}

	fmt.Println("latest: ", latest)

	fmt.Println("lastTickCount: ", lastTickCount)
	fmt.Println("pHeader.VarBuf[latest].TickCount: ", int(pHeader.VarBuf[latest].TickCount))

	// if newer than last recieved, than report new data
	if lastTickCount < int(pHeader.VarBuf[latest].TickCount) {
		// if asked to retrieve the data
		if returnData == true {

			for count := 0; count < 2; count++ {
				curTickCount := int(pHeader.VarBuf[latest].TickCount)
				// memcpy(data, pSharedMem + pHeader->varBuf[latest].bufOffset, pHeader->bufLen)
				startByte := int(pHeader.VarBuf[latest].BufOffset)
				startByte = 1358715
				endByte := startByte + int(pHeader.BufLen)
				fmt.Println("startByte: ", startByte)
				fmt.Println("endByte: ", endByte)
				fmt.Println("len(pSharedMem): ", len(pSharedMem))
				data = pSharedMem[startByte:endByte]
				fmt.Println("len(data): ", len(data))
				// fmt.Println("data: ", string(data[:]))

				if curTickCount == int(pHeader.VarBuf[latest].TickCount) {
					lastTickCount = curTickCount
					lastValidTime = time.Now()
					return data, true
				}
			}
			// if here, the data changed out from under us.
			return nil, false
		} else {
			lastTickCount = int(pHeader.VarBuf[latest].TickCount)
			lastValidTime = time.Now()
			return data, true
		}
	} else if lastTickCount > int(pHeader.VarBuf[latest].TickCount) {
		// if older than last recieved, than reset, we probably disconnected
		lastTickCount = int(pHeader.VarBuf[latest].TickCount)
		return nil, false
	}
	// else the same, and nothing changed this tick

	return nil, false
}

func updateSharedMem() error {
	pHeader = (*irsdk_header)(unsafe.Pointer(sharedMemPtr))

	pSharedMem = (*[1 << 30]byte)(unsafe.Pointer(sharedMemPtr))[:]
	return nil

	// This is also an option:

	// create a io.Reader
	endByte := unsafe.Sizeof(*pHeader)
	b := bytes.NewBuffer(pSharedMem[:endByte])
	// read []byte and convert it into irsd_header
	pHeader = &irsdk_header{}
	err := binary.Read(b, binary.LittleEndian, pHeader)
	return err
}
<commit_msg>Found the culprit<commit_after>package main

import "C"
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"github.com/akavel/winq"
)

const (
	IRSDK_MEMMAPFILENAME     = "Local\\IRSDKMemMapFileName"
	IRSDK_DATAVALIDEVENTNAME = "Local\\IRSDKDataValidEvent"
	SECTION_MAP_READ         = 4
	FILE_MAP_READ            = SECTION_MAP_READ
	INT_MAX                  = 2147483647
	SYNCHRONIZE              = 1048576

	IRSDK_MAX_BUFS   = 4
	IRSDK_MAX_STRING = 32
	// descriptions can be longer than max_string!
	IRSDK_MAX_DESC = 64

	irsdk_stConnected = 1
	TIMEOUT           = time.Duration(30) // timeout after 30 seconds with no communication
)

const (
	// 1 byte
	irsdk_char = iota
	irsdk_bool = iota

	// 4 bytes
	irsdk_int      = iota
	irsdk_bitField = iota
	irsdk_float    = iota

	// 8 bytes
	irsdk_double = iota
)

type irsdk_varBuf struct {
	TickCount C.int    // used to detect changes in data
	BufOffset C.int    // offset from header
	Pad       [2]C.int // (16 byte align)
}

type irsdk_header struct {
	Ver      C.int // api version 1 for now
	Status   C.int // bitfield using irsdk_StatusField
	TickRate C.int // ticks per second (60 or 360 etc)

	// session information, updated periodicaly
	SessionInfoUpdate C.int // Incremented when session info changes
	SessionInfoLen    C.int // Length in bytes of session info string
	SessionInfoOffset C.int // Session info, encoded in YAML format

	// State data, output at tickRate

	NumVars         C.int // length of array pointed to by varHeaderOffset
	VarHeaderOffset C.int // offset to irsdk_varHeader[numVars] array, Describes the variables recieved in varBuf

	NumBuf C.int    // <= IRSDK_MAX_BUFS (3 for now)
	BufLen C.int    // length in bytes for one line
	Pad1   [2]C.int // (16 byte align)
	VarBuf [IRSDK_MAX_BUFS]irsdk_varBuf
}

type irsdk_varHeader struct {
	Type   C.int // irsdk_VarType
	Offset C.int // offset fron start of buffer row
	Count  C.int // number of entrys (array)
	// so length in bytes would be irsdk_VarTypeBytes[type] * count
	Pad [1]C.int // (16 byte align)

	Name [IRSDK_MAX_STRING]byte
	Desc [IRSDK_MAX_DESC]byte
	Unit [IRSDK_MAX_STRING]byte // something like "kg/m^2"
}

func irsdk_getVarHeaderPtr() *irsdk_varHeader {
	// if isInitialized {
	// 	varHeaderoffset := unsafe.Sizeof(pHeader.varHeaderOffset)
	// 	varHeader := (*irsdk_varHeader)(unsafe.Pointer(pSharedMem) + varHeaderoffset)

	// 	fmt.Printf("%+v\n", varHeader)
	// 	fmt.Println(string(varHeader.name[:10]))
	// 	return nil
	// }
	return nil
}

// func irsdk_getVarHeaderEntry(index int) *irsdk_varHeader {
// 	if isInitialized {
// 		if index >= 0 && index < (int)(pHeader.numVars) {

// 			varHeader := (*irsdk_varHeader)((unsafe.Pointer((uintptr(pSharedMem) + unsafe.Sizeof(pHeader.varHeaderOffset)))))
// 			fmt.Printf("%+v\n", varHeader.name)
// 			fmt.Println(string(varHeader.name[:10]))
// 			fmt.Println(string(varHeader.desc[:10]))
// 			fmt.Println(string(varHeader.unit[:10]))
// 			return nil
// 			// return &((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset))[index];
// 		}
// 	}
// 	return nil
// }

var pHeader *irsdk_header
var isInitialized bool
var lastValidTime time.Time
var timeout time.Duration
var pSharedMem []byte
var sharedMemPtr uintptr
var lastTickCount = INT_MAX

func main() {
	// _, err := irsdk_startup()
	// if err != nil {
	// 	log.Fatal(err)
	// }

	for i := 0; i < 90000; i++ {
		data, success := irsdk_getNewData()
		fmt.Println("success: ", success)
		fmt.Println("len(data): ", len(data))
	}

	return

	// fmt.Println("connected: ", irsdk_isConnected())
	// byteArray := irsdk_getSessionInfoStr()
	// s := string(byteArray[:])
	// fmt.Println("irsdk_getSessionInfoStr: ", s)

}

func irsdk_startup() (bool, error) {
	var try winq.Try

	hMemMapFile := try.N("OpenFileMappingW", FILE_MAP_READ, false, syscall.StringToUTF16Ptr(IRSDK_MEMMAPFILENAME))
	if try.Err != nil {
		return false, try.Err
	}

	sharedMemPtr = try.N("MapViewOfFile", hMemMapFile, syscall.FILE_MAP_READ, 0, 0, 0)

	err := updateSharedMem()
	if err != nil {
		return false, err
	}

	hDataValidEvent := try.N("OpenEvent", SYNCHRONIZE, false, syscall.StringToUTF16Ptr(IRSDK_DATAVALIDEVENTNAME))

	if hDataValidEvent > 0 {
		isInitialized = true
		return isInitialized, nil
	}

	return false, nil
}

func irsdk_getSessionInfoStr() []byte {
	if isInitialized {
		return pSharedMem[pHeader.SessionInfoOffset:pHeader.SessionInfoLen]
	}
	return nil
}

func irsdk_isConnected() bool {
	if isInitialized {
		elapsed := time.Now().Sub(lastValidTime)
		fmt.Println("elapsed: ", elapsed)
		fmt.Println("timeout: ", timeout)
		fmt.Println("pHeader.status&irsdk_stConnected: ", pHeader.Status&irsdk_stConnected)
		if (pHeader.Status&irsdk_stConnected) > 0 && (elapsed < timeout) {
			return true
		}
	}

	return false
}

// func irsdk_varHeader *irsdk_getVarHeaderPtr()
// {
// 	if(isInitialized)
// 	{
// 		return ((irsdk_varHeader*)(pSharedMem + pHeader->varHeaderOffset));
// 	}
// 	return NULL;
// }

func irsdk_getNewData() ([]byte, bool) {
	var data []byte
	returnData := true

	if !isInitialized {
		success, _ := irsdk_startup()
		if !success {
			return nil, false
		}
	}

	// if sim is not active, then no new data
	if (int(pHeader.Status) & irsdk_stConnected) == 0 {
		lastTickCount = INT_MAX
		return nil, false
	}

	latest := 0
	for i := 0; i < int(pHeader.NumBuf); i++ {
		fmt.Println("i: ", i)
		fmt.Println("pHeader.VarBuf[latest].TickCount: ", pHeader.VarBuf[latest].TickCount)
		fmt.Println("pHeader.VarBuf[i].TickCount: ", pHeader.VarBuf[i].TickCount)
		if pHeader.VarBuf[latest].TickCount < pHeader.VarBuf[i].TickCount {
			latest = i
		}
	}

	fmt.Println("latest: ", latest)

	fmt.Println("lastTickCount: ", lastTickCount)
	fmt.Println("pHeader.VarBuf[latest].TickCount: ", int(pHeader.VarBuf[latest].TickCount))

	// if newer than last recieved, than report new data
	if lastTickCount < int(pHeader.VarBuf[latest].TickCount) {
		// if asked to retrieve the data
		if returnData == true {

			for count := 0; count < 2; count++ {
				curTickCount := int(pHeader.VarBuf[latest].TickCount)
				// memcpy(data, pSharedMem + pHeader->varBuf[latest].bufOffset, pHeader->bufLen)
				startByte := int(pHeader.VarBuf[latest].BufOffset)
				startByte = 1358715
				endByte := startByte + int(pHeader.BufLen)
				fmt.Println("startByte: ", startByte)
				fmt.Println("endByte: ", endByte)
				fmt.Println("len(pSharedMem): ", len(pSharedMem))
				data = pSharedMem[startByte:endByte]
				fmt.Println("len(data): ", len(data))
				// fmt.Println("data: ", string(data[:]))

				if curTickCount == int(pHeader.VarBuf[latest].TickCount) {
					lastTickCount = curTickCount
					lastValidTime = time.Now()
					return data, true
				}
			}
			// if here, the data changed out from under us.
			return nil, false
		} else {
			lastTickCount = int(pHeader.VarBuf[latest].TickCount)
			lastValidTime = time.Now()
			return data, true
		}
	} else if lastTickCount > int(pHeader.VarBuf[latest].TickCount) {
		// if older than last recieved, than reset, we probably disconnected
		lastTickCount = int(pHeader.VarBuf[latest].TickCount)
		return nil, false
	}
	// else the same, and nothing changed this tick

	return nil, false
}

func updateSharedMem() error {
	pHeader = (*irsdk_header)(unsafe.Pointer(sharedMemPtr))

	pSharedMem = (*[1 << 30]byte)(unsafe.Pointer(sharedMemPtr))[:]
	return nil

	// This is also an option:

	// create a io.Reader
	endByte := unsafe.Sizeof(*pHeader)
	b := bytes.NewBuffer(pSharedMem[:endByte])
	// read []byte and convert it into irsd_header
	pHeader = &irsdk_header{}
	err := binary.Read(b, binary.LittleEndian, pHeader)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	//"fmt"
	"io"
	//"io/ioutil"
	"log"
	"net/http"
)

var addr = flag.String("127.0.0.1", ":1718", "http service address") // Q=17, R=18

func main() {
	flag.Parse()
	//http.Handle("/", http.HandlerFunc(QR))
	err := http.ListenAndServe(*addr, http.HandlerFunc(mainHandler))
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

func mainHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		//io.WriteString(w, "please use post method.
")
		//io.WriteString(w, req.URL.Path)
		//log.Println("https://weixin.qq.com" + req.URL.Path)
		newReq, err := http.NewRequest(req.Method, "https://weixin.qq.com"+req.URL.Path, nil)
		//newReq.URL.Host = "weixin.qq.com"
		//newReq.Host = newReq.URL.Host
		//newReq.URL.Path = req.URL.Path

		client := &http.Client{}
		resp, err := client.Do(newReq)

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

		defer resp.Body.Close()

		//body, err := ioutil.ReadAll(resp.Body)
		//log.Println(string(body))

		io.Copy(w, resp.Body)

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

/*
func QR(w http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		io.WriteString(w, "please use post method.")
		//templ.Execute(w, req.FormValue("s"))
		return
	}
}

const templateStr = `

<title>QR Link Generator</title>

{{if .}}

{{.}}

{{end}}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>

`
*/
<commit_msg>done proxy part. process to sign part<commit_after>package main

import (
	"flag"
	//"fmt"
	"io"
	//"io/ioutil"
	"log"
	"net/http"
)

var addr = flag.String("127.0.0.1", ":1718", "http service address") // Q=17, R=18

func main() {
	flag.Parse()
	//http.Handle("/", http.HandlerFunc(QR))
	err := http.ListenAndServe(*addr, http.HandlerFunc(mainHandler))
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}

func mainHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		//io.WriteString(w, "please use post method.
")
		//io.WriteString(w, req.URL.Path)
		log.Println(req.URL.String())
		newReq, err := http.NewRequest(req.Method, req.URL.String(), nil)
		newReq.Header = req.Header
		newReq.URL.Host = "api.mch.weixin.qq.com"
		newReq.Host = newReq.URL.Host
		newReq.URL.Scheme = "https"
		//newReq.URL.Path = req.URL.Path

		client := &http.Client{}
		resp, err := client.Do(newReq)

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

		log.Println(resp.StatusCode)

		defer resp.Body.Close()

		//body, err := ioutil.ReadAll(resp.Body)
		//log.Println(string(body))

		//resp.Write(w)
		io.Copy(w, resp.Body)

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

/*
func QR(w http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		io.WriteString(w, "please use post method.")
		//templ.Execute(w, req.FormValue("s"))
		return
	}
}

const templateStr = `

<title>QR Link Generator</title>

{{if .}}

{{.}}

{{end}}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>

`
*/
<|endoftext|>


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

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

package apd

import (
	"math"

	"github.com/pkg/errors"
)

// loop provides a looping structure that determines when a given computation
// on an *Decimal has converged. It was adapted from robpike.io/ivy/value's loop
// implementation.
type loop struct {
	name          string   // The name of the function we are evaluating.
	i             uint64   // Loop count.
	maxIterations uint64   // When to give up.
	stallCount    int      // Iterations since |delta| changed more than threshold.
	arg           *Decimal // original argument to function; only used for diagnostic.
	prevZ         *Decimal // Result from the previous iteration.
	delta         *Decimal // |Change| from previous iteration.
	stallThresh   *Decimal // The maximum |delta| to be considered a stall.
}

const digitsToBitsRatio = math.Ln10 / math.Ln2

// newLoop returns a new loop checker. The arguments are the name
// of the function being evaluated, the argument to the function,
// and the desired scale of the result, and the iterations
// per bit.
func newLoop(name string, x *Decimal, itersPerBit int) *loop {
	bits := x.Coeff.BitLen()
	incrPrec := float64(x.Precision) + float64(x.Exponent)
	if incrPrec > 0 {
		bits += int(incrPrec * digitsToBitsRatio)
	}
	if scaleBits := int(float64(x.Precision) * digitsToBitsRatio); scaleBits > bits {
		bits = scaleBits
	}
	l := &loop{
		name:          name,
		maxIterations: 10 + uint64(itersPerBit*bits),
	}
	l.arg = new(Decimal)
	l.arg.Set(x)
	l.stallThresh = New(1, -int32(x.Precision+1))
	l.prevZ = new(Decimal)
	l.delta = new(Decimal)
	p := x.Precision + 2
	l.prevZ.Precision = p
	l.delta.Precision = p
	return l
}

// done reports whether the loop is done. If it does not converge
// after the maximum number of iterations, it returns an error.
func (l *loop) done(z *Decimal) (bool, error) {
	l.delta.Sub(l.prevZ, z)
	switch l.delta.Sign() {
	case 0:
		return true, nil
	case -1:
		l.delta.Neg(l.delta)
	}
	if c, err := l.delta.Cmp(l.stallThresh); err != nil {
		return false, err
	} else if c < 0 {
		l.stallCount++
		if l.stallCount > 2 {
			return true, nil
		}
	} else {
		l.stallCount = 0
	}
	l.i++
	if l.i == l.maxIterations {
		return false, errors.Errorf("%s %s: did not converge after %d iterations; prev,last result %s,%s delta %s", l.name, l.arg.String(), l.maxIterations, z.String(), l.prevZ.String(), l.delta.String())
	}
	l.prevZ.Set(z)
	return false, nil
}
<commit_msg>Remove double license<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

package apd

import (
	"math"

	"github.com/pkg/errors"
)

// loop provides a looping structure that determines when a given computation
// on an *Decimal has converged. It was adapted from robpike.io/ivy/value's loop
// implementation.
type loop struct {
	name          string   // The name of the function we are evaluating.
	i             uint64   // Loop count.
	maxIterations uint64   // When to give up.
	stallCount    int      // Iterations since |delta| changed more than threshold.
	arg           *Decimal // original argument to function; only used for diagnostic.
	prevZ         *Decimal // Result from the previous iteration.
	delta         *Decimal // |Change| from previous iteration.
	stallThresh   *Decimal // The maximum |delta| to be considered a stall.
}

const digitsToBitsRatio = math.Ln10 / math.Ln2

// newLoop returns a new loop checker. The arguments are the name
// of the function being evaluated, the argument to the function,
// and the desired scale of the result, and the iterations
// per bit.
func newLoop(name string, x *Decimal, itersPerBit int) *loop {
	bits := x.Coeff.BitLen()
	incrPrec := float64(x.Precision) + float64(x.Exponent)
	if incrPrec > 0 {
		bits += int(incrPrec * digitsToBitsRatio)
	}
	if scaleBits := int(float64(x.Precision) * digitsToBitsRatio); scaleBits > bits {
		bits = scaleBits
	}
	l := &loop{
		name:          name,
		maxIterations: 10 + uint64(itersPerBit*bits),
	}
	l.arg = new(Decimal)
	l.arg.Set(x)
	l.stallThresh = New(1, -int32(x.Precision+1))
	l.prevZ = new(Decimal)
	l.delta = new(Decimal)
	p := x.Precision + 2
	l.prevZ.Precision = p
	l.delta.Precision = p
	return l
}

// done reports whether the loop is done. If it does not converge
// after the maximum number of iterations, it returns an error.
func (l *loop) done(z *Decimal) (bool, error) {
	l.delta.Sub(l.prevZ, z)
	switch l.delta.Sign() {
	case 0:
		return true, nil
	case -1:
		l.delta.Neg(l.delta)
	}
	if c, err := l.delta.Cmp(l.stallThresh); err != nil {
		return false, err
	} else if c < 0 {
		l.stallCount++
		if l.stallCount > 2 {
			return true, nil
		}
	} else {
		l.stallCount = 0
	}
	l.i++
	if l.i == l.maxIterations {
		return false, errors.Errorf("%s %s: did not converge after %d iterations; prev,last result %s,%s delta %s", l.name, l.arg.String(), l.maxIterations, z.String(), l.prevZ.String(), l.delta.String())
	}
	l.prevZ.Set(z)
	return false, nil
}
<|endoftext|>


<commit_before>package luar // import "layeh.com/gopher-luar"

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

// New creates and returns a new lua.LValue for the given value.
//
// The following table shows how Go types are converted to Lua types:
//  Kind            gopher-lua Type  Custom Metatable
//  --------------------------------------------------
//  nil             LNil             No
//  Bool            LBool            No
//  Int             LNumber          No
//  Int8            LNumber          No
//  Int16           LNumber          No
//  Int32           LNumber          No
//  Int64           LNumber          No
//  Uint            LNumber          No
//  Uint8           LNumber          No
//  Uint16          LNumber          No
//  Uint32          LNumber          No
//  Uint64          LNumber          No
//  Uintptr         *LUserData       No
//  Float32         LNumber          No
//  Float64         LNumber          No
//  Complex64       *LUserData       No
//  Complex128      *LUserData       No
//  Array           *LUserData       Yes
//  Chan            *LUserData       Yes
//  Func            *LFunction       No
//  Map             *LUserData       Yes
//  Ptr             *LUserData       Yes
//  Slice           *LUserData       Yes
//  String          LString          No
//  Struct          *LUserData       Yes
//  UnsafePointer   *LUserData       No
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = getMetatableFromValue(L, val)
		return ud
	case reflect.Func:
		return funcWrapper(L, val, false)
	case reflect.String:
		return lua.LString(val.String())
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the returned lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = getTypeMetatable(L, val)

	return ud
}

type conversionError struct {
	Lua  lua.LValue
	Hint reflect.Type
}

func (c conversionError) Error() string {
	if _, isNil := c.Lua.(*lua.LNilType); isNil {
		return fmt.Sprintf("cannot use nil as type %s", c.Hint)
	}

	var val interface{}

	if userData, ok := c.Lua.(*lua.LUserData); ok {
		if reflectValue, ok := userData.Value.(reflect.Value); ok {
			val = reflectValue.Interface()
		} else {
			val = userData.Value
		}
	} else {
		val = c.Lua
	}

	return fmt.Sprintf("cannot use %v (type %T) as type %s", val, val, c.Hint)
}

type structFieldError struct {
	Field string
	Type  reflect.Type
}

func (s structFieldError) Error() string {
	return `type ` + s.Type.String() + ` has no field ` + s.Field
}

func lValueToReflect(L *lua.LState, v lua.LValue, hint reflect.Type, tryConvertPtr *bool) (reflect.Value, error) {
	if hint.Implements(refTypeLuaLValue) {
		return reflect.ValueOf(v), nil
	}

	isPtr := false

	switch converted := v.(type) {
	case lua.LBool:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(bool(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LChannel:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LNumber:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(float64(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LFunction:
		switch {
		case hint == refTypeEmptyIface:
			inOut := []reflect.Type{
				reflect.SliceOf(refTypeEmptyIface),
			}
			hint = reflect.FuncOf(inOut, inOut, true)
		case hint.Kind() != reflect.Func:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}

		fn := func(args []reflect.Value) []reflect.Value {
			thread, _ := L.NewThread()
			thread.Push(converted)

			varadicCount := 0

			for i, arg := range args {
				if hint.IsVariadic() && i+1 == len(args) {
					// arg is the varadic slice
					varadicCount = arg.Len()
					for j := 0; j < varadicCount; j++ {
						arg := arg.Index(j)
						if !arg.CanInterface() {
							thread.Pop(i + j + 1)
							panic(fmt.Errorf("unable to Interface argument %d", i+j))
						}
						thread.Push(New(thread, arg.Interface()))
					}
					// recount for varadic slice that appeared
					varadicCount--
					break
				}

				if !arg.CanInterface() {
					thread.Pop(i + 1)
					panic(fmt.Errorf("unable to Interface argument %d", i))
				}
				thread.Push(New(thread, arg.Interface()))
			}

			thread.Call(len(args)+varadicCount, hint.NumOut())
			defer thread.Pop(hint.NumOut())

			ret := make([]reflect.Value, hint.NumOut())

			for i := 0; i < hint.NumOut(); i++ {
				outHint := hint.Out(i)
				var err error
				ret[i], err = lValueToReflect(thread, thread.Get(-hint.NumOut()+i), outHint, nil)
				if err != nil {
					panic(err)
				}
			}

			return ret
		}
		return reflect.MakeFunc(hint, fn), nil
	case *lua.LNilType:
		switch hint.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
			return reflect.Zero(hint), nil
		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LState:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LString:
		val := reflect.ValueOf(string(converted))
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LTable:
		if hint == refTypeEmptyIface {
			hint = reflect.MapOf(refTypeEmptyIface, refTypeEmptyIface)
		}

		switch {
		case hint.Kind() == reflect.Slice:
			elemType := hint.Elem()
			length := converted.Len()
			s := reflect.MakeSlice(hint, length, length)

			for i := 0; i < length; i++ {
				value := converted.RawGetInt(i + 1)
				elemValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.Index(i).Set(elemValue)
			}

			return s, nil

		case hint.Kind() == reflect.Map:
			keyType := hint.Key()
			elemType := hint.Elem()
			s := reflect.MakeMap(hint)

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}

				lKey, err := lValueToReflect(L, key, keyType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				lValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.SetMapIndex(lKey, lValue)
			}

			return s, nil

		case hint.Kind() == reflect.Ptr && hint.Elem().Kind() == reflect.Struct:
			hint = hint.Elem()
			isPtr = true
			fallthrough
		case hint.Kind() == reflect.Struct:
			s := reflect.New(hint)
			t := s.Elem()

			mt := &Metatable{
				LTable: getMetatable(L, hint),
			}

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}
				if _, ok := key.(lua.LString); !ok {
					continue
				}

				fieldName := key.String()
				index := mt.fieldIndex(fieldName)
				if index == nil {
					return reflect.Value{}, structFieldError{
						Type:  hint,
						Field: fieldName,
					}
				}
				field := hint.FieldByIndex(index)

				lValue, err := lValueToReflect(L, value, field.Type, nil)
				if err != nil {
					return reflect.Value{}, nil
				}
				t.FieldByIndex(field.Index).Set(lValue)
			}

			if isPtr {
				return s, nil
			}

			return t, nil

		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LUserData:
		val := reflect.ValueOf(converted.Value)
		if tryConvertPtr != nil && val.Kind() != reflect.Ptr && hint.Kind() == reflect.Ptr && val.Type() == hint.Elem() {
			newVal := reflect.New(hint.Elem())
			newVal.Elem().Set(val)
			val = newVal
			*tryConvertPtr = true
		} else {
			if !val.Type().ConvertibleTo(hint) {
				return reflect.Value{}, conversionError{
					Lua:  converted,
					Hint: hint,
				}
			}
			val = val.Convert(hint)
			if tryConvertPtr != nil {
				*tryConvertPtr = false
			}
		}
		return val, nil
	default:
		panic("never reaches")
	}
}
<commit_msg>remove unused conversionError error string case<commit_after>package luar // import "layeh.com/gopher-luar"

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

// New creates and returns a new lua.LValue for the given value.
//
// The following table shows how Go types are converted to Lua types:
//  Kind            gopher-lua Type  Custom Metatable
//  --------------------------------------------------
//  nil             LNil             No
//  Bool            LBool            No
//  Int             LNumber          No
//  Int8            LNumber          No
//  Int16           LNumber          No
//  Int32           LNumber          No
//  Int64           LNumber          No
//  Uint            LNumber          No
//  Uint8           LNumber          No
//  Uint16          LNumber          No
//  Uint32          LNumber          No
//  Uint64          LNumber          No
//  Uintptr         *LUserData       No
//  Float32         LNumber          No
//  Float64         LNumber          No
//  Complex64       *LUserData       No
//  Complex128      *LUserData       No
//  Array           *LUserData       Yes
//  Chan            *LUserData       Yes
//  Func            *LFunction       No
//  Map             *LUserData       Yes
//  Ptr             *LUserData       Yes
//  Slice           *LUserData       Yes
//  String          LString          No
//  Struct          *LUserData       Yes
//  UnsafePointer   *LUserData       No
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = getMetatableFromValue(L, val)
		return ud
	case reflect.Func:
		return funcWrapper(L, val, false)
	case reflect.String:
		return lua.LString(val.String())
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the returned lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = getTypeMetatable(L, val)

	return ud
}

type conversionError struct {
	Lua  lua.LValue
	Hint reflect.Type
}

func (c conversionError) Error() string {
	if _, isNil := c.Lua.(*lua.LNilType); isNil {
		return fmt.Sprintf("cannot use nil as type %s", c.Hint)
	}

	var val interface{}

	if userData, ok := c.Lua.(*lua.LUserData); ok {
		val = userData.Value
	} else {
		val = c.Lua
	}

	return fmt.Sprintf("cannot use %v (type %T) as type %s", val, val, c.Hint)
}

type structFieldError struct {
	Field string
	Type  reflect.Type
}

func (s structFieldError) Error() string {
	return `type ` + s.Type.String() + ` has no field ` + s.Field
}

func lValueToReflect(L *lua.LState, v lua.LValue, hint reflect.Type, tryConvertPtr *bool) (reflect.Value, error) {
	if hint.Implements(refTypeLuaLValue) {
		return reflect.ValueOf(v), nil
	}

	isPtr := false

	switch converted := v.(type) {
	case lua.LBool:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(bool(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LChannel:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LNumber:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(float64(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LFunction:
		switch {
		case hint == refTypeEmptyIface:
			inOut := []reflect.Type{
				reflect.SliceOf(refTypeEmptyIface),
			}
			hint = reflect.FuncOf(inOut, inOut, true)
		case hint.Kind() != reflect.Func:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}

		fn := func(args []reflect.Value) []reflect.Value {
			thread, _ := L.NewThread()
			thread.Push(converted)

			varadicCount := 0

			for i, arg := range args {
				if hint.IsVariadic() && i+1 == len(args) {
					// arg is the varadic slice
					varadicCount = arg.Len()
					for j := 0; j < varadicCount; j++ {
						arg := arg.Index(j)
						if !arg.CanInterface() {
							thread.Pop(i + j + 1)
							panic(fmt.Errorf("unable to Interface argument %d", i+j))
						}
						thread.Push(New(thread, arg.Interface()))
					}
					// recount for varadic slice that appeared
					varadicCount--
					break
				}

				if !arg.CanInterface() {
					thread.Pop(i + 1)
					panic(fmt.Errorf("unable to Interface argument %d", i))
				}
				thread.Push(New(thread, arg.Interface()))
			}

			thread.Call(len(args)+varadicCount, hint.NumOut())
			defer thread.Pop(hint.NumOut())

			ret := make([]reflect.Value, hint.NumOut())

			for i := 0; i < hint.NumOut(); i++ {
				outHint := hint.Out(i)
				var err error
				ret[i], err = lValueToReflect(thread, thread.Get(-hint.NumOut()+i), outHint, nil)
				if err != nil {
					panic(err)
				}
			}

			return ret
		}
		return reflect.MakeFunc(hint, fn), nil
	case *lua.LNilType:
		switch hint.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
			return reflect.Zero(hint), nil
		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LState:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LString:
		val := reflect.ValueOf(string(converted))
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LTable:
		if hint == refTypeEmptyIface {
			hint = reflect.MapOf(refTypeEmptyIface, refTypeEmptyIface)
		}

		switch {
		case hint.Kind() == reflect.Slice:
			elemType := hint.Elem()
			length := converted.Len()
			s := reflect.MakeSlice(hint, length, length)

			for i := 0; i < length; i++ {
				value := converted.RawGetInt(i + 1)
				elemValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.Index(i).Set(elemValue)
			}

			return s, nil

		case hint.Kind() == reflect.Map:
			keyType := hint.Key()
			elemType := hint.Elem()
			s := reflect.MakeMap(hint)

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}

				lKey, err := lValueToReflect(L, key, keyType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				lValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.SetMapIndex(lKey, lValue)
			}

			return s, nil

		case hint.Kind() == reflect.Ptr && hint.Elem().Kind() == reflect.Struct:
			hint = hint.Elem()
			isPtr = true
			fallthrough
		case hint.Kind() == reflect.Struct:
			s := reflect.New(hint)
			t := s.Elem()

			mt := &Metatable{
				LTable: getMetatable(L, hint),
			}

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}
				if _, ok := key.(lua.LString); !ok {
					continue
				}

				fieldName := key.String()
				index := mt.fieldIndex(fieldName)
				if index == nil {
					return reflect.Value{}, structFieldError{
						Type:  hint,
						Field: fieldName,
					}
				}
				field := hint.FieldByIndex(index)

				lValue, err := lValueToReflect(L, value, field.Type, nil)
				if err != nil {
					return reflect.Value{}, nil
				}
				t.FieldByIndex(field.Index).Set(lValue)
			}

			if isPtr {
				return s, nil
			}

			return t, nil

		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LUserData:
		val := reflect.ValueOf(converted.Value)
		if tryConvertPtr != nil && val.Kind() != reflect.Ptr && hint.Kind() == reflect.Ptr && val.Type() == hint.Elem() {
			newVal := reflect.New(hint.Elem())
			newVal.Elem().Set(val)
			val = newVal
			*tryConvertPtr = true
		} else {
			if !val.Type().ConvertibleTo(hint) {
				return reflect.Value{}, conversionError{
					Lua:  converted,
					Hint: hint,
				}
			}
			val = val.Convert(hint)
			if tryConvertPtr != nil {
				*tryConvertPtr = false
			}
		}
		return val, nil
	default:
		panic("never reaches")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/LOG_LEVEL"
)

const driverName = "driver-zwave"

var log = logger.GetLogger(driverName)

func main() {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.zwave")
	if err != nil {
		log.FatalError(err, "Could not connect to MQTT")
	}

	pwd, _ := os.Getwd()

	bus, err := conn.AnnounceDriver("com.ninjablocks.zwave", driverName, pwd)
	if err != nil {
		log.FatalError(err, "Could not get driver bus")
	}

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalError(err, "Could not setup status job")
	}

	statusJob.Start()

	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.FatalError(err, "Could not get net address")
	}

	zwaveEvents := func(api openzwave.API, event openzwave.Event) {
		switch event.(type) {
		case *openzwave.NodeAvailable:
			log.Infof("device available %v", event.GetNode())
			node := event.GetNode()
			newDevice, err := GetLibrary().GetDeviceFactory(*node.GetProductId())(bus, node)
			if err != nil {
				log.Infof("error while creating device for node %v: %v", event.GetNode(), err)
				//TODO: generate notification
			} else {
				log.Infof("device created for node %v", event.GetNode())
			}
			event.GetNode().SetDevice(newDevice)
			break
		case *openzwave.NodeChanged:
			existingDevice := event.GetNode().GetDevice()
			_ = existingDevice
			break
		case *openzwave.NodeUnavailable:
			// TODO
		}
	}

	_ = bus
	_ = ipAddr

	os.Exit(openzwave.
		BuildAPI("/usr/local/etc/openzwave", "", "").
		SetLogger(log).
		AddBoolOption("ValidateValueChanges", true).
		AddBoolOption("SaveConfiguration", false).
		AddBoolOption("logging", false).
		AddStringOption("LogFileName", "/dev/null", false).
		AddBoolOption("ConsoleOutput", false).
		AddBoolOption("NotifyTransactions", true).
		AddIntOption("SaveLogLevel", LOG_LEVEL.NONE).
		AddIntOption("QueueLogLevel", LOG_LEVEL.NONE).
		AddIntOption("DumpTrigger", LOG_LEVEL.NONE).
		AddIntOption("PollInterval", 30).
		AddBoolOption("IntervalBetweenPolls", false).
		AddBoolOption("ValidateValueChanges", true).
		SetEventsCallback(zwaveEvents).
		Run())

}
<commit_msg>Disable status job for now.<commit_after>package main

import (
	"os"

	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/LOG_LEVEL"
)

const driverName = "driver-zwave"

var log = logger.GetLogger(driverName)

func main() {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.zwave")
	if err != nil {
		log.FatalError(err, "Could not connect to MQTT")
	}

	pwd, _ := os.Getwd()

	bus, err := conn.AnnounceDriver("com.ninjablocks.zwave", driverName, pwd)
	if err != nil {
		log.FatalError(err, "Could not get driver bus")
	}

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalError(err, "Could not setup status job")
	}
	_ = statusJob
	// statusJob.Start()

	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.FatalError(err, "Could not get net address")
	}

	zwaveEvents := func(api openzwave.API, event openzwave.Event) {
		switch event.(type) {
		case *openzwave.NodeAvailable:
			log.Infof("device available %v", event.GetNode())
			node := event.GetNode()
			newDevice, err := GetLibrary().GetDeviceFactory(*node.GetProductId())(bus, node)
			if err != nil {
				log.Infof("error while creating device for node %v: %v", event.GetNode(), err)
				//TODO: generate notification
			} else {
				log.Infof("device created for node %v", event.GetNode())
			}
			event.GetNode().SetDevice(newDevice)
			break
		case *openzwave.NodeChanged:
			existingDevice := event.GetNode().GetDevice()
			_ = existingDevice
			break
		case *openzwave.NodeUnavailable:
			// TODO
		}
	}

	_ = bus
	_ = ipAddr

	os.Exit(openzwave.
		BuildAPI("/usr/local/etc/openzwave", "", "").
		SetLogger(log).
		AddBoolOption("ValidateValueChanges", true).
		AddBoolOption("SaveConfiguration", false).
		AddBoolOption("logging", false).
		AddStringOption("LogFileName", "/dev/null", false).
		AddBoolOption("ConsoleOutput", false).
		AddBoolOption("NotifyTransactions", true).
		AddIntOption("SaveLogLevel", LOG_LEVEL.NONE).
		AddIntOption("QueueLogLevel", LOG_LEVEL.NONE).
		AddIntOption("DumpTrigger", LOG_LEVEL.NONE).
		AddIntOption("PollInterval", 30).
		AddBoolOption("IntervalBetweenPolls", false).
		AddBoolOption("ValidateValueChanges", true).
		SetEventsCallback(zwaveEvents).
		Run())

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/veandco/go-sdl2/sdl"
    "github.com/veandco/go-sdl2/sdl_ttf"
	"github.com/felixangell/nate/gui"
	"fmt"
)

type NateEditor struct {
	window *sdl.Window
	surface *sdl.Surface
	running bool
    panels []*gui.Panel
}

func (n *NateEditor) init() {
    // setup a default panel
    testPanel := gui.NewPanel()
    testPanel.AddComponent(gui.NewBuffer())
    n.panels = append(n.panels, testPanel)
}

func (n *NateEditor) update() {
	for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
		switch t := event.(type) {
		case *sdl.QuitEvent:
			n.running = false
		case *sdl.TextInputEvent:
			fmt.Println("todo, text input", t)
		}
	}

    for _, panel := range n.panels {
        panel.Update()
    }
}

func (n *NateEditor) render() {
    for _, panel := range n.panels {
        panel.Render(n.surface)
    }
    n.window.UpdateSurface()
}

func main() {
    sdl.Init(sdl.INIT_EVERYTHING)
    defer sdl.Quit()

    if err := ttf.Init(); err != nil {
        panic(err)
    }

    window, err := sdl.CreateWindow("Nate Editor",
    	sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
    	1280, 720,
    	sdl.WINDOW_SHOWN)
    if err != nil {
        panic(err)
    }
    defer window.Destroy()

    surface, err := window.GetSurface()
    if err != nil {
        panic(err)
    }

    editor := &NateEditor{window: window, surface: surface, running: true}
    editor.init()

    for editor.running {
    	editor.update()
    	editor.render()
    }
}
<commit_msg>fps limit stuff<commit_after>package main

import (
	"github.com/veandco/go-sdl2/sdl"
    "github.com/veandco/go-sdl2/sdl_ttf"
	"github.com/felixangell/nate/gui"
	"fmt"
)

type NateEditor struct {
	window *sdl.Window
	surface *sdl.Surface
	running bool
    panels []*gui.Panel
}

func (n *NateEditor) init() {
    // setup a default panel
    testPanel := gui.NewPanel()
    testPanel.AddComponent(gui.NewBuffer())
    n.panels = append(n.panels, testPanel)
}

func (n *NateEditor) update() {
	for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
		switch t := event.(type) {
		case *sdl.QuitEvent:
			n.running = false
		case *sdl.TextInputEvent:
			fmt.Println("todo, text input", t)
		}
	}

    for _, panel := range n.panels {
        panel.Update()
    }
}

func (n *NateEditor) render() {
    for _, panel := range n.panels {
        panel.Render(n.surface)
    }
    n.window.UpdateSurface()
}

func main() {
    sdl.Init(sdl.INIT_EVERYTHING)
    defer sdl.Quit()

    if err := ttf.Init(); err != nil {
        panic(err)
    }

    window, err := sdl.CreateWindow("Nate Editor",
    	sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
    	1280, 720,
    	sdl.WINDOW_SHOWN)
    if err != nil {
        panic(err)
    }
    defer window.Destroy()

    surface, err := window.GetSurface()
    if err != nil {
        panic(err)
    }

    editor := &NateEditor{window: window, surface: surface, running: true}
    editor.init()

    timer := sdl.GetTicks()
    var tick_interval uint32 = 20
    num_frames := 0
    frame_idx := sdl.GetTicks() / tick_interval
    simulate := true

    for editor.running {
        if sdl.GetTicks() / tick_interval > frame_idx {
            frame_idx = sdl.GetTicks() / tick_interval
            simulate = true
        }

    	if simulate {
            editor.update()
        }

    	editor.render()
        num_frames += 1

        if sdl.GetTicks() - timer > 1000 {
            timer = sdl.GetTicks()
            fmt.Println("frames: ", num_frames)
            num_frames = 0
        }
    }
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/reportportal/commons-go/commons"
	"github.com/reportportal/commons-go/conf"
	"github.com/reportportal/commons-go/server"
	"github.com/unrolled/secure"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}
	cfg := conf.EmptyConfig()
	rpConf := struct {
		Cfg         *conf.ServerConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         cfg,
		StaticsPath: currDir,
	}
	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}
	info := commons.GetBuildInfo()
	info.Name = "Service UI"
	srv := server.New(rpConf.Cfg, info)
	configureRouter(srv, rpConf)
	srv.StartServer()
}

func configureRouter(srv *server.RpServer, rpConf struct {
	Cfg         *conf.ServerConfig
	StaticsPath string `env:"RP_STATICS_PATH"`
}) {
	srv.WithRouter(func(router *chi.Mux) {
		//apply compression
		router.Use(middleware.DefaultCompress)
		router.Use(middleware.Logger)
		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "data:", "'unsafe-inline'", "*.uservoice.com"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"stats.g.doubleclick.net",
				"*.saucelabs.com",
				"*.epam.com",
				"*.uservoice.com",
				"*.rawgit.com",
			},
			"worker-src":     {"'self'", "blob:"},
			"font-src":       {"'self'", "data:", "fonts.googleapis.com", "fonts.gstatic.com", "*.rawgit.com"},
			"style-src-elem": {"'self'", "data:", "'unsafe-inline'", "*.googleapis.com", "*.rawgit.com"},
			"media-src":      {"'self'", "*.saucelabs.com"},
			"img-src":        {"*", "'self'", "data:", "blob:"},
			"object-src":     {"'self'"},
		}
		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
				STSSeconds:            315360000,
				STSIncludeSubdomains:  true,
				STSPreload:            true,
			}).Handler(next)
		})
		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}
		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))
			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}
			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))
	})
}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	var instr []string
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")
}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
    var notFoundStatusCode int = 404
	if notFoundStatusCode == status {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/#notfound", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}
}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<commit_msg>gofmt applied<commit_after>package main

import (
	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/reportportal/commons-go/commons"
	"github.com/reportportal/commons-go/conf"
	"github.com/reportportal/commons-go/server"
	"github.com/unrolled/secure"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {
	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}
	cfg := conf.EmptyConfig()
	rpConf := struct {
		Cfg         *conf.ServerConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         cfg,
		StaticsPath: currDir,
	}
	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}
	info := commons.GetBuildInfo()
	info.Name = "Service UI"
	srv := server.New(rpConf.Cfg, info)
	configureRouter(srv, rpConf)
	srv.StartServer()
}

func configureRouter(srv *server.RpServer, rpConf struct {
	Cfg         *conf.ServerConfig
	StaticsPath string `env:"RP_STATICS_PATH"`
}) {
	srv.WithRouter(func(router *chi.Mux) {
		//apply compression
		router.Use(middleware.DefaultCompress)
		router.Use(middleware.Logger)
		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "data:", "'unsafe-inline'", "*.uservoice.com"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"stats.g.doubleclick.net",
				"*.saucelabs.com",
				"*.epam.com",
				"*.uservoice.com",
				"*.rawgit.com",
			},
			"worker-src":     {"'self'", "blob:"},
			"font-src":       {"'self'", "data:", "fonts.googleapis.com", "fonts.gstatic.com", "*.rawgit.com"},
			"style-src-elem": {"'self'", "data:", "'unsafe-inline'", "*.googleapis.com", "*.rawgit.com"},
			"media-src":      {"'self'", "*.saucelabs.com"},
			"img-src":        {"*", "'self'", "data:", "blob:"},
			"object-src":     {"'self'"},
		}
		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
				STSSeconds:            315360000,
				STSIncludeSubdomains:  true,
				STSPreload:            true,
			}).Handler(next)
		})
		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}
		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))
			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}
			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))
	})
}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	var instr []string
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")
}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
	var notFoundStatusCode int = 404
	if notFoundStatusCode == status {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/#notfound", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}
}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"io"
	"log"
	"os"
)

type Metadata struct {
	signature1 uint32
	signature2 uint32
	flags      uint32
	version    uint32
	seed       [16]byte
	encryption [16]byte
	groups     uint32
	entries    uint32
	hash       [32]byte
	seed2      [32]byte
	rounds     uint32
}

type KeepassXDatabase struct {
	*Metadata
}

func NewKeepassXDatabase() (*KeepassXDatabase, error) {
	return &KeepassXDatabase{
		Metadata: new(Metadata),
	}, nil
}

func (k *KeepassXDatabase) ReadFrom(r io.Reader) (int64, error) {
	var buf [4]byte
	uint32Bytes := buf[:4]

	n, err := io.ReadFull(r, uint32Bytes)
	n64 := int64(n)
	k.signature1 = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.signature2 = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.flags = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.version = binary.LittleEndian.Uint32(uint32Bytes)

	var seed [16]byte
	n, err = io.ReadFull(r, seed[:])
	n64 += int64(n)
	k.seed = seed

	var encryption [16]byte
	n, err = io.ReadFull(r, encryption[:])
	n64 += int64(n)
	k.encryption = encryption

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.groups = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.entries = binary.LittleEndian.Uint32(uint32Bytes)

	var hash [32]byte
	n, err = io.ReadFull(r, hash[:])
	n64 += int64(n)
	k.hash = hash

	var seed2 [32]byte
	n, err = io.ReadFull(r, seed2[:])
	n64 += int64(n)
	k.seed2 = seed2

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	k.rounds = binary.LittleEndian.Uint32(uint32Bytes)

	return n64, err
}

func main() {
	path := os.Args[1]
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("%v", err)
	}
	defer f.Close()
	db, err := NewKeepassXDatabase()
	if err != nil {
		log.Fatalf("%v", err)
	}
	_, err = db.ReadFrom(f)
	if err != nil {
		log.Fatalf("%v", err)
	}
}
<commit_msg>stub parse, decrypt payload<commit_after>package main

import (
	"encoding/binary"
	"io"
	"log"
	"os"
)

var EncryptionTypes = map[string]int{
	"SHA2":     1,
	"Rijndael": 2,
	"AES":      2,
	"ArcFour":  4,
	"TwoFish":  8,
}

type Metadata struct {
	signature1 uint32
	signature2 uint32
	flags      uint32
	version    uint32
	seed       [16]byte
	encryption [16]byte
	groups     uint32
	entries    uint32
	hash       [32]byte
	seed2      [32]byte
	rounds     uint32
}

type KeepassXDatabase struct {
	*Metadata
	payload []byte
}

func NewKeepassXDatabase() (*KeepassXDatabase, error) {
	return &KeepassXDatabase{
		Metadata: new(Metadata),
	}, nil
}

func (m *Metadata) ReadFrom(r io.Reader) (int64, error) {
	var buf [4]byte
	uint32Bytes := buf[:4]

	n, err := io.ReadFull(r, uint32Bytes)
	n64 := int64(n)
	m.signature1 = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.signature2 = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.flags = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.version = binary.LittleEndian.Uint32(uint32Bytes)

	var seed [16]byte
	n, err = io.ReadFull(r, seed[:])
	n64 += int64(n)
	m.seed = seed

	var encryption [16]byte
	n, err = io.ReadFull(r, encryption[:])
	n64 += int64(n)
	m.encryption = encryption

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.groups = binary.LittleEndian.Uint32(uint32Bytes)

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.entries = binary.LittleEndian.Uint32(uint32Bytes)

	var hash [32]byte
	n, err = io.ReadFull(r, hash[:])
	n64 += int64(n)
	m.hash = hash

	var seed2 [32]byte
	n, err = io.ReadFull(r, seed2[:])
	n64 += int64(n)
	m.seed2 = seed2

	n, err = io.ReadFull(r, uint32Bytes)
	n64 += int64(n)
	m.rounds = binary.LittleEndian.Uint32(uint32Bytes)

	return n64, err
}

func (k *KeepassXDatabase) decryptPayload(payload []byte, seed [16]byte, seed2 [32]byte, rounds uint32, flags uint32, encryption [16]byte) ([]byte, error) {
	var err error
	var data []byte
	return data, err
}

func (k *KeepassXDatabase) parsePayload(payload []byte) error {
	return nil
}

func (k *KeepassXDatabase) ReadFrom(r io.Reader) (int64, error) {
	n, err := k.Metadata.ReadFrom(r)
	if err != nil {
		return n, err
	}
	var content []byte
	_, err = io.ReadFull(r, content[:])
	payload, err := k.decryptPayload(content, k.seed, k.seed2, k.rounds, k.flags, k.encryption)
	err = k.parsePayload(payload)
	return n, err
}

func main() {
	path := os.Args[1]
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("%v", err)
	}
	defer f.Close()
	db, err := NewKeepassXDatabase()
	if err != nil {
		log.Fatalf("%v", err)
	}
	_, err = db.ReadFrom(f)
	if err != nil {
		log.Fatalf("%v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"

	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/parser"
	"github.com/mattn/go-runewidth"
)

var prompt = "; "

type history struct {
	lines [][]rune
	i     int
}

func main() {
	var command = flag.String("c", "", "take first argument as a command to execute")
	flag.Parse()
	if *command != "" {
		if err := execute([]byte(*command)); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		return
	}
	var hist history
	for {
		if err := loop(&hist); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}

const (
	CharCtrlA = iota + 1
	CharCtrlB
	CharCtrlC
	CharCtrlD
	CharCtrlE
	CharCtrlF
	CharCtrlG
	CharCtrlH
	CharCtrlI
	CharCtrlJ
	CharCtrlK
	CharCtrlL
	CharCtrlM
	CharCtrlN
	CharCtrlO
	CharCtrlP
	CharCtrlQ
	CharCtrlR
	CharCtrlS
	CharCtrlT
	CharCtrlU
	CharCtrlV
	CharCtrlW
	CharCtrlX
	CharCtrlY
	CharCtrlZ
	CharEscape

	CharBackspace = 127
)

func loop(hist *history) error {
	fmt.Print("\n")
	fmt.Print("\r\033[J")
	fmt.Print("\033[B")
	fmt.Print("-- INSERT --")
	fmt.Print("\033[A")
	fmt.Print("\r")
	fmt.Print(prompt)

	rd := NewReader(os.Stdin)
	lines := make([][]rune, len(hist.lines))
	copy(lines, hist.lines)
	cl := &commandline{
		w: bufio.NewWriter(os.Stdout),
		hist: history{
			lines: lines,
			i:     hist.i,
		},
		mode: insertMode,
	}
	state, err := enterRowMode()
	if err != nil {
		return err
	}
LOOP:
	for {
		ch, err := rd.Read()
		if err != nil {
			return err
		}
		switch cl.mode {
		case normalMode:
			switch ch {
			case CharCtrlM:
				break LOOP
			case 'h':
				cl.toLeft()
			case 'l':
				cl.toRight()
			case '0':
				cl.toTheFirst()
			case '^':
				cl.toTheFirstNonBlank()
			case '$':
				cl.toTheEnd()
			case 'a':
				cl.moveForward()
				cl.mode = insertMode
			case 'i':
				cl.mode = insertMode
			case 'x':
				cl.deleteUnder()
			case 'k':
				cl.prevHistory()
			case 'j':
				cl.nextHistory()
			default:
			}
		case insertMode:
			switch ch {
			case CharCtrlM:
				break LOOP
			case CharEscape:
				cl.moveBackward()
				cl.mode = normalMode
			case CharBackspace:
				cl.deleteChar()
			default:
				cl.appendChar(ch)
			}
		}
		cl.refresh()
	}
	cl.w.WriteByte('\n')
	cl.w.WriteString("\r\033[K")
	cl.w.Flush()
	err = exitRowMode(state)
	if err != nil {
		return err
	}
	hist.lines = append(hist.lines, cl.buf)
	hist.i++
	return execute([]byte(string(cl.buf)))
}

func execute(b []byte) error {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return err
	}
	return eval.Eval(f.Lines)
}

type commandline struct {
	w     *bufio.Writer
	buf   []rune
	index int

	hist history

	mode mode
}

func (cl *commandline) refresh() {
	if cl.mode == insertMode {
		cl.w.WriteString("\033[B")
		cl.w.WriteString("\r\033[K")
		cl.w.WriteString("-- INSERT --")
		cl.w.WriteString("\033[A")
		cl.w.WriteString("\r\033[K")
	} else {
		cl.w.WriteString("\r\033[J")
	}

	cl.w.WriteString(prompt)
	cl.w.WriteString(string(cl.buf))
	cl.w.WriteString(fmt.Sprintf("\033[%vG", len(prompt)+runewidth.StringWidth(string(cl.buf[:cl.index]))+1))
	cl.w.Flush()
}

func (cl *commandline) moveBackward() {
	if cl.index == 0 {
		return
	}
	cl.index--
}

func (cl *commandline) moveForward() {
	if cl.index == len(cl.buf) {
		return
	}
	cl.index++
}

func (cl *commandline) appendChar(ch rune) {
	switch cl.index {
	case 0:
		cl.buf = append([]rune{ch}, cl.buf...)
	case len(cl.buf):
		cl.buf = append(cl.buf, ch)
	default:
		buf := make([]rune, cl.index, len(cl.buf)+1)
		copy(buf, cl.buf[:cl.index])
		buf = append(buf, ch)
		buf = append(buf, cl.buf[cl.index:]...)
		cl.buf = buf
	}
	cl.index++
}

func (cl *commandline) deleteChar() {
	switch cl.index {
	case 0:
		return
	case 1:
		cl.buf = cl.buf[1:]
	case len(cl.buf):
		cl.buf = cl.buf[:cl.index-1]
	default:
		cl.buf = append(cl.buf[:cl.index-1], cl.buf[cl.index:]...)
	}
	cl.index--
}
<commit_msg>Fix showmode<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"

	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/parser"
	"github.com/mattn/go-runewidth"
)

var prompt = "; "

type history struct {
	lines [][]rune
	i     int
}

func main() {
	var command = flag.String("c", "", "take first argument as a command to execute")
	flag.Parse()
	if *command != "" {
		if err := execute([]byte(*command)); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		return
	}
	var hist history
	for {
		if err := loop(&hist); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}

const (
	CharCtrlA = iota + 1
	CharCtrlB
	CharCtrlC
	CharCtrlD
	CharCtrlE
	CharCtrlF
	CharCtrlG
	CharCtrlH
	CharCtrlI
	CharCtrlJ
	CharCtrlK
	CharCtrlL
	CharCtrlM
	CharCtrlN
	CharCtrlO
	CharCtrlP
	CharCtrlQ
	CharCtrlR
	CharCtrlS
	CharCtrlT
	CharCtrlU
	CharCtrlV
	CharCtrlW
	CharCtrlX
	CharCtrlY
	CharCtrlZ
	CharEscape

	CharBackspace = 127
)

func loop(hist *history) error {
	fmt.Print("\r\033[J")
	fmt.Print("\n")
	fmt.Print("-- INSERT --")
	fmt.Print("\033[A")
	fmt.Print("\r")
	fmt.Print(prompt)

	rd := NewReader(os.Stdin)
	lines := make([][]rune, len(hist.lines))
	copy(lines, hist.lines)
	cl := &commandline{
		w: bufio.NewWriter(os.Stdout),
		hist: history{
			lines: lines,
			i:     hist.i,
		},
		mode: insertMode,
	}
	state, err := enterRowMode()
	if err != nil {
		return err
	}
LOOP:
	for {
		ch, err := rd.Read()
		if err != nil {
			return err
		}
		switch cl.mode {
		case normalMode:
			switch ch {
			case CharCtrlM:
				break LOOP
			case 'h':
				cl.toLeft()
			case 'l':
				cl.toRight()
			case '0':
				cl.toTheFirst()
			case '^':
				cl.toTheFirstNonBlank()
			case '$':
				cl.toTheEnd()
			case 'a':
				cl.moveForward()
				cl.mode = insertMode
			case 'i':
				cl.mode = insertMode
			case 'x':
				cl.deleteUnder()
			case 'k':
				cl.prevHistory()
			case 'j':
				cl.nextHistory()
			default:
			}
		case insertMode:
			switch ch {
			case CharCtrlM:
				break LOOP
			case CharEscape:
				cl.moveBackward()
				cl.mode = normalMode
			case CharBackspace:
				cl.deleteChar()
			default:
				cl.appendChar(ch)
			}
		}
		cl.refresh()
	}
	cl.w.WriteByte('\n')
	cl.w.WriteString("\r\033[K")
	cl.w.Flush()
	err = exitRowMode(state)
	if err != nil {
		return err
	}
	hist.lines = append(hist.lines, cl.buf)
	hist.i++
	return execute([]byte(string(cl.buf)))
}

func execute(b []byte) error {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return err
	}
	return eval.Eval(f.Lines)
}

type commandline struct {
	w     *bufio.Writer
	buf   []rune
	index int

	hist history

	mode mode
}

func (cl *commandline) refresh() {
	if cl.mode == insertMode {
		cl.w.WriteString("\033[B")
		cl.w.WriteString("\r\033[K")
		cl.w.WriteString("-- INSERT --")
		cl.w.WriteString("\033[A")
		cl.w.WriteString("\r\033[K")
	} else {
		cl.w.WriteString("\r\033[J")
	}

	cl.w.WriteString(prompt)
	cl.w.WriteString(string(cl.buf))
	cl.w.WriteString(fmt.Sprintf("\033[%vG", len(prompt)+runewidth.StringWidth(string(cl.buf[:cl.index]))+1))
	cl.w.Flush()
}

func (cl *commandline) moveBackward() {
	if cl.index == 0 {
		return
	}
	cl.index--
}

func (cl *commandline) moveForward() {
	if cl.index == len(cl.buf) {
		return
	}
	cl.index++
}

func (cl *commandline) appendChar(ch rune) {
	switch cl.index {
	case 0:
		cl.buf = append([]rune{ch}, cl.buf...)
	case len(cl.buf):
		cl.buf = append(cl.buf, ch)
	default:
		buf := make([]rune, cl.index, len(cl.buf)+1)
		copy(buf, cl.buf[:cl.index])
		buf = append(buf, ch)
		buf = append(buf, cl.buf[cl.index:]...)
		cl.buf = buf
	}
	cl.index++
}

func (cl *commandline) deleteChar() {
	switch cl.index {
	case 0:
		return
	case 1:
		cl.buf = cl.buf[1:]
	case len(cl.buf):
		cl.buf = cl.buf[:cl.index-1]
	default:
		cl.buf = append(cl.buf[:cl.index-1], cl.buf[cl.index:]...)
	}
	cl.index--
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"mime"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"time"

	"github.com/ONSdigital/florence/assets"
	"github.com/ONSdigital/florence/config"
	"github.com/ONSdigital/florence/healthcheck"
	"github.com/ONSdigital/florence/upload"
	"github.com/ONSdigital/go-ns/common"
	"github.com/ONSdigital/go-ns/handlers/reverseProxy"
	hc "github.com/ONSdigital/go-ns/healthcheck"
	"github.com/ONSdigital/go-ns/server"
	"github.com/ONSdigital/go-ns/vault"
	"github.com/ONSdigital/log.go/log"
	"github.com/gorilla/pat"
	"github.com/gorilla/websocket"
)

var getAsset = assets.Asset
var getAssetETag = assets.GetAssetETag
var upgrader = websocket.Upgrader{}

// Version is set by the make target
var Version string

func main() {
	log.Namespace = "florence"
	log.Event(nil, "florence version", log.Data{"version": Version})

	cfg, err := config.Get()
	if err != nil {
		log.Event(nil, "error getting configuration", log.Error(err))
		os.Exit(1)
	}

	zc := healthcheck.New(cfg.ZebedeeURL, "zebedee")
	rtrc := healthcheck.New(cfg.RouterURL, "router")
	dc := healthcheck.New(cfg.DatasetAPIURL, "dataset-api")
	rc := healthcheck.New(cfg.RecipeAPIURL, "recipe-api")
	ic := healthcheck.New(cfg.ImportAPIURL, "import-api")

	routerURL, err := url.Parse(cfg.RouterURL)
	if err != nil {
		log.Event(nil, "error parsing router URL", log.Error(err))
		os.Exit(1)
	}
	routerProxy := reverseProxy.Create(routerURL, director)

	zebedeeURL, err := url.Parse(cfg.ZebedeeURL)
	if err != nil {
		log.Event(nil, "error parsing zebedee URL", log.Error(err))
		os.Exit(1)
	}
	zebedeeProxy := reverseProxy.Create(zebedeeURL, zebedeeDirector)

	recipeAPIURL, err := url.Parse(cfg.RecipeAPIURL)
	if err != nil {
		log.Event(nil, "error parsing recipe API URL", log.Error(err))
		os.Exit(1)
	}
	recipeAPIProxy := reverseProxy.Create(recipeAPIURL, nil)

	tableURL, err := url.Parse(cfg.TableRendererURL)
	if err != nil {
		log.Event(nil, "error parsing table renderer URL", log.Error(err))
		os.Exit(1)
	}
	tableProxy := reverseProxy.Create(tableURL, tableDirector)

	importAPIURL, err := url.Parse(cfg.ImportAPIURL)
	if err != nil {
		log.Event(nil, "error parsing import API URL", log.Error(err))
		os.Exit(1)
	}
	importAPIProxy := reverseProxy.Create(importAPIURL, importAPIDirector)

	datasetAPIURL, err := url.Parse(cfg.DatasetAPIURL)
	if err != nil {
		log.Event(nil, "error parsing dataset API URL", log.Error(err))
		os.Exit(1)
	}
	datasetAPIProxy := reverseProxy.Create(datasetAPIURL, datasetAPIDirector)

	var vc upload.VaultClient
	if !cfg.EncryptionDisabled {
		vc, err = vault.CreateVaultClient(cfg.VaultToken, cfg.VaultAddr, 3)
		if err != nil {
			log.Event(nil, "error creating vault client", log.Error(err))
			os.Exit(1)
		}
	}

	uploader, err := upload.New(cfg.UploadBucketName, cfg.VaultPath, vc)
	if err != nil {
		log.Event(nil, "error creating file uploader", log.Error(err))
		os.Exit(1)
	}

	router := pat.New()

	router.Path("/healthcheck").HandlerFunc(hc.Do)

	if cfg.SharedConfig.EnableDatasetImport {
		router.Path("/upload").Methods("GET").HandlerFunc(uploader.CheckUploaded)
		router.Path("/upload").Methods("POST").HandlerFunc(uploader.Upload)
		router.Path("/upload/{id}").Methods("GET").HandlerFunc(uploader.GetS3URL)
		router.Handle("/recipes{uri:.*}", recipeAPIProxy)
		router.Handle("/import{uri:.*}", importAPIProxy)
		router.Handle("/dataset/{uri:.*}", datasetAPIProxy)
		router.Handle("/instances/{uri:.*}", datasetAPIProxy)
	}

	router.Handle("/zebedee{uri:/.*}", zebedeeProxy)
	router.Handle("/table/{uri:.*}", tableProxy)
	router.HandleFunc("/florence/dist/{uri:.*}", staticFiles)
	router.HandleFunc("/florence/", redirectToFlorence)
	router.HandleFunc("/florence/index.html", redirectToFlorence)
	router.Path("/florence/publishing-queue").HandlerFunc(legacyIndexFile(cfg))
	router.Path("/florence/reports").HandlerFunc(legacyIndexFile(cfg))
	router.Path("/florence/workspace").HandlerFunc(legacyIndexFile(cfg))
	router.HandleFunc("/florence/websocket", websocketHandler)
	router.Path("/florence{uri:.*}").HandlerFunc(refactoredIndexFile(cfg))
	router.Handle("/{uri:.*}", routerProxy)

	log.Event(nil, "starting server", log.Data{"config": cfg})

	s := server.New(cfg.BindAddr, router)
	// TODO need to reconsider default go-ns server timeouts
	s.Server.IdleTimeout = 120 * time.Second
	s.Server.WriteTimeout = 120 * time.Second
	s.Server.ReadTimeout = 30 * time.Second
	s.HandleOSSignals = false
	s.Middleware["RequestLogger"] = log.Middleware
	s.MiddlewareOrder = []string{"RequestID", "RequestLogger"}

	// FIXME temporary hack to remove timeout middleware (doesn't support hijacker interface)
	mo := s.MiddlewareOrder
	var newMo []string
	for _, mw := range mo {
		if mw != "Timeout" {
			newMo = append(newMo, mw)
		}
	}
	s.MiddlewareOrder = newMo

	go func() {
		if err := s.ListenAndServe(); err != nil {
			log.Event(nil, "error starting http server", log.Error(err))
			os.Exit(2)
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, os.Kill)

	for {
		hc.MonitorExternal(rtrc, zc, ic, rc, dc)

		timer := time.NewTimer(time.Second * 60)

		select {
		case <-timer.C:
			continue
		case <-stop:
			log.Event(nil, "shutting down gracefully")
			timer.Stop()
			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
			defer cancel()
			if err := s.Server.Shutdown(ctx); err != nil {
				log.Event(nil, "error shutting down gracefully", log.Error(err))
			}
			return
		}
	}
}

func redirectToFlorence(w http.ResponseWriter, req *http.Request) {
	http.Redirect(w, req, "/florence", 301)
}

func staticFiles(w http.ResponseWriter, req *http.Request) {
	path := req.URL.Query().Get(":uri")
	assetPath := "../dist/" + path

	etag, err := getAssetETag(assetPath)

	if hdr := req.Header.Get("If-None-Match"); len(hdr) > 0 && hdr == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	b, err := getAsset(assetPath)
	if err != nil {
		log.Event(req.Context(), "error getting asset", log.Error(err))
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`ETag`, etag)
	w.Header().Set(`Cache-Control`, "no-cache")
	w.Header().Set(`Content-Type`, mime.TypeByExtension(filepath.Ext(path)))
	w.WriteHeader(200)
	w.Write(b)
}

func legacyIndexFile(cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		log.Event(req.Context(), "getting legacy html file")

		b, err := getAsset("../dist/legacy-assets/index.html")
		if err != nil {
			log.Event(req.Context(), "error getting legacy html file", log.Error(err))
			w.WriteHeader(404)
			return
		}

		cfgJSON, err := json.Marshal(cfg.SharedConfig)
		if err != nil {
			log.Event(req.Context(), "error marshalling shared configuration", log.Error(err))
			w.WriteHeader(500)
			return
		}
		b = []byte(strings.Replace(string(b), "/* environment variables placeholder */", "/* server generated shared config */ "+string(cfgJSON), 1))

		w.Header().Set(`Content-Type`, "text/html")
		w.WriteHeader(200)
		w.Write(b)
	}
}

func refactoredIndexFile(cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		log.Event(req.Context(), "getting refactored html file")

		b, err := getAsset("../dist/refactored.html")
		if err != nil {
			log.Event(req.Context(), "error getting refactored html file", log.Error(err))
			w.WriteHeader(404)
			return
		}

		cfgJSON, err := json.Marshal(cfg.SharedConfig)
		if err != nil {
			log.Event(req.Context(), "error marshalling shared configuration", log.Error(err))
			w.WriteHeader(500)
			return
		}
		b = []byte(strings.Replace(string(b), "/* environment variables placeholder */", "/* server generated shared config */ "+string(cfgJSON), 1))

		w.Header().Set(`Content-Type`, "text/html")
		w.WriteHeader(200)
		w.Write(b)
	}
}

func zebedeeDirector(req *http.Request) {
	if c, err := req.Cookie(`access_token`); err == nil && len(c.Value) > 0 {
		req.Header.Set(`X-Florence-Token`, c.Value)
	}
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/zebedee")
}

func director(req *http.Request) {
	if accessTokenCookie, err := req.Cookie(common.FlorenceCookieKey); err == nil && len(accessTokenCookie.Value) > 0 {
		req.Header.Set(common.FlorenceHeaderKey, accessTokenCookie.Value)
	}

	if colletionCookie, err := req.Cookie(common.CollectionIDCookieKey); err == nil && len(colletionCookie.Value) > 0 {
		req.Header.Set(common.CollectionIDHeaderKey, colletionCookie.Value)
	}
}

func importAPIDirector(req *http.Request) {
	director(req)
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/import")
}

func tableDirector(req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/table")
}

func datasetAPIDirector(req *http.Request) {
	director(req)
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/dataset")
}

func websocketHandler(w http.ResponseWriter, req *http.Request) {
	c, err := upgrader.Upgrade(w, req, nil)
	if err != nil {
		log.Event(req.Context(), "error upgrading connection to websocket", log.Error(err))
		return
	}

	defer c.Close()

	err = c.WriteJSON(florenceServerEvent{"version", florenceVersionPayload{Version: Version}})
	if err != nil {
		log.Event(req.Context(), "error writing version message", log.Error(err))
		return
	}

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			log.Event(req.Context(), "error reading websocket message", log.Error(err))
			break
		}

		rdr := bufio.NewReader(bytes.NewReader(message))
		b, err := rdr.ReadBytes('{')
		if err != nil {
			log.Event(req.Context(), "error reading websocket bytes", log.Error(err), log.Data{"bytes": string(b)})
			continue
		}

		tags := strings.Split(string(b), ":")
		eventID := tags[0]
		eventType := tags[1]
		eventData := message[len(eventID)+len(eventType)+2:]

		switch eventType {
		case "log":
			var e florenceLogEvent
			e.ServerTimestamp = time.Now().UTC().Format("2006-01-02T15:04:05.000-0700Z")
			err = json.Unmarshal(eventData, &e)
			if err != nil {
				log.Event(req.Context(), "error unmarshalling websocket message", log.Error(err), log.Data{"data": string(eventData)})
				continue
			}
			log.Event(req.Context(), "client log", log.Data{"data": e})

			err = c.WriteJSON(florenceServerEvent{"ack", eventID})
			if err != nil {
				log.Event(req.Context(), "error writing websocket ack", log.Error(err))
			}
		default:
			log.Event(req.Context(), "unknown websocket event type", log.Data{"type": eventType, "data": string(eventData)})
		}
	}
}

type florenceLogEvent struct {
	ServerTimestamp string      `json:"-"`
	ClientTimestamp time.Time   `json:"clientTimestamp"`
	Type            string      `json:"type"`
	Location        string      `json:"location"`
	InstanceID      string      `json:"instanceID"`
	Payload         interface{} `json:"payload"`
}

type florenceServerEvent struct {
	Type    string      `json:"type"`
	Payload interface{} `json:"payload"`
}

type florenceVersionPayload struct {
	Version string `json:"version"`
}
<commit_msg>Add routing to dataset controller<commit_after>package main

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"mime"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"time"

	"github.com/ONSdigital/florence/assets"
	"github.com/ONSdigital/florence/config"
	"github.com/ONSdigital/florence/healthcheck"
	"github.com/ONSdigital/florence/upload"
	"github.com/ONSdigital/go-ns/common"
	"github.com/ONSdigital/go-ns/handlers/reverseProxy"
	hc "github.com/ONSdigital/go-ns/healthcheck"
	"github.com/ONSdigital/go-ns/server"
	"github.com/ONSdigital/go-ns/vault"
	"github.com/ONSdigital/log.go/log"
	"github.com/gorilla/pat"
	"github.com/gorilla/websocket"
)

var getAsset = assets.Asset
var getAssetETag = assets.GetAssetETag
var upgrader = websocket.Upgrader{}

// Version is set by the make target
var Version string

func main() {
	log.Namespace = "florence"
	log.Event(nil, "florence version", log.Data{"version": Version})

	cfg, err := config.Get()
	if err != nil {
		log.Event(nil, "error getting configuration", log.Error(err))
		os.Exit(1)
	}

	zc := healthcheck.New(cfg.ZebedeeURL, "zebedee")
	rtrc := healthcheck.New(cfg.RouterURL, "router")
	dc := healthcheck.New(cfg.DatasetAPIURL, "dataset-api")
	rc := healthcheck.New(cfg.RecipeAPIURL, "recipe-api")
	ic := healthcheck.New(cfg.ImportAPIURL, "import-api")

	routerURL, err := url.Parse(cfg.RouterURL)
	if err != nil {
		log.Event(nil, "error parsing router URL", log.Error(err))
		os.Exit(1)
	}
	routerProxy := reverseProxy.Create(routerURL, director)

	zebedeeURL, err := url.Parse(cfg.ZebedeeURL)
	if err != nil {
		log.Event(nil, "error parsing zebedee URL", log.Error(err))
		os.Exit(1)
	}
	zebedeeProxy := reverseProxy.Create(zebedeeURL, zebedeeDirector)

	recipeAPIURL, err := url.Parse(cfg.RecipeAPIURL)
	if err != nil {
		log.Event(nil, "error parsing recipe API URL", log.Error(err))
		os.Exit(1)
	}
	recipeAPIProxy := reverseProxy.Create(recipeAPIURL, nil)

	tableURL, err := url.Parse(cfg.TableRendererURL)
	if err != nil {
		log.Event(nil, "error parsing table renderer URL", log.Error(err))
		os.Exit(1)
	}
	tableProxy := reverseProxy.Create(tableURL, tableDirector)

	importAPIURL, err := url.Parse(cfg.ImportAPIURL)
	if err != nil {
		log.Event(nil, "error parsing import API URL", log.Error(err))
		os.Exit(1)
	}
	importAPIProxy := reverseProxy.Create(importAPIURL, importAPIDirector)

	datasetAPIURL, err := url.Parse(cfg.DatasetAPIURL)
	if err != nil {
		log.Event(nil, "error parsing dataset API URL", log.Error(err))
		os.Exit(1)
	}
	datasetAPIProxy := reverseProxy.Create(datasetAPIURL, datasetAPIDirector)

	datasetControllerURL, err := url.Parse(cfg.DatasetAPIURL)
	if err != nil {
		log.Event(nil, "error parsing dataset controller URL", log.Error(err))
		os.Exit(1)
	}
	datasetControllerProxy := reverseProxy.Create(datasetControllerURL, datasetControllerDirector)

	var vc upload.VaultClient
	if !cfg.EncryptionDisabled {
		vc, err = vault.CreateVaultClient(cfg.VaultToken, cfg.VaultAddr, 3)
		if err != nil {
			log.Event(nil, "error creating vault client", log.Error(err))
			os.Exit(1)
		}
	}

	uploader, err := upload.New(cfg.UploadBucketName, cfg.VaultPath, vc)
	if err != nil {
		log.Event(nil, "error creating file uploader", log.Error(err))
		os.Exit(1)
	}

	router := pat.New()

	router.Path("/healthcheck").HandlerFunc(hc.Do)

	if cfg.SharedConfig.EnableDatasetImport {
		router.Path("/upload").Methods("GET").HandlerFunc(uploader.CheckUploaded)
		router.Path("/upload").Methods("POST").HandlerFunc(uploader.Upload)
		router.Path("/upload/{id}").Methods("GET").HandlerFunc(uploader.GetS3URL)
		router.Handle("/recipes{uri:.*}", recipeAPIProxy)
		router.Handle("/import{uri:.*}", importAPIProxy)
		router.Handle("/dataset/{uri:.*}", datasetAPIProxy)
		router.Handle("/instances/{uri:.*}", datasetAPIProxy)
		router.Handle("/dataset-controller/{uri:.*}", datasetControllerProxy)
	}

	router.Handle("/zebedee{uri:/.*}", zebedeeProxy)
	router.Handle("/table/{uri:.*}", tableProxy)
	router.HandleFunc("/florence/dist/{uri:.*}", staticFiles)
	router.HandleFunc("/florence/", redirectToFlorence)
	router.HandleFunc("/florence/index.html", redirectToFlorence)
	router.Path("/florence/publishing-queue").HandlerFunc(legacyIndexFile(cfg))
	router.Path("/florence/reports").HandlerFunc(legacyIndexFile(cfg))
	router.Path("/florence/workspace").HandlerFunc(legacyIndexFile(cfg))
	router.HandleFunc("/florence/websocket", websocketHandler)
	router.Path("/florence{uri:.*}").HandlerFunc(refactoredIndexFile(cfg))
	router.Handle("/{uri:.*}", routerProxy)

	log.Event(nil, "starting server", log.Data{"config": cfg})

	s := server.New(cfg.BindAddr, router)
	// TODO need to reconsider default go-ns server timeouts
	s.Server.IdleTimeout = 120 * time.Second
	s.Server.WriteTimeout = 120 * time.Second
	s.Server.ReadTimeout = 30 * time.Second
	s.HandleOSSignals = false
	s.Middleware["RequestLogger"] = log.Middleware
	s.MiddlewareOrder = []string{"RequestID", "RequestLogger"}

	// FIXME temporary hack to remove timeout middleware (doesn't support hijacker interface)
	mo := s.MiddlewareOrder
	var newMo []string
	for _, mw := range mo {
		if mw != "Timeout" {
			newMo = append(newMo, mw)
		}
	}
	s.MiddlewareOrder = newMo

	go func() {
		if err := s.ListenAndServe(); err != nil {
			log.Event(nil, "error starting http server", log.Error(err))
			os.Exit(2)
		}
	}()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, os.Kill)

	for {
		hc.MonitorExternal(rtrc, zc, ic, rc, dc)

		timer := time.NewTimer(time.Second * 60)

		select {
		case <-timer.C:
			continue
		case <-stop:
			log.Event(nil, "shutting down gracefully")
			timer.Stop()
			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
			defer cancel()
			if err := s.Server.Shutdown(ctx); err != nil {
				log.Event(nil, "error shutting down gracefully", log.Error(err))
			}
			return
		}
	}
}

func redirectToFlorence(w http.ResponseWriter, req *http.Request) {
	http.Redirect(w, req, "/florence", 301)
}

func staticFiles(w http.ResponseWriter, req *http.Request) {
	path := req.URL.Query().Get(":uri")
	assetPath := "../dist/" + path

	etag, err := getAssetETag(assetPath)

	if hdr := req.Header.Get("If-None-Match"); len(hdr) > 0 && hdr == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	b, err := getAsset(assetPath)
	if err != nil {
		log.Event(req.Context(), "error getting asset", log.Error(err))
		w.WriteHeader(404)
		return
	}

	w.Header().Set(`ETag`, etag)
	w.Header().Set(`Cache-Control`, "no-cache")
	w.Header().Set(`Content-Type`, mime.TypeByExtension(filepath.Ext(path)))
	w.WriteHeader(200)
	w.Write(b)
}

func legacyIndexFile(cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		log.Event(req.Context(), "getting legacy html file")

		b, err := getAsset("../dist/legacy-assets/index.html")
		if err != nil {
			log.Event(req.Context(), "error getting legacy html file", log.Error(err))
			w.WriteHeader(404)
			return
		}

		cfgJSON, err := json.Marshal(cfg.SharedConfig)
		if err != nil {
			log.Event(req.Context(), "error marshalling shared configuration", log.Error(err))
			w.WriteHeader(500)
			return
		}
		b = []byte(strings.Replace(string(b), "/* environment variables placeholder */", "/* server generated shared config */ "+string(cfgJSON), 1))

		w.Header().Set(`Content-Type`, "text/html")
		w.WriteHeader(200)
		w.Write(b)
	}
}

func refactoredIndexFile(cfg *config.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		log.Event(req.Context(), "getting refactored html file")

		b, err := getAsset("../dist/refactored.html")
		if err != nil {
			log.Event(req.Context(), "error getting refactored html file", log.Error(err))
			w.WriteHeader(404)
			return
		}

		cfgJSON, err := json.Marshal(cfg.SharedConfig)
		if err != nil {
			log.Event(req.Context(), "error marshalling shared configuration", log.Error(err))
			w.WriteHeader(500)
			return
		}
		b = []byte(strings.Replace(string(b), "/* environment variables placeholder */", "/* server generated shared config */ "+string(cfgJSON), 1))

		w.Header().Set(`Content-Type`, "text/html")
		w.WriteHeader(200)
		w.Write(b)
	}
}

func zebedeeDirector(req *http.Request) {
	if c, err := req.Cookie(`access_token`); err == nil && len(c.Value) > 0 {
		req.Header.Set(`X-Florence-Token`, c.Value)
	}
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/zebedee")
}

func director(req *http.Request) {
	if accessTokenCookie, err := req.Cookie(common.FlorenceCookieKey); err == nil && len(accessTokenCookie.Value) > 0 {
		req.Header.Set(common.FlorenceHeaderKey, accessTokenCookie.Value)
	}

	if colletionCookie, err := req.Cookie(common.CollectionIDCookieKey); err == nil && len(colletionCookie.Value) > 0 {
		req.Header.Set(common.CollectionIDHeaderKey, colletionCookie.Value)
	}
}

func importAPIDirector(req *http.Request) {
	director(req)
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/import")
}

func tableDirector(req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/table")
}

func datasetAPIDirector(req *http.Request) {
	director(req)
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/dataset")
}

func datasetControllerDirector(req *http.Request) {
	director(req)
	req.URL.Path = strings.TrimPrefix(req.URL.Path, "/dataset-controller")
}

func websocketHandler(w http.ResponseWriter, req *http.Request) {
	c, err := upgrader.Upgrade(w, req, nil)
	if err != nil {
		log.Event(req.Context(), "error upgrading connection to websocket", log.Error(err))
		return
	}

	defer c.Close()

	err = c.WriteJSON(florenceServerEvent{"version", florenceVersionPayload{Version: Version}})
	if err != nil {
		log.Event(req.Context(), "error writing version message", log.Error(err))
		return
	}

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			log.Event(req.Context(), "error reading websocket message", log.Error(err))
			break
		}

		rdr := bufio.NewReader(bytes.NewReader(message))
		b, err := rdr.ReadBytes('{')
		if err != nil {
			log.Event(req.Context(), "error reading websocket bytes", log.Error(err), log.Data{"bytes": string(b)})
			continue
		}

		tags := strings.Split(string(b), ":")
		eventID := tags[0]
		eventType := tags[1]
		eventData := message[len(eventID)+len(eventType)+2:]

		switch eventType {
		case "log":
			var e florenceLogEvent
			e.ServerTimestamp = time.Now().UTC().Format("2006-01-02T15:04:05.000-0700Z")
			err = json.Unmarshal(eventData, &e)
			if err != nil {
				log.Event(req.Context(), "error unmarshalling websocket message", log.Error(err), log.Data{"data": string(eventData)})
				continue
			}
			log.Event(req.Context(), "client log", log.Data{"data": e})

			err = c.WriteJSON(florenceServerEvent{"ack", eventID})
			if err != nil {
				log.Event(req.Context(), "error writing websocket ack", log.Error(err))
			}
		default:
			log.Event(req.Context(), "unknown websocket event type", log.Data{"type": eventType, "data": string(eventData)})
		}
	}
}

type florenceLogEvent struct {
	ServerTimestamp string      `json:"-"`
	ClientTimestamp time.Time   `json:"clientTimestamp"`
	Type            string      `json:"type"`
	Location        string      `json:"location"`
	InstanceID      string      `json:"instanceID"`
	Payload         interface{} `json:"payload"`
}

type florenceServerEvent struct {
	Type    string      `json:"type"`
	Payload interface{} `json:"payload"`
}

type florenceVersionPayload struct {
	Version string `json:"version"`
}
<|endoftext|>