<commit_before>package godog

import (
	"bytes"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
	"time"
	"unicode"
)

var compiler = filepath.Join(build.ToolDir, "compile")
var linker = filepath.Join(build.ToolDir, "link")
var gopaths = filepath.SplitList(build.Default.GOPATH)
var goarch = build.Default.GOARCH
var goos = build.Default.GOOS

var godogImportPath = "github.com/DATA-DOG/godog"
var runnerTemplate = template.Must(template.New("testmain").Parse(`package main

import (
	"github.com/DATA-DOG/godog"
	{{if .Contexts}}_test "{{.ImportPath}}"{{end}}
	"os"
)

func main() {
	status := godog.Run(func (suite *godog.Suite) {
		{{range .Contexts}}
			_test.{{ . }}(suite)
		{{end}}
	})
	os.Exit(status)
}`))

// Build creates a test package like go test command.
// If there are no go files in tested directory, then
// it simply builds a godog executable to scan features.
//
// If there are go test files, it first builds a test
// package with standard go test command.
//
// Finally it generates godog suite executable which
// registers exported godog contexts from the test files
// of tested package.
//
// Returns the path to generated executable
func Build() (string, error) {
	abs, err := filepath.Abs(".")
	if err != nil {
		return "", err
	}

	bin := filepath.Join(abs, "godog.test")
	// suffix with .exe for windows
	if goos == "windows" {
		bin += ".exe"
	}

	// we allow package to be nil, if godog is run only when
	// there is a feature file in empty directory
	pkg, _ := build.ImportDir(abs, 0)
	src, anyContexts, err := buildTestMain(pkg)
	if err != nil {
		return bin, err
	}

	workdir := fmt.Sprintf(filepath.Join("%s", "godog-%d"), os.TempDir(), time.Now().UnixNano())
	testdir := workdir

	// if none of test files exist, or there are no contexts found
	// we will skip test package compilation, since it is useless
	if anyContexts {
		// first of all compile test package dependencies
		// that will save was many compilations for dependencies
		// go does it better
		out, err := exec.Command("go", "test", "-i").CombinedOutput()
		if err != nil {
			return bin, fmt.Errorf("failed to compile package %s:\n%s", pkg.Name, string(out))
		}

		// let go do the dirty work and compile test
		// package with it's dependencies. Older go
		// versions does not accept existing file output
		// so we create a temporary executable which will
		// removed.
		temp := fmt.Sprintf(filepath.Join("%s", "temp-%d.test"), os.TempDir(), time.Now().UnixNano())

		// builds and compile the tested package.
		// generated test executable will be removed
		// since we do not need it for godog suite.
		// we also print back the temp WORK directory
		// go has built. We will reuse it for our suite workdir.
		out, err = exec.Command("go", "test", "-c", "-work", "-o", temp).CombinedOutput()
		if err != nil {
			return bin, fmt.Errorf("failed to compile tested package %s:\n%s", pkg.Name, string(out))
		}
		defer os.Remove(temp)

		// extract go-build temporary directory as our workdir
		workdir = strings.TrimSpace(string(out))
		if !strings.HasPrefix(workdir, "WORK=") {
			return bin, fmt.Errorf("expected WORK dir path, but got: %s", workdir)
		}
		workdir = strings.Replace(workdir, "WORK=", "", 1)
		testdir = filepath.Join(workdir, pkg.ImportPath, "_test")
	} else {
		// still need to create temporary workdir
		if err = os.MkdirAll(testdir, 0755); err != nil {
			return bin, err
		}
	}
	defer os.RemoveAll(workdir)

	// replace _testmain.go file with our own
	testmain := filepath.Join(testdir, "_testmain.go")
	err = ioutil.WriteFile(testmain, src, 0644)
	if err != nil {
		return bin, err
	}

	// godog library may not be imported in tested package
	// but we need it for our testmain package.
	// So we look it up in available source paths
	// including vendor directory, supported since 1.5.
	try := maybeVendorPaths(abs)
	for _, d := range build.Default.SrcDirs() {
		try = append(try, filepath.Join(d, godogImportPath))
	}
	godogPkg, err := locatePackage(try)
	if err != nil {
		return bin, err
	}

	// make sure godog package archive is installed, gherkin
	// will be installed as dependency of godog
	cmd := exec.Command("go", "install", godogPkg.ImportPath)
	cmd.Env = os.Environ()
	out, err := cmd.CombinedOutput()
	if err != nil {
		return bin, fmt.Errorf("failed to install godog package:\n%s", string(out))
	}

	// collect all possible package dirs, will be
	// used for includes and linker
	pkgDirs := []string{workdir, testdir}
	for _, gopath := range gopaths {
		pkgDirs = append(pkgDirs, filepath.Join(gopath, "pkg", goos+"_"+goarch))
	}
	pkgDirs = uniqStringList(pkgDirs)

	// compile godog testmain package archive
	// we do not depend on CGO so a lot of checks are not necessary
	testMainPkgOut := filepath.Join(testdir, "main.a")
	args := []string{
		"-o", testMainPkgOut,
		// "-trimpath", workdir,
		"-p", "main",
		"-complete",
	}
	// if godog library is in vendor directory
	// link it with import map
	if i := strings.LastIndex(godogPkg.ImportPath, "vendor/"); i != -1 {
		args = append(args, "-importmap", godogImportPath+"="+godogPkg.ImportPath)
	}
	for _, inc := range pkgDirs {
		args = append(args, "-I", inc)
	}
	args = append(args, "-pack", testmain)
	cmd = exec.Command(compiler, args...)
	cmd.Env = os.Environ()
	out, err = cmd.CombinedOutput()
	if err != nil {
		return bin, fmt.Errorf("failed to compile testmain package:\n%s", string(out))
	}

	// link test suite executable
	args = []string{
		"-o", bin,
		"-extld", build.Default.Compiler,
		"-buildmode=exe",
	}
	for _, link := range pkgDirs {
		args = append(args, "-L", link)
	}
	args = append(args, testMainPkgOut)
	cmd = exec.Command(linker, args...)
	cmd.Env = os.Environ()

	out, err = cmd.CombinedOutput()
	if err != nil {
		return bin, fmt.Errorf("failed to link test executable:\n%s", string(out))
	}

	return bin, nil
}

func locatePackage(try []string) (*build.Package, error) {
	for _, path := range try {
		abs, err := filepath.Abs(path)
		if err != nil {
			continue
		}
		pkg, err := build.ImportDir(abs, 0)
		if err != nil {
			continue
		}
		return pkg, nil
	}
	return nil, fmt.Errorf("failed to find godog package in any of:\n%s", strings.Join(try, "\n"))
}

func uniqStringList(strs []string) (unique []string) {
	uniq := make(map[string]void, len(strs))
	for _, s := range strs {
		if _, ok := uniq[s]; !ok {
			uniq[s] = void{}
			unique = append(unique, s)
		}
	}
	return
}

// buildTestMain if given package is valid
// it scans test files for contexts
// and produces a testmain source code.
func buildTestMain(pkg *build.Package) ([]byte, bool, error) {
	var contexts []string
	var importPath string
	name := "main"
	if nil != pkg {
		ctxs, err := processPackageTestFiles(
			pkg.TestGoFiles,
			pkg.XTestGoFiles,
		)
		if err != nil {
			return nil, false, err
		}
		contexts = ctxs
		importPath = pkg.ImportPath
		name = pkg.Name
	}

	data := struct {
		Name       string
		Contexts   []string
		ImportPath string
	}{name, contexts, importPath}

	var buf bytes.Buffer
	if err := runnerTemplate.Execute(&buf, data); err != nil {
		return nil, len(contexts) > 0, err
	}
	return buf.Bytes(), len(contexts) > 0, nil
}

// maybeVendorPaths determines possible vendor paths
// which goes levels down from given directory
// until it reaches GOPATH source dir
func maybeVendorPaths(dir string) []string {
	paths := []string{filepath.Join(dir, "vendor", godogImportPath)}
	for _, gopath := range gopaths {
		if !strings.HasPrefix(dir, gopath) {
			continue
		}

		for p := filepath.Dir(dir); p != filepath.Join(gopath, "src"); p = filepath.Dir(p) {
			paths = append(paths, filepath.Join(p, "vendor", godogImportPath))
		}
	}
	return paths
}

// processPackageTestFiles runs through ast of each test
// file pack and looks for godog suite contexts to register
// on run
func processPackageTestFiles(packs ...[]string) ([]string, error) {
	var ctxs []string
	fset := token.NewFileSet()
	for _, pack := range packs {
		for _, testFile := range pack {
			node, err := parser.ParseFile(fset, testFile, nil, 0)
			if err != nil {
				return ctxs, err
			}

			ctxs = append(ctxs, astContexts(node)...)
		}
	}
	var failed []string
	for _, ctx := range ctxs {
		runes := []rune(ctx)
		if unicode.IsLower(runes[0]) {
			expected := append([]rune{unicode.ToUpper(runes[0])}, runes[1:]...)
			failed = append(failed, fmt.Sprintf("%s - should be: %s", ctx, string(expected)))
		}
	}
	if len(failed) > 0 {
		return ctxs, fmt.Errorf("godog contexts must be exported:\n\t%s", strings.Join(failed, "\n\t"))
	}
	return ctxs, nil
}
<commit_msg>remove unnecessary linker flag<commit_after>package godog

import (
	"bytes"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
	"time"
	"unicode"
)

var compiler = filepath.Join(build.ToolDir, "compile")
var linker = filepath.Join(build.ToolDir, "link")
var gopaths = filepath.SplitList(build.Default.GOPATH)
var goarch = build.Default.GOARCH
var goos = build.Default.GOOS

var godogImportPath = "github.com/DATA-DOG/godog"
var runnerTemplate = template.Must(template.New("testmain").Parse(`package main

import (
	"github.com/DATA-DOG/godog"
	{{if .Contexts}}_test "{{.ImportPath}}"{{end}}
	"os"
)

func main() {
	status := godog.Run(func (suite *godog.Suite) {
		{{range .Contexts}}
			_test.{{ . }}(suite)
		{{end}}
	})
	os.Exit(status)
}`))

// Build creates a test package like go test command.
// If there are no go files in tested directory, then
// it simply builds a godog executable to scan features.
//
// If there are go test files, it first builds a test
// package with standard go test command.
//
// Finally it generates godog suite executable which
// registers exported godog contexts from the test files
// of tested package.
//
// Returns the path to generated executable
func Build() (string, error) {
	abs, err := filepath.Abs(".")
	if err != nil {
		return "", err
	}

	bin := filepath.Join(abs, "godog.test")
	// suffix with .exe for windows
	if goos == "windows" {
		bin += ".exe"
	}

	// we allow package to be nil, if godog is run only when
	// there is a feature file in empty directory
	pkg, _ := build.ImportDir(abs, 0)
	src, anyContexts, err := buildTestMain(pkg)
	if err != nil {
		return bin, err
	}

	workdir := fmt.Sprintf(filepath.Join("%s", "godog-%d"), os.TempDir(), time.Now().UnixNano())
	testdir := workdir

	// if none of test files exist, or there are no contexts found
	// we will skip test package compilation, since it is useless
	if anyContexts {
		// first of all compile test package dependencies
		// that will save was many compilations for dependencies
		// go does it better
		out, err := exec.Command("go", "test", "-i").CombinedOutput()
		if err != nil {
			return bin, fmt.Errorf("failed to compile package %s:\n%s", pkg.Name, string(out))
		}

		// let go do the dirty work and compile test
		// package with it's dependencies. Older go
		// versions does not accept existing file output
		// so we create a temporary executable which will
		// removed.
		temp := fmt.Sprintf(filepath.Join("%s", "temp-%d.test"), os.TempDir(), time.Now().UnixNano())

		// builds and compile the tested package.
		// generated test executable will be removed
		// since we do not need it for godog suite.
		// we also print back the temp WORK directory
		// go has built. We will reuse it for our suite workdir.
		out, err = exec.Command("go", "test", "-c", "-work", "-o", temp).CombinedOutput()
		if err != nil {
			return bin, fmt.Errorf("failed to compile tested package %s:\n%s", pkg.Name, string(out))
		}
		defer os.Remove(temp)

		// extract go-build temporary directory as our workdir
		workdir = strings.TrimSpace(string(out))
		if !strings.HasPrefix(workdir, "WORK=") {
			return bin, fmt.Errorf("expected WORK dir path, but got: %s", workdir)
		}
		workdir = strings.Replace(workdir, "WORK=", "", 1)
		testdir = filepath.Join(workdir, pkg.ImportPath, "_test")
	} else {
		// still need to create temporary workdir
		if err = os.MkdirAll(testdir, 0755); err != nil {
			return bin, err
		}
	}
	defer os.RemoveAll(workdir)

	// replace _testmain.go file with our own
	testmain := filepath.Join(testdir, "_testmain.go")
	err = ioutil.WriteFile(testmain, src, 0644)
	if err != nil {
		return bin, err
	}

	// godog library may not be imported in tested package
	// but we need it for our testmain package.
	// So we look it up in available source paths
	// including vendor directory, supported since 1.5.
	try := maybeVendorPaths(abs)
	for _, d := range build.Default.SrcDirs() {
		try = append(try, filepath.Join(d, godogImportPath))
	}
	godogPkg, err := locatePackage(try)
	if err != nil {
		return bin, err
	}

	// make sure godog package archive is installed, gherkin
	// will be installed as dependency of godog
	cmd := exec.Command("go", "install", godogPkg.ImportPath)
	cmd.Env = os.Environ()
	out, err := cmd.CombinedOutput()
	if err != nil {
		return bin, fmt.Errorf("failed to install godog package:\n%s", string(out))
	}

	// collect all possible package dirs, will be
	// used for includes and linker
	pkgDirs := []string{workdir, testdir}
	for _, gopath := range gopaths {
		pkgDirs = append(pkgDirs, filepath.Join(gopath, "pkg", goos+"_"+goarch))
	}
	pkgDirs = uniqStringList(pkgDirs)

	// compile godog testmain package archive
	// we do not depend on CGO so a lot of checks are not necessary
	testMainPkgOut := filepath.Join(testdir, "main.a")
	args := []string{
		"-o", testMainPkgOut,
		// "-trimpath", workdir,
		"-p", "main",
		"-complete",
	}
	// if godog library is in vendor directory
	// link it with import map
	if i := strings.LastIndex(godogPkg.ImportPath, "vendor/"); i != -1 {
		args = append(args, "-importmap", godogImportPath+"="+godogPkg.ImportPath)
	}
	for _, inc := range pkgDirs {
		args = append(args, "-I", inc)
	}
	args = append(args, "-pack", testmain)
	cmd = exec.Command(compiler, args...)
	cmd.Env = os.Environ()
	out, err = cmd.CombinedOutput()
	if err != nil {
		return bin, fmt.Errorf("failed to compile testmain package:\n%s", string(out))
	}

	// link test suite executable
	args = []string{
		"-o", bin,
		"-buildmode=exe",
	}
	for _, link := range pkgDirs {
		args = append(args, "-L", link)
	}
	args = append(args, testMainPkgOut)
	cmd = exec.Command(linker, args...)
	cmd.Env = os.Environ()

	out, err = cmd.CombinedOutput()
	if err != nil {
		msg := `failed to link test executable:
	reason: %s
	command: %s`
		return bin, fmt.Errorf(msg, string(out), linker+" '"+strings.Join(args, "' '")+"'")
	}

	return bin, nil
}

func locatePackage(try []string) (*build.Package, error) {
	for _, path := range try {
		abs, err := filepath.Abs(path)
		if err != nil {
			continue
		}
		pkg, err := build.ImportDir(abs, 0)
		if err != nil {
			continue
		}
		return pkg, nil
	}
	return nil, fmt.Errorf("failed to find godog package in any of:\n%s", strings.Join(try, "\n"))
}

func uniqStringList(strs []string) (unique []string) {
	uniq := make(map[string]void, len(strs))
	for _, s := range strs {
		if _, ok := uniq[s]; !ok {
			uniq[s] = void{}
			unique = append(unique, s)
		}
	}
	return
}

// buildTestMain if given package is valid
// it scans test files for contexts
// and produces a testmain source code.
func buildTestMain(pkg *build.Package) ([]byte, bool, error) {
	var contexts []string
	var importPath string
	name := "main"
	if nil != pkg {
		ctxs, err := processPackageTestFiles(
			pkg.TestGoFiles,
			pkg.XTestGoFiles,
		)
		if err != nil {
			return nil, false, err
		}
		contexts = ctxs
		importPath = pkg.ImportPath
		name = pkg.Name
	}

	data := struct {
		Name       string
		Contexts   []string
		ImportPath string
	}{name, contexts, importPath}

	var buf bytes.Buffer
	if err := runnerTemplate.Execute(&buf, data); err != nil {
		return nil, len(contexts) > 0, err
	}
	return buf.Bytes(), len(contexts) > 0, nil
}

// maybeVendorPaths determines possible vendor paths
// which goes levels down from given directory
// until it reaches GOPATH source dir
func maybeVendorPaths(dir string) []string {
	paths := []string{filepath.Join(dir, "vendor", godogImportPath)}
	for _, gopath := range gopaths {
		if !strings.HasPrefix(dir, gopath) {
			continue
		}

		for p := filepath.Dir(dir); p != filepath.Join(gopath, "src"); p = filepath.Dir(p) {
			paths = append(paths, filepath.Join(p, "vendor", godogImportPath))
		}
	}
	return paths
}

// processPackageTestFiles runs through ast of each test
// file pack and looks for godog suite contexts to register
// on run
func processPackageTestFiles(packs ...[]string) ([]string, error) {
	var ctxs []string
	fset := token.NewFileSet()
	for _, pack := range packs {
		for _, testFile := range pack {
			node, err := parser.ParseFile(fset, testFile, nil, 0)
			if err != nil {
				return ctxs, err
			}

			ctxs = append(ctxs, astContexts(node)...)
		}
	}
	var failed []string
	for _, ctx := range ctxs {
		runes := []rune(ctx)
		if unicode.IsLower(runes[0]) {
			expected := append([]rune{unicode.ToUpper(runes[0])}, runes[1:]...)
			failed = append(failed, fmt.Sprintf("%s - should be: %s", ctx, string(expected)))
		}
	}
	if len(failed) > 0 {
		return ctxs, fmt.Errorf("godog contexts must be exported:\n\t%s", strings.Join(failed, "\n\t"))
	}
	return ctxs, nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

// Package shim provides APIs for the chaincode to access its state
// variables, transaction context and call other chaincodes.
package shim

import (
	"context"
	"encoding/base64"
	"flag"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric/core/comm"
	pb "github.com/hyperledger/fabric/protos/peer"
	logging "github.com/op/go-logging"
	"github.com/pkg/errors"
	"google.golang.org/grpc"
)

// Logger for the shim package.
var chaincodeLogger = logging.MustGetLogger("shim")

const (
	minUnicodeRuneValue   = 0            //U+0000
	maxUnicodeRuneValue   = utf8.MaxRune //U+10FFFF - maximum (and unallocated) code point
	compositeKeyNamespace = "\x00"
	emptyKeySubstitute    = "\x01"
)

//this separates the chaincode stream interface establishment
//so we can replace it with a mock peer stream
type peerStreamGetter func(name string) (PeerChaincodeStream, error)

//UTs to setup mock peer stream getter
var streamGetter peerStreamGetter

//the non-mock user CC stream establishment func
func userChaincodeStreamGetter(name string) (PeerChaincodeStream, error) {
	chaincodeLogger.Debugf("os.Args returns: %s", os.Args)
	peerAddress := flag.String("peer.address", "", "peer address")
	flag.Parse()
	if *peerAddress == "" {
		return nil, errors.New("flag 'peer.address' must be set")
	}
	chaincodeLogger.Debugf("Peer address: %s", *peerAddress)

	// Establish connection with validating peer
	clientConn, err := newPeerClientConnection(*peerAddress)
	if err != nil {
		err = errors.Wrap(err, "error trying to connect to local peer")
		chaincodeLogger.Errorf("%+v", err)
		return nil, err
	}

	// establish stream with peer
	chaincodeSupportClient := pb.NewChaincodeSupportClient(clientConn)
	stream, err := chaincodeSupportClient.Register(context.Background())
	if err != nil {
		return nil, errors.WithMessagef(
			err,
			"error connecting to peer address %s",
			*peerAddress,
		)
	}
	return stream, nil
}

// chaincodes.
func Start(cc Chaincode) error {
	chaincodename := os.Getenv("CORE_CHAINCODE_ID_NAME")
	if chaincodename == "" {
		return errors.New("'CORE_CHAINCODE_ID_NAME' must be set")
	}

	//mock stream not set up ... get real stream
	if streamGetter == nil {
		streamGetter = userChaincodeStreamGetter
	}

	stream, err := streamGetter(chaincodename)
	if err != nil {
		return err
	}

	err = chatWithPeer(chaincodename, stream, cc)

	return err
}

// StartInProc is an entry point for system chaincodes bootstrap. It is not an
// API for chaincodes.
func StartInProc(env []string, args []string, cc Chaincode, recv <-chan *pb.ChaincodeMessage, send chan<- *pb.ChaincodeMessage) error {
	chaincodeLogger.Debugf("in proc %v", args)

	var chaincodename string
	for _, v := range env {
		if strings.Index(v, "CORE_CHAINCODE_ID_NAME=") == 0 {
			p := strings.SplitAfter(v, "CORE_CHAINCODE_ID_NAME=")
			chaincodename = p[1]
			break
		}
	}
	if chaincodename == "" {
		return errors.New("'CORE_CHAINCODE_ID_NAME' must be set")
	}

	stream := newInProcStream(recv, send)
	chaincodeLogger.Debugf("starting chat with peer using name=%s", chaincodename)
	err := chatWithPeer(chaincodename, stream, cc)
	return err
}

func newPeerClientConnection(address string) (*grpc.ClientConn, error) {

	// set the keepalive options to match static settings for chaincode server
	kaOpts := &comm.KeepaliveOptions{
		ClientInterval: time.Duration(1) * time.Minute,
		ClientTimeout:  time.Duration(20) * time.Second,
	}
	secOpts, err := secureOptions()
	if err != nil {
		return nil, err
	}
	config := comm.ClientConfig{
		KaOpts:  kaOpts,
		SecOpts: secOpts,
		Timeout: 3 * time.Second,
	}

	client, err := comm.NewGRPCClient(config)
	if err != nil {
		return nil, err
	}
	return client.NewConnection(address, "")
}

func secureOptions() (*comm.SecureOptions, error) {

	tlsEnabled, err := strconv.ParseBool(os.Getenv("CORE_PEER_TLS_ENABLED"))
	if err != nil {
		return nil, errors.WithMessage(
			err,
			"'CORE_PEER_TLS_ENABLED' must be set to 'true' or 'false'",
		)
	}
	if tlsEnabled {
		data, err := ioutil.ReadFile(os.Getenv("CORE_TLS_CLIENT_KEY_PATH"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read private key file")
		}
		key, err := base64.StdEncoding.DecodeString(string(data))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to decode private key file")
		}
		data, err = ioutil.ReadFile(os.Getenv("CORE_TLS_CLIENT_CERT_PATH"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read public key file")
		}
		cert, err := base64.StdEncoding.DecodeString(string(data))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to decode public key file")
		}
		root, err := ioutil.ReadFile(os.Getenv("CORE_PEER_TLS_ROOTCERT_FILE"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read root cert file")
		}
		return &comm.SecureOptions{
				UseTLS:            true,
				Certificate:       []byte(cert),
				Key:               []byte(key),
				ServerRootCAs:     [][]byte{root},
				RequireClientCert: true,
			},
			nil
	}
	return &comm.SecureOptions{}, nil
}

func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode) error {
	// Create the shim handler responsible for all control logic
	handler := newChaincodeHandler(stream, cc)
	defer stream.CloseSend()

	// Send the ChaincodeID during register.
	chaincodeID := &pb.ChaincodeID{Name: chaincodename}
	payload, err := proto.Marshal(chaincodeID)
	if err != nil {
		return errors.Wrap(err, "error marshalling chaincodeID during chaincode registration")
	}

	// Register on the stream
	chaincodeLogger.Debugf("Registering.. sending %s", pb.ChaincodeMessage_REGISTER)
	if err = handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload}); err != nil {
		return errors.WithMessage(err, "error sending chaincode REGISTER")
	}

	// holds return values from gRPC Recv below
	type recvMsg struct {
		msg *pb.ChaincodeMessage
		err error
	}
	msgAvail := make(chan *recvMsg, 1)
	errc := make(chan error)

	receiveMessage := func() {
		in, err := stream.Recv()
		msgAvail <- &recvMsg{in, err}
	}

	go receiveMessage()
	for {
		select {
		case rmsg := <-msgAvail:
			switch {
			case rmsg.err == io.EOF:
				err = errors.Wrapf(rmsg.err, "received EOF, ending chaincode stream")
				chaincodeLogger.Debugf("%+v", err)
				return err
			case rmsg.err != nil:
				err := errors.Wrap(rmsg.err, "receive failed")
				chaincodeLogger.Errorf("Received error from server, ending chaincode stream: %+v", err)
				return err
			case rmsg.msg == nil:
				err := errors.New("received nil message, ending chaincode stream")
				chaincodeLogger.Debugf("%+v", err)
				return err
			default:
				chaincodeLogger.Debugf("[%s]Received message %s from peer", shorttxid(rmsg.msg.Txid), rmsg.msg.Type)
				err := handler.handleMessage(rmsg.msg, errc)
				if err != nil {
					err = errors.WithMessage(err, "error handling message")
					return err
				}

				go receiveMessage()
			}

		case sendErr := <-errc:
			if sendErr != nil {
				err := errors.Wrap(sendErr, "error sending")
				return err
			}
		}
	}
}
<commit_msg>[FAB-15366] Remove go-logging from shim<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

// Package shim provides APIs for the chaincode to access its state
// variables, transaction context and call other chaincodes.
package shim

import (
	"context"
	"encoding/base64"
	"flag"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric/core/comm"
	pb "github.com/hyperledger/fabric/protos/peer"
	"github.com/pkg/errors"
	"google.golang.org/grpc"
)

const (
	minUnicodeRuneValue   = 0            //U+0000
	maxUnicodeRuneValue   = utf8.MaxRune //U+10FFFF - maximum (and unallocated) code point
	compositeKeyNamespace = "\x00"
	emptyKeySubstitute    = "\x01"
)

//this separates the chaincode stream interface establishment
//so we can replace it with a mock peer stream
type peerStreamGetter func(name string) (PeerChaincodeStream, error)

//UTs to setup mock peer stream getter
var streamGetter peerStreamGetter

//the non-mock user CC stream establishment func
func userChaincodeStreamGetter(name string) (PeerChaincodeStream, error) {
	peerAddress := flag.String("peer.address", "", "peer address")
	flag.Parse()
	if *peerAddress == "" {
		return nil, errors.New("flag 'peer.address' must be set")
	}

	// Establish connection with validating peer
	clientConn, err := newPeerClientConnection(*peerAddress)
	if err != nil {
		err = errors.Wrap(err, "error trying to connect to local peer")
		return nil, err
	}

	// establish stream with peer
	chaincodeSupportClient := pb.NewChaincodeSupportClient(clientConn)
	stream, err := chaincodeSupportClient.Register(context.Background())
	if err != nil {
		return nil, errors.WithMessagef(
			err,
			"error connecting to peer address %s",
			*peerAddress,
		)
	}
	return stream, nil
}

// chaincodes.
func Start(cc Chaincode) error {
	chaincodename := os.Getenv("CORE_CHAINCODE_ID_NAME")
	if chaincodename == "" {
		return errors.New("'CORE_CHAINCODE_ID_NAME' must be set")
	}

	//mock stream not set up ... get real stream
	if streamGetter == nil {
		streamGetter = userChaincodeStreamGetter
	}

	stream, err := streamGetter(chaincodename)
	if err != nil {
		return err
	}

	err = chatWithPeer(chaincodename, stream, cc)

	return err
}

// StartInProc is an entry point for system chaincodes bootstrap. It is not an
// API for chaincodes.
func StartInProc(env []string, args []string, cc Chaincode, recv <-chan *pb.ChaincodeMessage, send chan<- *pb.ChaincodeMessage) error {
	var chaincodename string
	for _, v := range env {
		if strings.Index(v, "CORE_CHAINCODE_ID_NAME=") == 0 {
			p := strings.SplitAfter(v, "CORE_CHAINCODE_ID_NAME=")
			chaincodename = p[1]
			break
		}
	}
	if chaincodename == "" {
		return errors.New("'CORE_CHAINCODE_ID_NAME' must be set")
	}

	stream := newInProcStream(recv, send)
	err := chatWithPeer(chaincodename, stream, cc)
	return err
}

func newPeerClientConnection(address string) (*grpc.ClientConn, error) {

	// set the keepalive options to match static settings for chaincode server
	kaOpts := &comm.KeepaliveOptions{
		ClientInterval: time.Duration(1) * time.Minute,
		ClientTimeout:  time.Duration(20) * time.Second,
	}
	secOpts, err := secureOptions()
	if err != nil {
		return nil, err
	}
	config := comm.ClientConfig{
		KaOpts:  kaOpts,
		SecOpts: secOpts,
		Timeout: 3 * time.Second,
	}

	client, err := comm.NewGRPCClient(config)
	if err != nil {
		return nil, err
	}
	return client.NewConnection(address, "")
}

func secureOptions() (*comm.SecureOptions, error) {

	tlsEnabled, err := strconv.ParseBool(os.Getenv("CORE_PEER_TLS_ENABLED"))
	if err != nil {
		return nil, errors.WithMessage(
			err,
			"'CORE_PEER_TLS_ENABLED' must be set to 'true' or 'false'",
		)
	}
	if tlsEnabled {
		data, err := ioutil.ReadFile(os.Getenv("CORE_TLS_CLIENT_KEY_PATH"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read private key file")
		}
		key, err := base64.StdEncoding.DecodeString(string(data))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to decode private key file")
		}
		data, err = ioutil.ReadFile(os.Getenv("CORE_TLS_CLIENT_CERT_PATH"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read public key file")
		}
		cert, err := base64.StdEncoding.DecodeString(string(data))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to decode public key file")
		}
		root, err := ioutil.ReadFile(os.Getenv("CORE_PEER_TLS_ROOTCERT_FILE"))
		if err != nil {
			return nil, errors.WithMessage(err, "failed to read root cert file")
		}
		return &comm.SecureOptions{
				UseTLS:            true,
				Certificate:       []byte(cert),
				Key:               []byte(key),
				ServerRootCAs:     [][]byte{root},
				RequireClientCert: true,
			},
			nil
	}
	return &comm.SecureOptions{}, nil
}

func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode) error {
	// Create the shim handler responsible for all control logic
	handler := newChaincodeHandler(stream, cc)
	defer stream.CloseSend()

	// Send the ChaincodeID during register.
	chaincodeID := &pb.ChaincodeID{Name: chaincodename}
	payload, err := proto.Marshal(chaincodeID)
	if err != nil {
		return errors.Wrap(err, "error marshalling chaincodeID during chaincode registration")
	}

	// Register on the stream
	if err = handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload}); err != nil {
		return errors.WithMessage(err, "error sending chaincode REGISTER")
	}

	// holds return values from gRPC Recv below
	type recvMsg struct {
		msg *pb.ChaincodeMessage
		err error
	}
	msgAvail := make(chan *recvMsg, 1)
	errc := make(chan error)

	receiveMessage := func() {
		in, err := stream.Recv()
		msgAvail <- &recvMsg{in, err}
	}

	go receiveMessage()
	for {
		select {
		case rmsg := <-msgAvail:
			switch {
			case rmsg.err == io.EOF:
				err = errors.Wrapf(rmsg.err, "received EOF, ending chaincode stream")
				return err
			case rmsg.err != nil:
				err := errors.Wrap(rmsg.err, "receive failed")
				return err
			case rmsg.msg == nil:
				err := errors.New("received nil message, ending chaincode stream")
				return err
			default:
				err := handler.handleMessage(rmsg.msg, errc)
				if err != nil {
					err = errors.WithMessage(err, "error handling message")
					return err
				}

				go receiveMessage()
			}

		case sendErr := <-errc:
			if sendErr != nil {
				err := errors.Wrap(sendErr, "error sending")
				return err
			}
		}
	}
}
<|endoftext|>


<commit_before>package gocd

import (
	"context"
	"fmt"
)

type PipelinesService service

type Pipeline struct {
	Name                  string     `json:"name"`
	LabelTemplate         string     `json:"label_template,omitempty"`
	EnablePipelineLocking bool       `json:"enable_pipeline_locking,omitempty"`
	Template              string     `json:"template,omitempty"`
	Materials             []Material `json:"materials,omitempty"`
	Stages                []Stage    `json:"stages"`
	Version               string
}

type Material struct {
	Type string `json:"type"`
	Attributes struct {
		Url             string      `json:"url"`
		Destination     string      `json:"destination,omitempty"`
		Filter          interface{} `json:"filter,omitempty"`
		InvertFilter    bool        `json:"invert_filter,omitempty"`
		Name            string      `json:"name,omitempty"`
		AutoUpdate      bool        `json:"auto_update,omitempty"`
		Branch          string      `json:"branch,omitempty"`
		SubmoduleFolder string      `json:"submodule_folder,omitempty"`
		ShallowClone    bool        `json:"shallow_clone,omitempty"`
	} `json:"attributes"`
}

type PipelineHistory struct {
	Pipelines []*PipelineInstance `json:"pipelines"`
}
type PipelineInstance struct {
}

func (pgs *PipelinesService) GetHistory(ctx context.Context, name string, offset int) (*PipelineHistory, *APIResponse, error) {
	stub := fmt.Sprintf("pipelines/%s/history", name)
	if offset > 0 {
		stub = fmt.Sprintf("%s/%d", stub, offset)
	}
	u, err := addOptions(stub)

	if err != nil {
		return nil, nil, err
	}

	req, err := pgs.client.NewRequest("GET", u, nil, apiV3)
	if err != nil {
		return nil, nil, err
	}

	pt := PipelineHistory{}
	resp, err := pgs.client.Do(ctx, req, &pt)
	if err != nil {
		return nil, resp, err
	}

	return &pt, resp, nil
}
<commit_msg>Autocommit for 'gofmt -w'.<commit_after>package gocd

import (
	"context"
	"fmt"
)

type PipelinesService service

type Pipeline struct {
	Name                  string     `json:"name"`
	LabelTemplate         string     `json:"label_template,omitempty"`
	EnablePipelineLocking bool       `json:"enable_pipeline_locking,omitempty"`
	Template              string     `json:"template,omitempty"`
	Materials             []Material `json:"materials,omitempty"`
	Stages                []Stage    `json:"stages"`
	Version               string
}

type Material struct {
	Type       string `json:"type"`
	Attributes struct {
		Url             string      `json:"url"`
		Destination     string      `json:"destination,omitempty"`
		Filter          interface{} `json:"filter,omitempty"`
		InvertFilter    bool        `json:"invert_filter,omitempty"`
		Name            string      `json:"name,omitempty"`
		AutoUpdate      bool        `json:"auto_update,omitempty"`
		Branch          string      `json:"branch,omitempty"`
		SubmoduleFolder string      `json:"submodule_folder,omitempty"`
		ShallowClone    bool        `json:"shallow_clone,omitempty"`
	} `json:"attributes"`
}

type PipelineHistory struct {
	Pipelines []*PipelineInstance `json:"pipelines"`
}
type PipelineInstance struct {
}

func (pgs *PipelinesService) GetHistory(ctx context.Context, name string, offset int) (*PipelineHistory, *APIResponse, error) {
	stub := fmt.Sprintf("pipelines/%s/history", name)
	if offset > 0 {
		stub = fmt.Sprintf("%s/%d", stub, offset)
	}
	u, err := addOptions(stub)

	if err != nil {
		return nil, nil, err
	}

	req, err := pgs.client.NewRequest("GET", u, nil, apiV3)
	if err != nil {
		return nil, nil, err
	}

	pt := PipelineHistory{}
	resp, err := pgs.client.Do(ctx, req, &pt)
	if err != nil {
		return nil, resp, err
	}

	return &pt, resp, nil
}
<|endoftext|>


<commit_before>// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or 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 constants

// Version number string.
const Version = "0.2.11"
<commit_msg>Bump to version v0.2.12<commit_after>// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or 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 constants

// Version number string.
const Version = "0.2.12"
<|endoftext|>


<commit_before>// Go Supervise
// svscan.go - Service controller code
//
// (c) 2015, Christian Senkowski

package main

import (
	"bufio"
	"fmt"
	"github.com/adar/go-supervise/config"
	"io"
	"log/syslog"
	"os"
	"os/exec"
	"sync"
	"time"
)

var LOGGER, LOGERR = syslog.New(syslog.LOG_WARNING, "svscan")
var CONFIG, CONFERR = config.ReadConfig()

const (
	VERSION              = "0.3"
	MAX_SERVICE_STARTUPS = 5
)

type ServiceHandler struct {
	mutex   *sync.Mutex
	service *Service
}

func main() {
	if CONFERR != nil {
		fmt.Printf("Error while reading config ", CONFERR)
	} else {
		start()
	}
}

/**
* Start
* Loops through list of services in etcd database
* and on defined path, resorts those and starts/restarts the services
* which are still active.
 */
func start() {

	if LOGERR != nil {
		panic(LOGERR)
	}

	servicePath := &CONFIG.ServiceConfig.Path
	removeSlashes(servicePath)

	db := new(DB)
	db.getClient()

	LOGGER.Warning(fmt.Sprintf("Scanning %s\n", *servicePath))

	if _, err := os.Stat("/" + *servicePath); err != nil {
		if crErr := os.Mkdir("/"+*servicePath, 0755); crErr != nil {
			LOGGER.Crit(fmt.Sprintf("Scanning %s failed - directory does not exist and is not creatable\n", *servicePath))
			fmt.Printf("Scanning %s failed - directory does not exist and is not creatable\n", *servicePath)
			usage(1)
		}
	}

	runningServices := make(map[string]*Service)

	// Loop knownServices and services in directory
	// If differ, decide which to remove or add
	for {
		servicesInDir := readServiceDir(servicePath)
		db.createNewServicesIfNeeded(&servicesInDir, servicePath)
		knownServices := db.getServices()

		for serviceName, service := range knownServices {
			serviceName := serviceName
			service := service

			srvDone := make(chan error, 1)

			_, ok := runningServices[serviceName]
			if ok != true {
				// service is not yet running
				// so start it and a logger
				go func() {
					err1 := updateServicePaths(&knownServices, servicePath)
					err2 := removeServiceBefore(&servicesInDir, serviceName)
					if err1 == nil && err2 == nil {
						LOGGER.Debug(fmt.Sprintf("%s not yet running\n", serviceName))
						time.Sleep(1 * time.Second)
						sv := new(ServiceHandler)
						sv.mutex = &sync.Mutex{}
						sv.service = service
						sv.startService(srvDone, runningServices, serviceName)
					}
				}()
			} else {
				// the service is running
				// but might have been removed manually (rm)
				err := removeServiceAfter(&servicesInDir, serviceName, runningServices[serviceName], srvDone)
				if err == nil {
					LOGGER.Debug(fmt.Sprintf("%s already running\n", serviceName))
				} else {
					delete(runningServices, serviceName)
				}
			}
		}

		time.Sleep(5 * time.Second)
	}

	LOGGER.Warning("exiting")
}

func (s *ServiceHandler) writeLine(stdin io.WriteCloser, line string) error {
	LOGGER.Debug(fmt.Sprintf("writing \"%s\" to stdin, %s\n", line, stdin))
	_, err := io.WriteString(stdin, line+"\n")
	return err
}

func (s *ServiceHandler) startLogger(loggerDone chan error, stdout io.ReadCloser) {
	if s.service.Startups >= MAX_SERVICE_STARTUPS {
		LOGGER.Crit(fmt.Sprintf("service %s has had too many startups in this session", s.service.Value))
		if len(s.service.LogBuffer) > 0 {
			LOGGER.Crit(fmt.Sprintf("%s - %s", s.service.Value, s.service.LogBuffer))
			s.service.LogBuffer = nil
		}
		return
	}

	s.mutex.Lock()
	s.service.LogCmd = exec.Command("./../multilog/multilog", "-path", "/"+s.service.Value)

	//@TODO rewrite multilog so that it can take stderr and stdout separately
	stdOutBuff := bufio.NewScanner(stdout)
	stdin, err := s.service.LogCmd.StdinPipe()
	if err != nil {
		LOGGER.Crit(fmt.Sprintf("Error while catching stdinpipe of %s, %s", s.service.Value, err))
		s.mutex.Unlock()
		return
	}
	defer stdin.Close()
	err = s.service.LogCmd.Start()
	if err != nil {
		LOGGER.Crit(fmt.Sprintf("Error while starting logger %s", err))
		s.mutex.Unlock()
		return
	}
	s.mutex.Unlock()

	if len(s.service.LogBuffer) > 0 {
		LOGGER.Crit(fmt.Sprintf("found unhandled log lines for %s, writing those first", s.service.Value))
		for _, line := range s.service.LogBuffer {
			err := s.writeLine(stdin, line)
			if err != nil {
				LOGGER.Crit(fmt.Sprintf("Could not write buffered log for %s. error: %s", s.service.Value, err))
				LOGGER.Crit(fmt.Sprintf("%s - %s", s.service.Value, line))
				break
			}
		}
		s.service.LogBuffer = nil
	}

	for stdOutBuff.Scan() {
		err := s.writeLine(stdin, stdOutBuff.Text())
		if err != nil {
			LOGGER.Crit(fmt.Sprintf("IO gone away for %s, %s", s.service.Value, s.service.LogCmd.Process))
			s.service.LogBuffer = append(s.service.LogBuffer, stdOutBuff.Text()+"\n")
			break
		}
	}

	loggerDone <- s.service.LogCmd.Wait()

	select {
	case <-loggerDone:
		LOGGER.Warning(fmt.Sprintf("logger %s done without errors", s.service.Value))
		if len(s.service.LogBuffer) > 0 {
			s.startLogger(loggerDone, stdout)
		}
		break
	case err := <-loggerDone:
		LOGGER.Warning(fmt.Sprintf("logger %s done with error = %v\n", s.service.Value, err))
		s.startLogger(loggerDone, stdout)
		break
	}
}

func (s *ServiceHandler) startService(srvDone chan error, runningServices map[string]*Service, serviceName string) {
	if s.service.Startups >= CONFIG.ServiceConfig.MaxFailedStartups {
		LOGGER.Crit(fmt.Sprintf("service %s has had too many startups in this session", serviceName))
		return

	}
	loggerDone := make(chan error, 1)
	s.mutex.Lock()
	knownServices := new(DB).getServices()
	s.mutex.Unlock()
	if _, ok := knownServices[serviceName]; ok != true {
		return
	}
	LOGGER.Warning(fmt.Sprintf("Starting %s\n", s.service.Value))

	s.service.Cmd = exec.Command("/" + s.service.Value + "/run")

	stdout, _ := s.service.Cmd.StdoutPipe()

	s.service.Startups += 1
	if err := s.service.Cmd.Start(); err != nil {
		LOGGER.Crit(fmt.Sprintf("service %s not startable: %s", serviceName, err))
		return
	}
	LOGGER.Debug(fmt.Sprintf("Starting %s, %s\n", s.service.Cmd.Process, s.service.Value))

	go s.startLogger(loggerDone, stdout)

	runningServices[serviceName] = s.service
	srvDone <- s.service.Cmd.Wait()
	select {
	case err := <-srvDone:
		LOGGER.Warning(fmt.Sprintf("restarting service %s, %s", serviceName, err))
		if s.service.LogCmd != nil && s.service.LogCmd.Process != nil {
			loggerDone <- s.service.LogCmd.Process.Kill()
		}
		time.Sleep(time.Duration(CONFIG.ServiceConfig.TimeWaitBetweenStartups) * time.Second)
		s.startService(srvDone, runningServices, serviceName)
	}
}

func usage(code int) {
	fmt.Printf(
		`go- %s - (c) 2015 Christian Senkowski
			Usage: go-supervise -path /service-path/
		`, VERSION)
	os.Exit(code)
}
<commit_msg>logger can now be (re)started twice the amount of MAX_SERVICE_STARTUPS because it might still have buffered log lines left which need to be processed<commit_after>// Go Supervise
// svscan.go - Service controller code
//
// (c) 2015, Christian Senkowski

package main

import (
	"bufio"
	"fmt"
	"github.com/adar/go-supervise/config"
	"io"
	"log/syslog"
	"os"
	"os/exec"
	"sync"
	"time"
)

var LOGGER, LOGERR = syslog.New(syslog.LOG_WARNING, "svscan")
var CONFIG, CONFERR = config.ReadConfig()

const (
	VERSION              = "0.3"
	MAX_SERVICE_STARTUPS = 5
)

type ServiceHandler struct {
	mutex   *sync.Mutex
	service *Service
}

func main() {
	if CONFERR != nil {
		fmt.Printf("Error while reading config ", CONFERR)
	} else {
		start()
	}
}

/**
* Start
* Loops through list of services in etcd database
* and on defined path, resorts those and starts/restarts the services
* which are still active.
 */
func start() {

	if LOGERR != nil {
		panic(LOGERR)
	}

	servicePath := &CONFIG.ServiceConfig.Path
	removeSlashes(servicePath)

	db := new(DB)
	db.getClient()

	LOGGER.Warning(fmt.Sprintf("Scanning %s\n", *servicePath))

	if _, err := os.Stat("/" + *servicePath); err != nil {
		if crErr := os.Mkdir("/"+*servicePath, 0755); crErr != nil {
			LOGGER.Crit(fmt.Sprintf("Scanning %s failed - directory does not exist and is not creatable\n", *servicePath))
			fmt.Printf("Scanning %s failed - directory does not exist and is not creatable\n", *servicePath)
			usage(1)
		}
	}

	runningServices := make(map[string]*Service)

	// Loop knownServices and services in directory
	// If differ, decide which to remove or add
	for {
		servicesInDir := readServiceDir(servicePath)
		db.createNewServicesIfNeeded(&servicesInDir, servicePath)
		knownServices := db.getServices()

		for serviceName, service := range knownServices {
			serviceName := serviceName
			service := service

			srvDone := make(chan error, 1)

			_, ok := runningServices[serviceName]
			if ok != true {
				// service is not yet running
				// so start it and a logger
				go func() {
					err1 := updateServicePaths(&knownServices, servicePath)
					err2 := removeServiceBefore(&servicesInDir, serviceName)
					if err1 == nil && err2 == nil {
						LOGGER.Debug(fmt.Sprintf("%s not yet running\n", serviceName))
						time.Sleep(1 * time.Second)
						sv := new(ServiceHandler)
						sv.mutex = &sync.Mutex{}
						sv.service = service
						sv.startService(srvDone, runningServices, serviceName)
					}
				}()
			} else {
				// the service is running
				// but might have been removed manually (rm)
				err := removeServiceAfter(&servicesInDir, serviceName, runningServices[serviceName], srvDone)
				if err == nil {
					LOGGER.Debug(fmt.Sprintf("%s already running\n", serviceName))
				} else {
					delete(runningServices, serviceName)
				}
			}
		}

		time.Sleep(5 * time.Second)
	}

	LOGGER.Warning("exiting")
}

func (s *ServiceHandler) writeLine(stdin io.WriteCloser, line string) error {
	LOGGER.Debug(fmt.Sprintf("writing \"%s\" to stdin, %s\n", line, stdin))
	_, err := io.WriteString(stdin, line+"\n")
	return err
}

func (s *ServiceHandler) startLogger(loggerDone chan error, stdout io.ReadCloser) {
	if s.service.Startups >= MAX_SERVICE_STARTUPS*2 {
		LOGGER.Crit(fmt.Sprintf("logger %s has had too many startups in this session", s.service.Value))
		if len(s.service.LogBuffer) > 0 {
			LOGGER.Crit(fmt.Sprintf("%s - %s", s.service.Value, s.service.LogBuffer))
			s.service.LogBuffer = nil
		}
		return
	}

	s.mutex.Lock()
	s.service.LogCmd = exec.Command("./../multilog/multilog", "-path", "/"+s.service.Value)

	//@TODO rewrite multilog so that it can take stderr and stdout separately
	stdOutBuff := bufio.NewScanner(stdout)
	stdin, err := s.service.LogCmd.StdinPipe()
	if err != nil {
		LOGGER.Crit(fmt.Sprintf("Error while catching stdinpipe of %s, %s", s.service.Value, err))
		s.mutex.Unlock()
		return
	}
	defer stdin.Close()
	err = s.service.LogCmd.Start()
	if err != nil {
		LOGGER.Crit(fmt.Sprintf("Error while starting logger %s", err))
		s.mutex.Unlock()
		return
	}
	s.mutex.Unlock()

	if len(s.service.LogBuffer) > 0 {
		LOGGER.Crit(fmt.Sprintf("found unhandled log lines for %s, writing those first", s.service.Value))
		for _, line := range s.service.LogBuffer {
			err := s.writeLine(stdin, line)
			if err != nil {
				LOGGER.Crit(fmt.Sprintf("Could not write buffered log for %s. error: %s", s.service.Value, err))
				LOGGER.Crit(fmt.Sprintf("%s - %s", s.service.Value, line))
				break
			}
		}
		s.service.LogBuffer = nil
	}

	for stdOutBuff.Scan() {
		err := s.writeLine(stdin, stdOutBuff.Text())
		if err != nil {
			LOGGER.Crit(fmt.Sprintf("IO gone away for %s, %s", s.service.Value, s.service.LogCmd.Process))
			s.service.LogBuffer = append(s.service.LogBuffer, stdOutBuff.Text()+"\n")
			break
		}
	}

	loggerDone <- s.service.LogCmd.Wait()

	select {
	case <-loggerDone:
		LOGGER.Warning(fmt.Sprintf("logger %s done without errors", s.service.Value))
		if len(s.service.LogBuffer) > 0 {
			s.startLogger(loggerDone, stdout)
		}
		break
	case err := <-loggerDone:
		LOGGER.Warning(fmt.Sprintf("logger %s done with error = %v\n", s.service.Value, err))
		s.startLogger(loggerDone, stdout)
		break
	}
}

func (s *ServiceHandler) startService(srvDone chan error, runningServices map[string]*Service, serviceName string) {
	if s.service.Startups >= CONFIG.ServiceConfig.MaxFailedStartups {
		LOGGER.Crit(fmt.Sprintf("service %s has had too many startups in this session", serviceName))
		return

	}
	loggerDone := make(chan error, 1)
	s.mutex.Lock()
	knownServices := new(DB).getServices()
	s.mutex.Unlock()
	if _, ok := knownServices[serviceName]; ok != true {
		return
	}
	LOGGER.Warning(fmt.Sprintf("Starting %s\n", s.service.Value))

	s.service.Cmd = exec.Command("/" + s.service.Value + "/run")

	stdout, _ := s.service.Cmd.StdoutPipe()

	s.service.Startups += 1
	if err := s.service.Cmd.Start(); err != nil {
		LOGGER.Crit(fmt.Sprintf("service %s not startable: %s", serviceName, err))
		return
	}
	LOGGER.Debug(fmt.Sprintf("Starting %s, %s\n", s.service.Cmd.Process, s.service.Value))

	go s.startLogger(loggerDone, stdout)

	runningServices[serviceName] = s.service
	srvDone <- s.service.Cmd.Wait()
	select {
	case err := <-srvDone:
		LOGGER.Warning(fmt.Sprintf("restarting service %s, %s", serviceName, err))
		if s.service.LogCmd != nil && s.service.LogCmd.Process != nil {
			loggerDone <- s.service.LogCmd.Process.Kill()
		}
		time.Sleep(time.Duration(CONFIG.ServiceConfig.TimeWaitBetweenStartups) * time.Second)
		s.startService(srvDone, runningServices, serviceName)
	}
}

func usage(code int) {
	fmt.Printf(
		`go- %s - (c) 2015 Christian Senkowski
			Usage: go-supervise -path /service-path/
		`, VERSION)
	os.Exit(code)
}
<|endoftext|>


<commit_before>// +build android

package vulkan

/*
#cgo android LDFLAGS: -Wl,--no-warn-mismatch -lm_hard
#cgo android CFLAGS: -DVK_USE_PLATFORM_ANDROID_KHR -D_NDK_MATH_NO_SOFTFP=1 -mfpu=vfp

#include <android/native_window.h>

#include "vulkan/vulkan.h"
#include "vk_wrapper.h"
#include "vk_bridge.h"
#include "cgo_helpers.h"
*/
import "C"
import "unsafe"

const (
	// UsePlatformAndroid as defined in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html
	UsePlatformAndroid = 1
	// KhrAndroidSurface as defined in vulkan/vulkan.h:3669
	KhrAndroidSurface = 1
	// KhrAndroidSurfaceSpecVersion as defined in vulkan/vulkan.h:3672
	KhrAndroidSurfaceSpecVersion = 6
	// KhrAndroidSurfaceExtensionName as defined in vulkan/vulkan.h:3673
	KhrAndroidSurfaceExtensionName = "VK_KHR_android_surface"
)

// CreateWindowSurface creates a Vulkan surface (VK_KHR_android_surface) for ANativeWindow from Android NDK.
func CreateWindowSurface(instance Instance, nativeWindow uintptr, pAllocator *AllocationCallbacks, pSurface *Surface) Result {
	cinstance, _ := *(*C.VkInstance)(unsafe.Pointer(&instance)), cgoAllocsUnknown
	cpAllocator, _ := (*C.VkAllocationCallbacks)(unsafe.Pointer(pAllocator)), cgoAllocsUnknown
	cpSurface, _ := (*C.VkSurfaceKHR)(unsafe.Pointer(pSurface)), cgoAllocsUnknown
	pCreateInfo := &AndroidSurfaceCreateInfo{
		SType:  StructureTypeAndroidSurfaceCreateInfo,
		Window: (*ANativeWindow)(unsafe.Pointer(nativeWindow)),
	}
	cpCreateInfo, _ := pCreateInfo.PassRef()
	__ret := C.callVkCreateAndroidSurfaceKHR(cinstance, cpCreateInfo, cpAllocator, cpSurface)
	__v := (Result)(__ret)
	return __v
}

// GetRequiredInstanceExtensions should be used to query instance extensions required for surface initialization.
func GetRequiredInstanceExtensions() []string {
	return []string{
		"VK_KHR_surface\x00",
		"VK_KHR_android_surface\x00",
	}
}

// CreateAndroidSurface function as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkCreateAndroidSurfaceKHR
func CreateAndroidSurface(instance Instance, pCreateInfo *AndroidSurfaceCreateInfo, pAllocator *AllocationCallbacks, pSurface *Surface) Result {
	cinstance, _ := *(*C.VkInstance)(unsafe.Pointer(&instance)), cgoAllocsUnknown
	cpCreateInfo, _ := pCreateInfo.PassRef()
	cpAllocator, _ := (*C.VkAllocationCallbacks)(unsafe.Pointer(pAllocator)), cgoAllocsUnknown
	cpSurface, _ := (*C.VkSurfaceKHR)(unsafe.Pointer(pSurface)), cgoAllocsUnknown
	__ret := C.callVkCreateAndroidSurfaceKHR(cinstance, cpCreateInfo, cpAllocator, cpSurface)
	__v := (Result)(__ret)
	return __v
}

// allocAndroidSurfaceCreateInfoMemory allocates memory for type C.VkAndroidSurfaceCreateInfoKHR in C.
// The caller is responsible for freeing the this memory via C.free.
func allocAndroidSurfaceCreateInfoMemory(n int) unsafe.Pointer {
	mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfAndroidSurfaceCreateInfoValue))
	if err != nil {
		panic("memory alloc error: " + err.Error())
	}
	return mem
}

const sizeOfAndroidSurfaceCreateInfoValue = unsafe.Sizeof([1]C.VkAndroidSurfaceCreateInfoKHR{})

// Ref returns the underlying reference to C object or nil if struct is nil.
func (x *AndroidSurfaceCreateInfo) Ref() *C.VkAndroidSurfaceCreateInfoKHR {
	if x == nil {
		return nil
	}
	return x.refeca5c35c
}

// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free.
// Does nothing if struct is nil or has no allocation map.
func (x *AndroidSurfaceCreateInfo) Free() {
	if x != nil && x.allocseca5c35c != nil {
		x.allocseca5c35c.(*cgoAllocMap).Free()
		x.refeca5c35c = nil
	}
}

// NewAndroidSurfaceCreateInfoRef creates a new wrapper struct with underlying reference set to the original C object.
// Returns nil if the provided pointer to C object is nil too.
func NewAndroidSurfaceCreateInfoRef(ref unsafe.Pointer) *AndroidSurfaceCreateInfo {
	if ref == nil {
		return nil
	}
	obj := new(AndroidSurfaceCreateInfo)
	obj.refeca5c35c = (*C.VkAndroidSurfaceCreateInfoKHR)(unsafe.Pointer(ref))
	return obj
}

// PassRef returns the underlying C object, otherwise it will allocate one and set its values
// from this wrapping struct, counting allocations into an allocation map.
func (x *AndroidSurfaceCreateInfo) PassRef() (*C.VkAndroidSurfaceCreateInfoKHR, *cgoAllocMap) {
	if x == nil {
		return nil, nil
	} else if x.refeca5c35c != nil {
		return x.refeca5c35c, nil
	}
	memeca5c35c := allocAndroidSurfaceCreateInfoMemory(1)
	refeca5c35c := (*C.VkAndroidSurfaceCreateInfoKHR)(memeca5c35c)
	allocseca5c35c := new(cgoAllocMap)
	var csType_allocs *cgoAllocMap
	refeca5c35c.sType, csType_allocs = (C.VkStructureType)(x.SType), cgoAllocsUnknown
	allocseca5c35c.Borrow(csType_allocs)

	var cpNext_allocs *cgoAllocMap
	refeca5c35c.pNext, cpNext_allocs = *(*unsafe.Pointer)(unsafe.Pointer(&x.PNext)), cgoAllocsUnknown
	allocseca5c35c.Borrow(cpNext_allocs)

	var cflags_allocs *cgoAllocMap
	refeca5c35c.flags, cflags_allocs = (C.VkAndroidSurfaceCreateFlagsKHR)(x.Flags), cgoAllocsUnknown
	allocseca5c35c.Borrow(cflags_allocs)

	var cwindow_allocs *cgoAllocMap
	refeca5c35c.window, cwindow_allocs = *(**C.ANativeWindow)(unsafe.Pointer(&x.Window)), cgoAllocsUnknown
	allocseca5c35c.Borrow(cwindow_allocs)

	x.refeca5c35c = refeca5c35c
	x.allocseca5c35c = allocseca5c35c
	return refeca5c35c, allocseca5c35c

}

// PassValue does the same as PassRef except that it will try to dereference the returned pointer.
func (x AndroidSurfaceCreateInfo) PassValue() (C.VkAndroidSurfaceCreateInfoKHR, *cgoAllocMap) {
	if x.refeca5c35c != nil {
		return *x.refeca5c35c, nil
	}
	ref, allocs := x.PassRef()
	return *ref, allocs
}

// Deref uses the underlying reference to C object and fills the wrapping struct with values.
// Do not forget to call this method whether you get a struct for C object and want to read its values.
func (x *AndroidSurfaceCreateInfo) Deref() {
	if x.refeca5c35c == nil {
		return
	}
	x.SType = (StructureType)(x.refeca5c35c.sType)
	x.PNext = (unsafe.Pointer)(unsafe.Pointer(x.refeca5c35c.pNext))
	x.Flags = (AndroidSurfaceCreateFlags)(x.refeca5c35c.flags)
	x.Window = (*ANativeWindow)(unsafe.Pointer(x.refeca5c35c.window))
}

// ANativeWindow as declared in android/native_window.h:36
type ANativeWindow C.ANativeWindow

// AndroidSurfaceCreateFlags type as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkAndroidSurfaceCreateFlagsKHR
type AndroidSurfaceCreateFlags uint32

// AndroidSurfaceCreateInfo as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkAndroidSurfaceCreateInfoKHR
type AndroidSurfaceCreateInfo struct {
	SType          StructureType
	PNext          unsafe.Pointer
	Flags          AndroidSurfaceCreateFlags
	Window         *ANativeWindow
	refeca5c35c    *C.VkAndroidSurfaceCreateInfoKHR
	allocseca5c35c interface{}
}

// Ref returns a reference to C object as it is.
func (x *ANativeWindow) Ref() *C.ANativeWindow {
	if x == nil {
		return nil
	}
	return (*C.ANativeWindow)(unsafe.Pointer(x))
}

// Free cleanups the referenced memory using C free.
func (x *ANativeWindow) Free() {
	if x != nil {
		C.free(unsafe.Pointer(x))
	}
}

// NewANativeWindowRef converts the C object reference into a raw struct reference without wrapping.
func NewANativeWindowRef(ref unsafe.Pointer) *ANativeWindow {
	return (*ANativeWindow)(ref)
}

// NewANativeWindow allocates a new C object of this type and converts the reference into
// a raw struct reference without wrapping.
func NewANativeWindow() *ANativeWindow {
	return (*ANativeWindow)(allocANativeWindowMemory(1))
}

// allocANativeWindowMemory allocates memory for type C.ANativeWindow in C.
// The caller is responsible for freeing the this memory via C.free.
func allocANativeWindowMemory(n int) unsafe.Pointer {
	mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfANativeWindowValue))
	if err != nil {
		panic("memory alloc error: " + err.Error())
	}
	return mem
}

const sizeOfANativeWindowValue = unsafe.Sizeof([1]C.ANativeWindow{})

// PassRef returns a reference to C object as it is or allocates a new C object of this type.
func (x *ANativeWindow) PassRef() *C.ANativeWindow {
	if x == nil {
		x = (*ANativeWindow)(allocANativeWindowMemory(1))
	}
	return (*C.ANativeWindow)(unsafe.Pointer(x))
}
<commit_msg>remove m_hard lib<commit_after>// +build android

package vulkan

/*
#cgo android LDFLAGS: -Wl,--no-warn-mismatch
#cgo android CFLAGS: -DVK_USE_PLATFORM_ANDROID_KHR -D_NDK_MATH_NO_SOFTFP=1 -mfpu=vfp

#include <android/native_window.h>

#include "vulkan/vulkan.h"
#include "vk_wrapper.h"
#include "vk_bridge.h"
#include "cgo_helpers.h"
*/
import "C"
import "unsafe"

const (
	// UsePlatformAndroid as defined in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html
	UsePlatformAndroid = 1
	// KhrAndroidSurface as defined in vulkan/vulkan.h:3669
	KhrAndroidSurface = 1
	// KhrAndroidSurfaceSpecVersion as defined in vulkan/vulkan.h:3672
	KhrAndroidSurfaceSpecVersion = 6
	// KhrAndroidSurfaceExtensionName as defined in vulkan/vulkan.h:3673
	KhrAndroidSurfaceExtensionName = "VK_KHR_android_surface"
)

// CreateWindowSurface creates a Vulkan surface (VK_KHR_android_surface) for ANativeWindow from Android NDK.
func CreateWindowSurface(instance Instance, nativeWindow uintptr, pAllocator *AllocationCallbacks, pSurface *Surface) Result {
	cinstance, _ := *(*C.VkInstance)(unsafe.Pointer(&instance)), cgoAllocsUnknown
	cpAllocator, _ := (*C.VkAllocationCallbacks)(unsafe.Pointer(pAllocator)), cgoAllocsUnknown
	cpSurface, _ := (*C.VkSurfaceKHR)(unsafe.Pointer(pSurface)), cgoAllocsUnknown
	pCreateInfo := &AndroidSurfaceCreateInfo{
		SType:  StructureTypeAndroidSurfaceCreateInfo,
		Window: (*ANativeWindow)(unsafe.Pointer(nativeWindow)),
	}
	cpCreateInfo, _ := pCreateInfo.PassRef()
	__ret := C.callVkCreateAndroidSurfaceKHR(cinstance, cpCreateInfo, cpAllocator, cpSurface)
	__v := (Result)(__ret)
	return __v
}

// GetRequiredInstanceExtensions should be used to query instance extensions required for surface initialization.
func GetRequiredInstanceExtensions() []string {
	return []string{
		"VK_KHR_surface\x00",
		"VK_KHR_android_surface\x00",
	}
}

// CreateAndroidSurface function as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkCreateAndroidSurfaceKHR
func CreateAndroidSurface(instance Instance, pCreateInfo *AndroidSurfaceCreateInfo, pAllocator *AllocationCallbacks, pSurface *Surface) Result {
	cinstance, _ := *(*C.VkInstance)(unsafe.Pointer(&instance)), cgoAllocsUnknown
	cpCreateInfo, _ := pCreateInfo.PassRef()
	cpAllocator, _ := (*C.VkAllocationCallbacks)(unsafe.Pointer(pAllocator)), cgoAllocsUnknown
	cpSurface, _ := (*C.VkSurfaceKHR)(unsafe.Pointer(pSurface)), cgoAllocsUnknown
	__ret := C.callVkCreateAndroidSurfaceKHR(cinstance, cpCreateInfo, cpAllocator, cpSurface)
	__v := (Result)(__ret)
	return __v
}

// allocAndroidSurfaceCreateInfoMemory allocates memory for type C.VkAndroidSurfaceCreateInfoKHR in C.
// The caller is responsible for freeing the this memory via C.free.
func allocAndroidSurfaceCreateInfoMemory(n int) unsafe.Pointer {
	mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfAndroidSurfaceCreateInfoValue))
	if err != nil {
		panic("memory alloc error: " + err.Error())
	}
	return mem
}

const sizeOfAndroidSurfaceCreateInfoValue = unsafe.Sizeof([1]C.VkAndroidSurfaceCreateInfoKHR{})

// Ref returns the underlying reference to C object or nil if struct is nil.
func (x *AndroidSurfaceCreateInfo) Ref() *C.VkAndroidSurfaceCreateInfoKHR {
	if x == nil {
		return nil
	}
	return x.refeca5c35c
}

// Free invokes alloc map's free mechanism that cleanups any allocated memory using C free.
// Does nothing if struct is nil or has no allocation map.
func (x *AndroidSurfaceCreateInfo) Free() {
	if x != nil && x.allocseca5c35c != nil {
		x.allocseca5c35c.(*cgoAllocMap).Free()
		x.refeca5c35c = nil
	}
}

// NewAndroidSurfaceCreateInfoRef creates a new wrapper struct with underlying reference set to the original C object.
// Returns nil if the provided pointer to C object is nil too.
func NewAndroidSurfaceCreateInfoRef(ref unsafe.Pointer) *AndroidSurfaceCreateInfo {
	if ref == nil {
		return nil
	}
	obj := new(AndroidSurfaceCreateInfo)
	obj.refeca5c35c = (*C.VkAndroidSurfaceCreateInfoKHR)(unsafe.Pointer(ref))
	return obj
}

// PassRef returns the underlying C object, otherwise it will allocate one and set its values
// from this wrapping struct, counting allocations into an allocation map.
func (x *AndroidSurfaceCreateInfo) PassRef() (*C.VkAndroidSurfaceCreateInfoKHR, *cgoAllocMap) {
	if x == nil {
		return nil, nil
	} else if x.refeca5c35c != nil {
		return x.refeca5c35c, nil
	}
	memeca5c35c := allocAndroidSurfaceCreateInfoMemory(1)
	refeca5c35c := (*C.VkAndroidSurfaceCreateInfoKHR)(memeca5c35c)
	allocseca5c35c := new(cgoAllocMap)
	var csType_allocs *cgoAllocMap
	refeca5c35c.sType, csType_allocs = (C.VkStructureType)(x.SType), cgoAllocsUnknown
	allocseca5c35c.Borrow(csType_allocs)

	var cpNext_allocs *cgoAllocMap
	refeca5c35c.pNext, cpNext_allocs = *(*unsafe.Pointer)(unsafe.Pointer(&x.PNext)), cgoAllocsUnknown
	allocseca5c35c.Borrow(cpNext_allocs)

	var cflags_allocs *cgoAllocMap
	refeca5c35c.flags, cflags_allocs = (C.VkAndroidSurfaceCreateFlagsKHR)(x.Flags), cgoAllocsUnknown
	allocseca5c35c.Borrow(cflags_allocs)

	var cwindow_allocs *cgoAllocMap
	refeca5c35c.window, cwindow_allocs = *(**C.ANativeWindow)(unsafe.Pointer(&x.Window)), cgoAllocsUnknown
	allocseca5c35c.Borrow(cwindow_allocs)

	x.refeca5c35c = refeca5c35c
	x.allocseca5c35c = allocseca5c35c
	return refeca5c35c, allocseca5c35c

}

// PassValue does the same as PassRef except that it will try to dereference the returned pointer.
func (x AndroidSurfaceCreateInfo) PassValue() (C.VkAndroidSurfaceCreateInfoKHR, *cgoAllocMap) {
	if x.refeca5c35c != nil {
		return *x.refeca5c35c, nil
	}
	ref, allocs := x.PassRef()
	return *ref, allocs
}

// Deref uses the underlying reference to C object and fills the wrapping struct with values.
// Do not forget to call this method whether you get a struct for C object and want to read its values.
func (x *AndroidSurfaceCreateInfo) Deref() {
	if x.refeca5c35c == nil {
		return
	}
	x.SType = (StructureType)(x.refeca5c35c.sType)
	x.PNext = (unsafe.Pointer)(unsafe.Pointer(x.refeca5c35c.pNext))
	x.Flags = (AndroidSurfaceCreateFlags)(x.refeca5c35c.flags)
	x.Window = (*ANativeWindow)(unsafe.Pointer(x.refeca5c35c.window))
}

// ANativeWindow as declared in android/native_window.h:36
type ANativeWindow C.ANativeWindow

// AndroidSurfaceCreateFlags type as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkAndroidSurfaceCreateFlagsKHR
type AndroidSurfaceCreateFlags uint32

// AndroidSurfaceCreateInfo as declared in https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/xhtml/vkspec.html#vkAndroidSurfaceCreateInfoKHR
type AndroidSurfaceCreateInfo struct {
	SType          StructureType
	PNext          unsafe.Pointer
	Flags          AndroidSurfaceCreateFlags
	Window         *ANativeWindow
	refeca5c35c    *C.VkAndroidSurfaceCreateInfoKHR
	allocseca5c35c interface{}
}

// Ref returns a reference to C object as it is.
func (x *ANativeWindow) Ref() *C.ANativeWindow {
	if x == nil {
		return nil
	}
	return (*C.ANativeWindow)(unsafe.Pointer(x))
}

// Free cleanups the referenced memory using C free.
func (x *ANativeWindow) Free() {
	if x != nil {
		C.free(unsafe.Pointer(x))
	}
}

// NewANativeWindowRef converts the C object reference into a raw struct reference without wrapping.
func NewANativeWindowRef(ref unsafe.Pointer) *ANativeWindow {
	return (*ANativeWindow)(ref)
}

// NewANativeWindow allocates a new C object of this type and converts the reference into
// a raw struct reference without wrapping.
func NewANativeWindow() *ANativeWindow {
	return (*ANativeWindow)(allocANativeWindowMemory(1))
}

// allocANativeWindowMemory allocates memory for type C.ANativeWindow in C.
// The caller is responsible for freeing the this memory via C.free.
func allocANativeWindowMemory(n int) unsafe.Pointer {
	mem, err := C.calloc(C.size_t(n), (C.size_t)(sizeOfANativeWindowValue))
	if err != nil {
		panic("memory alloc error: " + err.Error())
	}
	return mem
}

const sizeOfANativeWindowValue = unsafe.Sizeof([1]C.ANativeWindow{})

// PassRef returns a reference to C object as it is or allocates a new C object of this type.
func (x *ANativeWindow) PassRef() *C.ANativeWindow {
	if x == nil {
		x = (*ANativeWindow)(allocANativeWindowMemory(1))
	}
	return (*C.ANativeWindow)(unsafe.Pointer(x))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/raff/goble"
)

var (
	debug   = flag.Bool("debug", false, "log debug messages")
	verbose = flag.Bool("verbose", false, "dump all events")
	dups    = flag.Bool("allow-duplicates", false, "allow duplicates when scanning")
)

func DebugPrint(params ...interface{}) {
	if *debug {
		log.Println(params...)
	}
}

type Result struct {
	count int
	data  string
}

func explore(ble *goble.BLE, peripheral *goble.Peripheral) {
	results := map[string]Result{}

	// connect
	ble.On("connect", func(ev goble.Event) (done bool) {
		DebugPrint("connected", ev)
		ble.DiscoverServices(ev.DeviceUUID, nil)

		go func() {
			time.Sleep(2 * time.Minute)
			ble.Disconnect(ev.DeviceUUID)
		}()

		return
	})

	// discover services
	ble.On("servicesDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("serviceDiscovered", ev)
		for sid, service := range ev.Peripheral.Services {
			// this is a map that contains services UUIDs (string) and service startHandle (int)
			// for now we only process the "strings"
			if _, ok := sid.(string); ok {
				serviceInfo := service.Uuid

				if len(service.Name) > 0 {
					serviceInfo += " (" + service.Name + ")"
				}

				results[service.Uuid] = Result{data: serviceInfo}
				ble.DiscoverCharacterstics(ev.DeviceUUID, service.Uuid, nil)
			}
		}

		return
	})

	// discover characteristics
	ble.On("characteristicsDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("characteristicsDiscovered", ev)
		serviceUuid := ev.ServiceUuid
		serviceResult := results[serviceUuid]

		for cid, characteristic := range ev.Peripheral.Services[serviceUuid].Characteristics {
			// this is a map that contains services UUIDs (string) and service startHandle (int)
			// for now we only process the "strings"
			if _, ok := cid.(string); ok {
				characteristicInfo := "  " + characteristic.Uuid

				if len(characteristic.Name) > 0 {
					characteristicInfo += " (" + characteristic.Name + ")"
				}

				characteristicInfo += "\n    properties  " + characteristic.Properties.String()
				serviceResult.data += characteristicInfo

				if characteristic.Properties.Readable() {
					serviceResult.count += 1
					ble.Read(ev.DeviceUUID, serviceUuid, characteristic.Uuid)
				}

				//ble.DiscoverDescriptors(ev.DeviceUUID, serviceUuid, characteristic.Uuid)
				results[serviceUuid] = serviceResult

				if *verbose {
					log.Println(results[serviceUuid])
				}
			}
		}

		return
	})

	// discover descriptors
	ble.On("descriptorsDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("descriptorsDiscovered", ev)
		fmt.Println("    descriptors  ", ev.Peripheral.Services[ev.ServiceUuid].Characteristics[ev.CharacteristicUuid].Descriptors)
		return
	})

	// read
	ble.On("read", func(ev goble.Event) (done bool) {
		DebugPrint("read", ev)
		serviceUuid := ev.ServiceUuid
		serviceResult := results[serviceUuid]
		serviceResult.data += fmt.Sprintf("    value        %x | %q\n", ev.Data, ev.Data)
		serviceResult.count -= 1

		if serviceResult.count <= 0 {
			fmt.Println(serviceResult.data)
			return true
		} else {
			results[serviceUuid] = serviceResult
		}

		return
	})

	// disconnect
	ble.On("disconnect", func(ev goble.Event) (done bool) {
		DebugPrint("disconnected", ev)
		os.Exit(0)
		return true
	})

	fmt.Println("services and characteristics:")
	ble.Connect(peripheral.Uuid)

	/*
	           async.series([
	             function(callback) {
	               characteristic.discoverDescriptors(function(error, descriptors) {
	                 async.detect(
	                   descriptors,
	                   function(descriptor, callback) {
	                     return callback(descriptor.uuid === '2901")
	                   },
	                   function(userDescriptionDescriptor){
	                     if (userDescriptionDescriptor) {
	                       userDescriptionDescriptor.readValue(function(error, data) {
	                         characteristicInfo += ' (' + data.toString() + ')';
	                         callback();
	                       });
	                     } else {
	                       callback();
	                     }
	                   }
	                 );
	               });
	             },
	             function(callback) {
	                   characteristicInfo += '\n    properties  ' + characteristic.properties.join(', ")

	               if (characteristic.properties.indexOf('read') !== -1) {
	                 characteristic.read(function(error, data) {
	                   if (data) {
	                     var string = data.toString('ascii")

	                     characteristicInfo += '\n    value       ' + data.toString('hex') + ' | \'' + string + '\'';
	                   }
	                   callback();
	                 });
	               } else {
	                 callback();
	               }
	             },
	             function() {
	               console.log(characteristicInfo);
	               characteristicIndex++;
	               callback();
	             }
	           ]);
	         },
	         function(error) {
	           serviceIndex++;
	           callback();
	         }
	       );
	     });
	   },
	*/
}

func main() {
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Println("usage:", os.Args[0], "[options] peripheral-uuid")
		os.Exit(1)
	}

	peripheralUuid := flag.Args()[0]

	var done chan bool

	ble := goble.New()
	ble.SetVerbose(*verbose)

	if *verbose {
		ble.On(goble.ALL, func(ev goble.Event) (done bool) {
			log.Println("Event", ev)
			return
		})
	}

	ble.On("stateChange", func(ev goble.Event) (done bool) {
		DebugPrint("stateChanged", ev)
		if ev.State == "poweredOn" {
			ble.StartScanning(nil, *dups)
		} else {
			ble.StopScanning()
			done = true
		}

		return
	})

	ble.On("discover", func(ev goble.Event) (done bool) {
		DebugPrint("discovered", ev)
		if peripheralUuid == ev.DeviceUUID.String() {
			ble.StopScanning()

			fmt.Println()
			fmt.Println("peripheral with UUID", ev.DeviceUUID, "found")

			advertisement := ev.Peripheral.Advertisement

			DebugPrint("advertised", advertisement)

			localName := advertisement.LocalName
			txPowerLevel := advertisement.TxPowerLevel
			manufacturerData := advertisement.ManufacturerData
			serviceData := advertisement.ServiceData
			//serviceUuids := advertisement.ServiceUuids

			if ev.Peripheral.Connectable {
				fmt.Println("  Connectable")
			}
			if len(localName) > 0 {
				fmt.Println("  Local Name        =", localName)
			}

			if txPowerLevel != 0 {
				fmt.Println("  TX Power Level    =", txPowerLevel)
			}

			if len(manufacturerData) > 0 {
				fmt.Println("  Manufacturer Data =", manufacturerData)
			}

			if len(serviceData) > 0 {
				fmt.Println("  Service Data      =", serviceData)
			}

			fmt.Println()

			DebugPrint("explore", ev.Peripheral)
			explore(ble, &ev.Peripheral)
		}

		return
	})

	if *verbose {
		log.Println("Init...")
	}

	ble.Init()

	fmt.Println("waiting...")
	<-done

	fmt.Println("goodbye!")
	os.Exit(0)
}
<commit_msg>fix mispelled function name (https://github.com/raff/goble/issues/4)<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/raff/goble"
)

var (
	debug   = flag.Bool("debug", false, "log debug messages")
	verbose = flag.Bool("verbose", false, "dump all events")
	dups    = flag.Bool("allow-duplicates", false, "allow duplicates when scanning")
)

func DebugPrint(params ...interface{}) {
	if *debug {
		log.Println(params...)
	}
}

type Result struct {
	count int
	data  string
}

func explore(ble *goble.BLE, peripheral *goble.Peripheral) {
	results := map[string]Result{}

	// connect
	ble.On("connect", func(ev goble.Event) (done bool) {
		DebugPrint("connected", ev)
		ble.DiscoverServices(ev.DeviceUUID, nil)

		go func() {
			time.Sleep(2 * time.Minute)
			ble.Disconnect(ev.DeviceUUID)
		}()

		return
	})

	// discover services
	ble.On("servicesDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("serviceDiscovered", ev)
		for sid, service := range ev.Peripheral.Services {
			// this is a map that contains services UUIDs (string) and service startHandle (int)
			// for now we only process the "strings"
			if _, ok := sid.(string); ok {
				serviceInfo := service.Uuid

				if len(service.Name) > 0 {
					serviceInfo += " (" + service.Name + ")"
				}

				results[service.Uuid] = Result{data: serviceInfo}
				ble.DiscoverCharacteristics(ev.DeviceUUID, service.Uuid, nil)
			}
		}

		return
	})

	// discover characteristics
	ble.On("characteristicsDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("characteristicsDiscovered", ev)
		serviceUuid := ev.ServiceUuid
		serviceResult := results[serviceUuid]

		for cid, characteristic := range ev.Peripheral.Services[serviceUuid].Characteristics {
			// this is a map that contains services UUIDs (string) and service startHandle (int)
			// for now we only process the "strings"
			if _, ok := cid.(string); ok {
				characteristicInfo := "  " + characteristic.Uuid

				if len(characteristic.Name) > 0 {
					characteristicInfo += " (" + characteristic.Name + ")"
				}

				characteristicInfo += "\n    properties  " + characteristic.Properties.String()
				serviceResult.data += characteristicInfo

				if characteristic.Properties.Readable() {
					serviceResult.count += 1
					ble.Read(ev.DeviceUUID, serviceUuid, characteristic.Uuid)
				}

				//ble.DiscoverDescriptors(ev.DeviceUUID, serviceUuid, characteristic.Uuid)
				results[serviceUuid] = serviceResult

				if *verbose {
					log.Println(results[serviceUuid])
				}
			}
		}

		return
	})

	// discover descriptors
	ble.On("descriptorsDiscover", func(ev goble.Event) (done bool) {
		DebugPrint("descriptorsDiscovered", ev)
		fmt.Println("    descriptors  ", ev.Peripheral.Services[ev.ServiceUuid].Characteristics[ev.CharacteristicUuid].Descriptors)
		return
	})

	// read
	ble.On("read", func(ev goble.Event) (done bool) {
		DebugPrint("read", ev)
		serviceUuid := ev.ServiceUuid
		serviceResult := results[serviceUuid]
		serviceResult.data += fmt.Sprintf("    value        %x | %q\n", ev.Data, ev.Data)
		serviceResult.count -= 1

		if serviceResult.count <= 0 {
			fmt.Println(serviceResult.data)
			return true
		} else {
			results[serviceUuid] = serviceResult
		}

		return
	})

	// disconnect
	ble.On("disconnect", func(ev goble.Event) (done bool) {
		DebugPrint("disconnected", ev)
		os.Exit(0)
		return true
	})

	fmt.Println("services and characteristics:")
	ble.Connect(peripheral.Uuid)

	/*
	           async.series([
	             function(callback) {
	               characteristic.discoverDescriptors(function(error, descriptors) {
	                 async.detect(
	                   descriptors,
	                   function(descriptor, callback) {
	                     return callback(descriptor.uuid === '2901")
	                   },
	                   function(userDescriptionDescriptor){
	                     if (userDescriptionDescriptor) {
	                       userDescriptionDescriptor.readValue(function(error, data) {
	                         characteristicInfo += ' (' + data.toString() + ')';
	                         callback();
	                       });
	                     } else {
	                       callback();
	                     }
	                   }
	                 );
	               });
	             },
	             function(callback) {
	                   characteristicInfo += '\n    properties  ' + characteristic.properties.join(', ")

	               if (characteristic.properties.indexOf('read') !== -1) {
	                 characteristic.read(function(error, data) {
	                   if (data) {
	                     var string = data.toString('ascii")

	                     characteristicInfo += '\n    value       ' + data.toString('hex') + ' | \'' + string + '\'';
	                   }
	                   callback();
	                 });
	               } else {
	                 callback();
	               }
	             },
	             function() {
	               console.log(characteristicInfo);
	               characteristicIndex++;
	               callback();
	             }
	           ]);
	         },
	         function(error) {
	           serviceIndex++;
	           callback();
	         }
	       );
	     });
	   },
	*/
}

func main() {
	flag.Parse()

	if len(flag.Args()) != 1 {
		fmt.Println("usage:", os.Args[0], "[options] peripheral-uuid")
		os.Exit(1)
	}

	peripheralUuid := flag.Args()[0]

	var done chan bool

	ble := goble.New()
	ble.SetVerbose(*verbose)

	if *verbose {
		ble.On(goble.ALL, func(ev goble.Event) (done bool) {
			log.Println("Event", ev)
			return
		})
	}

	ble.On("stateChange", func(ev goble.Event) (done bool) {
		DebugPrint("stateChanged", ev)
		if ev.State == "poweredOn" {
			ble.StartScanning(nil, *dups)
		} else {
			ble.StopScanning()
			done = true
		}

		return
	})

	ble.On("discover", func(ev goble.Event) (done bool) {
		DebugPrint("discovered", ev)
		if peripheralUuid == ev.DeviceUUID.String() {
			ble.StopScanning()

			fmt.Println()
			fmt.Println("peripheral with UUID", ev.DeviceUUID, "found")

			advertisement := ev.Peripheral.Advertisement

			DebugPrint("advertised", advertisement)

			localName := advertisement.LocalName
			txPowerLevel := advertisement.TxPowerLevel
			manufacturerData := advertisement.ManufacturerData
			serviceData := advertisement.ServiceData
			//serviceUuids := advertisement.ServiceUuids

			if ev.Peripheral.Connectable {
				fmt.Println("  Connectable")
			}
			if len(localName) > 0 {
				fmt.Println("  Local Name        =", localName)
			}

			if txPowerLevel != 0 {
				fmt.Println("  TX Power Level    =", txPowerLevel)
			}

			if len(manufacturerData) > 0 {
				fmt.Println("  Manufacturer Data =", manufacturerData)
			}

			if len(serviceData) > 0 {
				fmt.Println("  Service Data      =", serviceData)
			}

			fmt.Println()

			DebugPrint("explore", ev.Peripheral)
			explore(ble, &ev.Peripheral)
		}

		return
	})

	if *verbose {
		log.Println("Init...")
	}

	ble.Init()

	fmt.Println("waiting...")
	<-done

	fmt.Println("goodbye!")
	os.Exit(0)
}
<|endoftext|>


<commit_before>package flightid

import(
	"encoding/json"
	"fmt"
	"net/http"
	"sort"

	"google.golang.org/appengine"
	"google.golang.org/appengine/urlfetch"
	//"golang.org/x/net/context"

	"github.com/skypies/geo"
	"github.com/skypies/util/date"

	"github.com/skypies/pi/airspace"
	fdb "github.com/skypies/flightdb2"
)

func init() {
	http.HandleFunc("/cdb/airspace", airspaceHandler)
}

// {{{ airspaceHandler

func airspaceHandler(w http.ResponseWriter, r *http.Request) {
	client := urlfetch.Client(appengine.NewContext(r))

	str := ""

	f,err,debug := FindOverhead(client, geo.Latlong{37.060312,-121.990814}, 0, true)
	str += fmt.Sprintf("======/// FindOverhead ///======\nerr=%v\nf=%s\n\n%s", err, f, debug)

/*
	as, err := FetchAirspace(client)
	if err != nil {
		http.Error(w, fmt.Sprintf("FetchAirspace: %v", err), http.StatusInternalServerError)
		return
	}
	str += "======/// Airspace ///=====\n\n" + as.String()

	snaps := AirspaceToSnapshots(as)
	str += "\n\n=====/// Snaps ///=====\n\n"
	for _,fs := range snaps {
		str += fmt.Sprintf("* %s\n", fs)
	}
*/

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("OK\n\n"+str))
}

// }}}

// {{{ AirspaceToSnapshots

func AirspaceToSnapshots(as *airspace.Airspace) []fdb.FlightSnapshot {
	ret := []fdb.FlightSnapshot{}

	for _,ad := range as.Aircraft {
		fs := fdb.FlightSnapshot{
			Trackpoint: fdb.TrackpointFromADSB(ad.Msg),
			Flight: fdb.BlankFlight(),
		}
		fs.Airframe = ad.Airframe
		fs.Identity.Schedule = ad.Schedule
		fs.Identity.IcaoId = string(ad.Msg.Icao24)
		fs.Identity.Callsign = ad.Msg.Callsign
		ret = append(ret, fs)
	}

	return ret
}

// }}}
// {{{ FlightSnapshotToAircraft

func FlightSnapshotToAircraft(snap *fdb.FlightSnapshot) *Aircraft {
	if snap == nil { return nil }

	return &Aircraft{
		Dist: snap.DistToReferenceKM,
		Dist3: snap.Dist3ToReferenceKM,
		BearingFromObserver: snap.BearingToReference,
		// Fr24Url string
		Id: snap.Flight.IdSpecString(),
		Id2: snap.Flight.IcaoId,
		Lat: snap.Trackpoint.Lat,
		Long: snap.Trackpoint.Long,
		Track: snap.Trackpoint.Heading,
		Altitude: snap.Trackpoint.Altitude,
		Speed: snap.Trackpoint.GroundSpeed,
		// Squawk string
		// Radar string
		EquipType: snap.Flight.EquipmentType,
		Registration: snap.Flight.Registration,
		// Epoch float64
		Origin: snap.Flight.Origin,
		Destination: snap.Flight.Destination,
		FlightNumber: snap.Flight.BestFlightNumber(),
		// Unknown float64
		VerticalSpeed: snap.Trackpoint.VerticalRate,
		Callsign: snap.Flight.Callsign,
		// Unknown2 float64
	}
}

// }}}

// {{{ FetchAirspace

func FetchAirspace(client *http.Client, bbox geo.LatlongBox) (*airspace.Airspace, string, error) {
	as := airspace.Airspace{}
	url := "http://fdb.serfr1.org/?json=1&"+bbox.ToCGIArgs("box")

	str := fmt.Sprintf("* FetchAirspace(%s)\n* %s\n", bbox, url)

	if resp,err := client.Get(url); err != nil {
		return nil, str, err
	} else if resp.StatusCode != http.StatusOK {
		return nil, str, fmt.Errorf ("Bad status: %v", resp.Status)
	} else if err := json.NewDecoder(resp.Body).Decode(&as); err != nil {
		return nil, str, err
	}

	return &as, str, nil
}

// }}}
// {{{ FilterSnapshots

func FilterSnapshots(in []fdb.FlightSnapshot) []fdb.FlightSnapshot {
	out := []fdb.FlightSnapshot{}

	for _,snap := range in {
		if snap.Flight.BestFlightNumber() == "" { continue }
		if snap.Trackpoint.Altitude > 28000 { continue }
		if snap.Trackpoint.Altitude <  1000 { continue }
		if snap.Dist3ToReferenceKM > 80 { continue }

		out = append(out, snap)
/*
		if a.Radar == "T-F5M" { continue }    // 5m delayed data; not what's overhead
		if a.FlightNumber == "" {continue}
		// if a.BestIdent() == "" { continue }  // No ID info; not much interesting to say
		if a.Altitude > 28000 { continue }    // Too high to be the problem
		if a.Altitude <   500 { continue }    // Too low to be the problem

		// Strip out little planes
		skip := false
		for _,e := range kBlacklistEquipmentTypes {
			if a.EquipType == e { skip = true }
		}
		if skip { continue }
*/
	}

	return out
}

// }}}
// {{{ SelectOverhead

func SelectOverhead(snaps []fdb.FlightSnapshot) (*fdb.FlightSnapshot, string) {
	if len(snaps) == 0 { return nil, "** empty list\n" }

	// closest plane has to be within 12 km to be 'overhead', and it has
	// to be 4km away from the next-closest
	if (snaps[0].Dist3ToReferenceKM < 12.0) {
		if (len(snaps) == 1) || (snaps[1].Dist3ToReferenceKM - snaps[0].Dist3ToReferenceKM) > 4.0 {
			return &snaps[0], "** selected 1st\n"

		} else {
			return nil, "** 2nd was too close to 1st\n"
		}

	} else {
		return nil, "** 1st was too far away\n"
	}

}

// }}}

// {{{ FindAllOverhead

func FindAllOverhead(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (*Aircraft, []*Aircraft, []*Aircraft, error, string) {
	str := fmt.Sprintf("*** FindAllOverhead for %s@%.0fft, at %s\n", pos, elev, date.NowInPdt())

	outAll := []*Aircraft{}
	outFilt := []*Aircraft{}

	if pos.IsNil() {
		return nil, outAll, outFilt, fmt.Errorf("flightid.FindOverhead needs a non-nil position"), str
	}

	bbox := pos.Box(64,64) // A box with sides ~40 miles, centered on the observer

	as, deb, err := FetchAirspace(client, bbox)
	str += deb
	if err != nil { return nil, outAll, outFilt, err, str }

	snaps := AirspaceToSnapshots(as)
	for i,_ := range snaps {
		snaps[i].LocalizeTo(pos, elev)
	}
	sort.Sort(fdb.FlightSnapshotsByDist3(snaps))
	str += "** nearby list:-\n"+fdb.DebugFlightSnapshotList(snaps)

	filtered := FilterSnapshots(snaps)
	str += "** filtered:-\n"+fdb.DebugFlightSnapshotList(filtered)
	if len(filtered) == 0 { return nil, outAll, outFilt, nil, str }

	overheadSnap,debug := SelectOverhead(filtered)
	if overheadSnap == nil && grabAny {
		overheadSnap = &filtered[0]
		debug += "** grabbing first anyway\n"
	}
	str += debug

	for _,snap := range snaps { outAll = append(outAll, FlightSnapshotToAircraft(&snap)) }
	for _,snap := range filtered { outFilt = append(outFilt, FlightSnapshotToAircraft(&snap)) }

	return FlightSnapshotToAircraft(overheadSnap), outAll, outFilt, nil, str
}

// }}}
// {{{ FindOverhead

func FindOverhead(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (*Aircraft, error, string) {
	result := FindOverheadResult(client, pos, elev, grabAny)
	return result.Flight, result.Err, result.Debug
}

// }}}

// {{{ FindOverheadResult

func FindOverheadResult(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (out Result) {
	out.Debug = fmt.Sprintf("*** FindAllOverhead for %s@%.0fft, at %s\n", pos, elev, date.NowInPdt())

	if pos.IsNil() {
		out.Err = fmt.Errorf("flightid.FindOverhead needs a non-nil position")
		return
	}

	bbox := pos.Box(64,64) // A box with sides ~40 miles, centered on the observer

	as, deb, err := FetchAirspace(client, bbox)
	out.Debug += deb
	if err != nil {
		out.Err = err
		return
	}

	snaps := AirspaceToSnapshots(as)
	for i,_ := range snaps {
		snaps[i].LocalizeTo(pos, elev)
	}
	sort.Sort(fdb.FlightSnapshotsByDist3(snaps))
	out.Debug += "** nearby list:-\n"+fdb.DebugFlightSnapshotList(snaps)

	filtered := FilterSnapshots(snaps)
	out.Debug += "** filtered:-\n"+fdb.DebugFlightSnapshotList(filtered)
	if len(filtered) == 0 {
		return
	}

	overheadSnap,debug := SelectOverhead(filtered)
	if overheadSnap == nil && grabAny {
		overheadSnap = &filtered[0]
		out.Debug += "** grabbing first anyway\n"
	}
	out.Debug += debug

	out.All = []*Aircraft{}
	out.Filtered = []*Aircraft{}
	for _,snap := range snaps { out.All = append(out.All, FlightSnapshotToAircraft(&snap)) }
	for _,snap := range filtered { out.Filtered = append(out.Filtered, FlightSnapshotToAircraft(&snap)) }

	out.Flight = FlightSnapshotToAircraft(overheadSnap)
	return
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<commit_msg>Ensure snapshots can generate valid IdSpecs<commit_after>package flightid

import(
	"encoding/json"
	"fmt"
	"net/http"
	"sort"

	"google.golang.org/appengine"
	"google.golang.org/appengine/urlfetch"

	fdb "github.com/skypies/flightdb2"
	"github.com/skypies/geo"
	"github.com/skypies/pi/airspace"
	"github.com/skypies/util/date"
)

func init() {
	http.HandleFunc("/cdb/airspace", airspaceHandler)
}

// {{{ airspaceHandler

func airspaceHandler(w http.ResponseWriter, r *http.Request) {
	client := urlfetch.Client(appengine.NewContext(r))

	str := ""

	f,err,debug := FindOverhead(client, geo.Latlong{37.060312,-121.990814}, 0, true)
	str += fmt.Sprintf("======/// FindOverhead ///======\nerr=%v\nf=%s\n\n%s", err, f, debug)

/*
	as, err := FetchAirspace(client)
	if err != nil {
		http.Error(w, fmt.Sprintf("FetchAirspace: %v", err), http.StatusInternalServerError)
		return
	}
	str += "======/// Airspace ///=====\n\n" + as.String()

	snaps := AirspaceToSnapshots(as)
	str += "\n\n=====/// Snaps ///=====\n\n"
	for _,fs := range snaps {
		str += fmt.Sprintf("* %s\n", fs)
	}
*/

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("OK\n\n"+str))
}

// }}}

// {{{ AirspaceToSnapshots

func AirspaceToSnapshots(as *airspace.Airspace) []fdb.FlightSnapshot {
	ret := []fdb.FlightSnapshot{}

	for _,ad := range as.Aircraft {
		tp := fdb.TrackpointFromADSB(ad.Msg)
		fs := fdb.FlightSnapshot{
			Trackpoint: tp,
			Flight: fdb.BlankFlight(),
		}
		fs.Airframe = ad.Airframe
		fs.Identity.Schedule = ad.Schedule
		fs.Identity.IcaoId = string(ad.Msg.Icao24)
		fs.Identity.Callsign = ad.Msg.Callsign

		// Rig up a track from the single datapoint; that's needed to get timestamps for IdSpec
		track := fdb.Track{}
		track = append(track, tp)
		fs.Flight.Tracks[tp.DataSource] = &track

		ret = append(ret, fs)
	}

	return ret
}

// }}}
// {{{ FlightSnapshotToAircraft

func FlightSnapshotToAircraft(snap *fdb.FlightSnapshot) *Aircraft {
	if snap == nil { return nil }

	return &Aircraft{
		Dist: snap.DistToReferenceKM,
		Dist3: snap.Dist3ToReferenceKM,
		BearingFromObserver: snap.BearingToReference,
		// Fr24Url string
		Id: snap.Flight.IdSpecString(),
		Id2: snap.Flight.IcaoId,
		Lat: snap.Trackpoint.Lat,
		Long: snap.Trackpoint.Long,
		Track: snap.Trackpoint.Heading,
		Altitude: snap.Trackpoint.Altitude,
		Speed: snap.Trackpoint.GroundSpeed,
		// Squawk string
		// Radar string
		EquipType: snap.Flight.EquipmentType,
		Registration: snap.Flight.Registration,
		// Epoch float64
		Origin: snap.Flight.Origin,
		Destination: snap.Flight.Destination,
		FlightNumber: snap.Flight.BestFlightNumber(),
		// Unknown float64
		VerticalSpeed: snap.Trackpoint.VerticalRate,
		Callsign: snap.Flight.Callsign,
		// Unknown2 float64
	}
}

// }}}

// {{{ FetchAirspace

func FetchAirspace(client *http.Client, bbox geo.LatlongBox) (*airspace.Airspace, string, error) {
	as := airspace.Airspace{}
	url := "http://fdb.serfr1.org/?json=1&"+bbox.ToCGIArgs("box")

	str := fmt.Sprintf("* FetchAirspace(%s)\n* %s\n", bbox, url)

	if resp,err := client.Get(url); err != nil {
		return nil, str, err
	} else if resp.StatusCode != http.StatusOK {
		return nil, str, fmt.Errorf ("Bad status: %v", resp.Status)
	} else if err := json.NewDecoder(resp.Body).Decode(&as); err != nil {
		return nil, str, err
	}

	return &as, str, nil
}

// }}}
// {{{ FilterSnapshots

func FilterSnapshots(in []fdb.FlightSnapshot) []fdb.FlightSnapshot {
	out := []fdb.FlightSnapshot{}

	for _,snap := range in {
		if snap.Flight.BestFlightNumber() == "" { continue }
		if snap.Trackpoint.Altitude > 28000 { continue }
		if snap.Trackpoint.Altitude <  1000 { continue }
		if snap.Dist3ToReferenceKM > 80 { continue }

		out = append(out, snap)
/*
		if a.Radar == "T-F5M" { continue }    // 5m delayed data; not what's overhead
		if a.FlightNumber == "" {continue}
		// if a.BestIdent() == "" { continue }  // No ID info; not much interesting to say
		if a.Altitude > 28000 { continue }    // Too high to be the problem
		if a.Altitude <   500 { continue }    // Too low to be the problem

		// Strip out little planes
		skip := false
		for _,e := range kBlacklistEquipmentTypes {
			if a.EquipType == e { skip = true }
		}
		if skip { continue }
*/
	}

	return out
}

// }}}
// {{{ SelectOverhead

func SelectOverhead(snaps []fdb.FlightSnapshot) (*fdb.FlightSnapshot, string) {
	if len(snaps) == 0 { return nil, "** empty list\n" }

	// closest plane has to be within 12 km to be 'overhead', and it has
	// to be 4km away from the next-closest
	if (snaps[0].Dist3ToReferenceKM < 12.0) {
		if (len(snaps) == 1) || (snaps[1].Dist3ToReferenceKM - snaps[0].Dist3ToReferenceKM) > 4.0 {
			return &snaps[0], "** selected 1st\n"

		} else {
			return nil, "** 2nd was too close to 1st\n"
		}

	} else {
		return nil, "** 1st was too far away\n"
	}

}

// }}}

// {{{ FindAllOverhead

func FindAllOverhead(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (*Aircraft, []*Aircraft, []*Aircraft, error, string) {
	str := fmt.Sprintf("*** FindAllOverhead for %s@%.0fft, at %s\n", pos, elev, date.NowInPdt())

	outAll := []*Aircraft{}
	outFilt := []*Aircraft{}

	if pos.IsNil() {
		return nil, outAll, outFilt, fmt.Errorf("flightid.FindOverhead needs a non-nil position"), str
	}

	bbox := pos.Box(64,64) // A box with sides ~40 miles, centered on the observer

	as, deb, err := FetchAirspace(client, bbox)
	str += deb
	if err != nil { return nil, outAll, outFilt, err, str }

	snaps := AirspaceToSnapshots(as)
	for i,_ := range snaps {
		snaps[i].LocalizeTo(pos, elev)
	}
	sort.Sort(fdb.FlightSnapshotsByDist3(snaps))
	str += "** nearby list:-\n"+fdb.DebugFlightSnapshotList(snaps)

	filtered := FilterSnapshots(snaps)
	str += "** filtered:-\n"+fdb.DebugFlightSnapshotList(filtered)
	if len(filtered) == 0 { return nil, outAll, outFilt, nil, str }

	overheadSnap,debug := SelectOverhead(filtered)
	if overheadSnap == nil && grabAny {
		overheadSnap = &filtered[0]
		debug += "** grabbing first anyway\n"
	}
	str += debug

	for _,snap := range snaps { outAll = append(outAll, FlightSnapshotToAircraft(&snap)) }
	for _,snap := range filtered { outFilt = append(outFilt, FlightSnapshotToAircraft(&snap)) }

	return FlightSnapshotToAircraft(overheadSnap), outAll, outFilt, nil, str
}

// }}}
// {{{ FindOverhead

func FindOverhead(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (*Aircraft, error, string) {
	result := FindOverheadResult(client, pos, elev, grabAny)
	return result.Flight, result.Err, result.Debug
}

// }}}

// {{{ FindOverheadResult

func FindOverheadResult(client *http.Client, pos geo.Latlong, elev float64, grabAny bool) (out Result) {
	out.Debug = fmt.Sprintf("*** FindAllOverhead for %s@%.0fft, at %s\n", pos, elev, date.NowInPdt())

	if pos.IsNil() {
		out.Err = fmt.Errorf("flightid.FindOverhead needs a non-nil position")
		return
	}

	bbox := pos.Box(64,64) // A box with sides ~40 miles, centered on the observer

	as, deb, err := FetchAirspace(client, bbox)
	out.Debug += deb
	if err != nil {
		out.Err = err
		return
	}

	snaps := AirspaceToSnapshots(as)
	for i,_ := range snaps {
		snaps[i].LocalizeTo(pos, elev)
	}
	sort.Sort(fdb.FlightSnapshotsByDist3(snaps))
	out.Debug += "** nearby list:-\n"+fdb.DebugFlightSnapshotList(snaps)

	filtered := FilterSnapshots(snaps)
	out.Debug += "** filtered:-\n"+fdb.DebugFlightSnapshotList(filtered)
	if len(filtered) == 0 {
		return
	}

	overheadSnap,debug := SelectOverhead(filtered)
	if overheadSnap == nil && grabAny {
		overheadSnap = &filtered[0]
		out.Debug += "** grabbing first anyway\n"
	}
	out.Debug += debug

	out.All = []*Aircraft{}
	out.Filtered = []*Aircraft{}
	for _,snap := range snaps { out.All = append(out.All, FlightSnapshotToAircraft(&snap)) }
	for _,snap := range filtered { out.Filtered = append(out.Filtered, FlightSnapshotToAircraft(&snap)) }

	out.Flight = FlightSnapshotToAircraft(overheadSnap)
	return
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<|endoftext|>