<commit_before>package runkeeper

import (
	"log"
	"time"

	runkeeper "github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/c9s/go-runkeeper"
	dm "github.com/svdberg/syncmysport-runkeeper/datamodel"
)

const API = "API"

func ConvertToActivity(rkActivity *runkeeper.FitnessActivity) *dm.Activity {
	returnActivity := dm.CreateActivity()
	if rkActivity.Type == "Other" {
		returnActivity.Type = "Activity"
	} else {
		returnActivity.Type = rkActivity.Type
	}

	//RK time is 'Local'
	correctedTime := time.Time(rkActivity.StartTime).Add(time.Duration(rkActivity.UtcOffset) * time.Hour)
	log.Printf("RK Local date: %s, start date: %s, unix: %d, offset: %d", time.Time(rkActivity.StartTime), correctedTime, time.Time(rkActivity.StartTime).Unix(), rkActivity.UtcOffset)
	returnActivity.StartTime = int(time.Time(correctedTime).Unix())
	returnActivity.UtcOffSet = rkActivity.UtcOffset
	returnActivity.Duration = int(rkActivity.Duration)
	returnActivity.Name = rkActivity.Notes
	returnActivity.Notes = rkActivity.Notes
	returnActivity.Private = false
	returnActivity.Stationary = rkActivity.HasMap
	returnActivity.AverageHeartRate = rkActivity.AverageHeartRate
	returnActivity.Calories = rkActivity.TotalCalories
	returnActivity.Distance = rkActivity.TotalDistance
	returnActivity.GPS = convertFromPath(rkActivity.Path)
	returnActivity.HeartRate = convertFromHR(rkActivity.HeartRate)

	log.Printf("INPUT: %s, OUTPUT: %s", rkActivity, returnActivity)
	return returnActivity
}

func ConvertToRkActivity(activity *dm.Activity) *runkeeper.FitnessActivityNew {
	rkActivity := runkeeper.CreateNewFitnessActivity(activity.Name, float64(activity.Duration))

	rkActivity.Type = activity.Type
	//runkeeper only nows the following types:
	//Running, Cycling, Mountain Biking, Walking,
	//Hiking, Downhill Skiing, Cross-Country Skiing,
	//Snowboarding, Skating, Swimming, Wheelchair, Rowing, Elliptical, Other
	//
	//check if Type is one of these, otherwise Other.
	rkKnownTypes := map[string]string{
		"Running":              "Running",
		"Cycling":              "Cycling",
		"Mountain Biking":      "Mountain Biking",
		"Walking":              "Walking",
		"Hiking":               "Hiking",
		"Downhill Skiing":      "Downhill Skiing",
		"Cross-Country Skiing": "Cross-Country Skiing",
		"Snowboarding":         "Snowboarding",
		"Skating":              "Skating",
		"Swimming":             "Swimming",
		"Wheelchair":           "Wheelchair",
		"Rowing":               "Rowing",
		"Elliptical":           "Elliptical",
		"Other":                "Other"}

	_, ok := rkKnownTypes[activity.Type]
	if !ok {
		rkActivity.Type = "Other"
	}

	//runkeeper times are in local timezones, so covert back to the local time
	rkLocalLocation := time.FixedZone("rkZone", activity.UtcOffSet*60*60)
	rkActivity.StartTime = runkeeper.Time(time.Unix(int64(activity.StartTime), 0).In(rkLocalLocation))
	log.Printf("SMS time: %s, converted to RK time: %s for offset: %d", activity.StartTime, rkActivity.StartTime, activity.UtcOffSet)
	rkActivity.Notes = activity.Name
	rkActivity.TotalDistance = activity.Distance
	rkActivity.AverageHeartRate = activity.AverageHeartRate
	rkActivity.TotalCalories = activity.Calories
	rkActivity.Source = activity.Source
	rkActivity.EntryMode = API

	rkActivity.Path = convertToPath(activity.GPS)
	rkActivity.HeartRate = convertToHR(activity.HeartRate)
	return rkActivity
}

func convertToPath(gps []dm.GPS) []runkeeper.Path {
	rkPath := make([]runkeeper.Path, len(gps))
	for i, gp := range gps {
		rkPath[i] = runkeeper.Path{gp.Altitude, gp.Longitude, "gps", gp.Latitude, gp.Timestamp}
	}
	return rkPath
}

func convertFromPath(path []runkeeper.Path) []dm.GPS {
	dmPath := make([]dm.GPS, len(path))
	for i, rp := range path {
		dmPath[i] = dm.GPS{rp.Timestamp, rp.Altitude, rp.Longitude, rp.Latitude}
	}
	return dmPath
}

func convertToHR(hr []dm.HeartRate) []runkeeper.HeartRate {
	rkHr := make([]runkeeper.HeartRate, len(hr))
	for i, h := range hr {
		rkHr[i] = runkeeper.HeartRate{h.Timestamp, h.Heartrate}
	}
	return rkHr
}

func convertFromHR(rkHr []runkeeper.HeartRate) []dm.HeartRate {
	dmHr := make([]dm.HeartRate, len(rkHr))
	for i, h := range rkHr {
		dmHr[i] = dm.HeartRate{h.TimeStamp, h.HearRateNr}
	}
	return dmHr
}
<commit_msg>Convert to proper TZ in the Go way<commit_after>package runkeeper

import (
	"log"
	"time"

	runkeeper "github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/c9s/go-runkeeper"
	dm "github.com/svdberg/syncmysport-runkeeper/datamodel"
)

const API = "API"

func ConvertToActivity(rkActivity *runkeeper.FitnessActivity) *dm.Activity {
	returnActivity := dm.CreateActivity()
	if rkActivity.Type == "Other" {
		returnActivity.Type = "Activity"
	} else {
		returnActivity.Type = rkActivity.Type
	}

	//RK time is 'Local', convert to UTC
	sourceLocation := time.FixedZone("RKSourceLocation", rkActivity.UtcOffset*60*60)
	correctedTime := time.Time(rkActivity.StartTime).In(sourceLocation)
	log.Printf("RK Local date: %s, start date: %s, unix: %d, offset: %d", time.Time(rkActivity.StartTime), correctedTime, time.Time(rkActivity.StartTime).Unix(), rkActivity.UtcOffset)
	returnActivity.StartTime = int(time.Time(correctedTime).Unix())
	returnActivity.UtcOffSet = rkActivity.UtcOffset
	returnActivity.Duration = int(rkActivity.Duration)
	returnActivity.Name = rkActivity.Notes
	returnActivity.Notes = rkActivity.Notes
	returnActivity.Private = false
	returnActivity.Stationary = rkActivity.HasMap
	returnActivity.AverageHeartRate = rkActivity.AverageHeartRate
	returnActivity.Calories = rkActivity.TotalCalories
	returnActivity.Distance = rkActivity.TotalDistance
	returnActivity.GPS = convertFromPath(rkActivity.Path)
	returnActivity.HeartRate = convertFromHR(rkActivity.HeartRate)

	// log.Printf("INPUT: %s, OUTPUT: %s", rkActivity, returnActivity)
	return returnActivity
}

func ConvertToRkActivity(activity *dm.Activity) *runkeeper.FitnessActivityNew {
	rkActivity := runkeeper.CreateNewFitnessActivity(activity.Name, float64(activity.Duration))

	rkActivity.Type = activity.Type
	//runkeeper only nows the following types:
	//Running, Cycling, Mountain Biking, Walking,
	//Hiking, Downhill Skiing, Cross-Country Skiing,
	//Snowboarding, Skating, Swimming, Wheelchair, Rowing, Elliptical, Other
	//
	//check if Type is one of these, otherwise Other.
	rkKnownTypes := map[string]string{
		"Running":              "Running",
		"Cycling":              "Cycling",
		"Mountain Biking":      "Mountain Biking",
		"Walking":              "Walking",
		"Hiking":               "Hiking",
		"Downhill Skiing":      "Downhill Skiing",
		"Cross-Country Skiing": "Cross-Country Skiing",
		"Snowboarding":         "Snowboarding",
		"Skating":              "Skating",
		"Swimming":             "Swimming",
		"Wheelchair":           "Wheelchair",
		"Rowing":               "Rowing",
		"Elliptical":           "Elliptical",
		"Other":                "Other"}

	_, ok := rkKnownTypes[activity.Type]
	if !ok {
		rkActivity.Type = "Other"
	}

	//runkeeper times are in local timezones, so covert back to the local time
	rkLocalLocation := time.FixedZone("rkZone", activity.UtcOffSet*60*60)
	rkActivity.StartTime = runkeeper.Time(time.Unix(int64(activity.StartTime), 0).In(rkLocalLocation))
	log.Printf("SMS time: %s, converted to RK time: %s for offset: %d", activity.StartTime, rkActivity.StartTime, activity.UtcOffSet)
	rkActivity.Notes = activity.Name
	rkActivity.TotalDistance = activity.Distance
	rkActivity.AverageHeartRate = activity.AverageHeartRate
	rkActivity.TotalCalories = activity.Calories
	rkActivity.Source = activity.Source
	rkActivity.EntryMode = API

	rkActivity.Path = convertToPath(activity.GPS)
	rkActivity.HeartRate = convertToHR(activity.HeartRate)
	return rkActivity
}

func convertToPath(gps []dm.GPS) []runkeeper.Path {
	rkPath := make([]runkeeper.Path, len(gps))
	for i, gp := range gps {
		rkPath[i] = runkeeper.Path{gp.Altitude, gp.Longitude, "gps", gp.Latitude, gp.Timestamp}
	}
	return rkPath
}

func convertFromPath(path []runkeeper.Path) []dm.GPS {
	dmPath := make([]dm.GPS, len(path))
	for i, rp := range path {
		dmPath[i] = dm.GPS{rp.Timestamp, rp.Altitude, rp.Longitude, rp.Latitude}
	}
	return dmPath
}

func convertToHR(hr []dm.HeartRate) []runkeeper.HeartRate {
	rkHr := make([]runkeeper.HeartRate, len(hr))
	for i, h := range hr {
		rkHr[i] = runkeeper.HeartRate{h.Timestamp, h.Heartrate}
	}
	return rkHr
}

func convertFromHR(rkHr []runkeeper.HeartRate) []dm.HeartRate {
	dmHr := make([]dm.HeartRate, len(rkHr))
	for i, h := range rkHr {
		dmHr[i] = dm.HeartRate{h.TimeStamp, h.HearRateNr}
	}
	return dmHr
}
<|endoftext|>


<commit_before>package linker

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"plaid/parser"
)

type node struct {
	flag     int
	path     string
	ast      *parser.Program
	children []*node
	parents  []*node
	module   *Module
}

type graph struct {
	root  *node
	nodes map[string]*node
}

func (g *graph) resetFlags() {
	for _, n := range g.nodes {
		n.flag = 0
	}
}

// Link does some stuff
func Link(path string, ast *parser.Program, builtins ...*Module) (*Module, error) {
	order, err := resolve(path, ast)
	if err != nil {
		return nil, err
	}

	// Link ordered modules.
	for _, n := range order {
		for _, child := range n.children {
			n.module.Imports = append(n.module.Imports, child.module)
		}
	}

	return order[len(order)-1].module, nil
}

// resolve determines if a module has any dependency cycles
func resolve(path string, ast *parser.Program) ([]*node, error) {
	n := makeNode(path, ast)
	g, err := buildGraph(n, getDependencyPaths, loadDependency)
	if err != nil {
		return nil, err
	}

	if cycle := findCycle(g.root, nil); cycle != nil {
		return nil, fmt.Errorf("Dependency cycle: %s", routeToString(cycle))
	}

	order := orderDependencies(g)
	return order, nil
}

func nodesToModules(route []*node) (mods []*Module) {
	for _, n := range route {
		mod := n.module
		for _, dep := range n.children {
			if containsNode(route, dep) == false {

			}
		}
		mods = append(mods, mod)
	}
	return mods
}

func orderDependencies(g *graph) (order []*node) {
	const FlagTemp = 1
	const FlagPerm = 2

	var visit func(*node)
	visit = func(n *node) {
		if n.flag == FlagPerm {
			return
		} else if n.flag == FlagTemp {
			panic("not a DAG")
		} else {
			n.flag = FlagTemp
			for _, m := range n.children {
				visit(m)
			}
			n.flag = FlagPerm
			order = append(order, n)
		}
	}

	g.resetFlags()
	visit(g.root)
	return order
}

func routeToString(route []*node) (out string) {
	if len(route) == 0 {
		return "empty route"
	}

	for i, n := range route {
		if i == len(route)-1 {
			out += filepath.Base(n.path)
		} else {
			out += fmt.Sprintf("%s <- ", filepath.Base(n.path))
		}
	}
	return out
}

func findCycle(n *node, route []*node) (cycle []*node) {
	for _, child := range n.children {
		newRoute := append(route, n)

		if containsNode(newRoute, child) {
			return extractCycle(append(newRoute, child))
		}

		if cycle := findCycle(child, newRoute); cycle != nil {
			return cycle
		}
	}

	return nil
}

func containsNode(list []*node, goal *node) bool {
	for _, n := range list {
		if goal == n {
			return true
		}
	}

	return false
}

// extractCycle takes a slice of nodes and--assuming the last node in the slice
// is the start of a cycle--works backward through the slice trying to find a
// repetition of the node route[len(route)-1].
func extractCycle(route []*node) (cycle []*node) {
	for i := len(route) - 1; i >= 0; i-- {
		if len(cycle) > 0 && route[i] == cycle[0] {
			return append(cycle, route[i])
		}

		cycle = append(cycle, route[i])
	}

	return nil
}

func buildGraph(n *node, branch func(*node) []string, load func(string) (*node, error)) (g *graph, err error) {
	g = &graph{n, map[string]*node{}}
	done := map[string]*node{}
	todo := []*node{n}
	g.nodes[n.path] = n
	done[n.path] = n

	for len(todo) > 0 {
		n, todo = todo[0], todo[1:]
		for _, path := range branch(n) {
			if dep := done[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
			} else if dep := g.nodes[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
			} else if dep, err = load(path); err == nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
				g.nodes[path] = dep
			} else {
				return nil, err
			}
		}
		addDone(done, n)
	}

	return g, nil
}

func getDependencyPaths(n *node) (paths []string) {
	for _, stmt := range n.ast.Stmts {
		if stmt, ok := stmt.(*parser.UseStmt); ok {
			dir := filepath.Dir(n.path)
			path := filepath.Join(dir, stmt.Path.Val)
			paths = append(paths, path)
		}
	}

	return paths
}

func addParent(child *node, parent *node) {
	child.parents = append(child.parents, parent)
}

func addChild(parent *node, child *node) {
	parent.children = append(parent.children, child)
}

func addTodo(todo *[]*node, n *node) {
	*todo = append(*todo, n)
}

func addDone(done map[string]*node, n *node) {
	done[n.path] = n
}

func loadDependency(path string) (n *node, err error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	ast, err := parser.Parse(path, string(buf))
	if err != nil {
		return nil, err
	}

	return makeNode(path, ast), nil
}

func makeNode(path string, ast *parser.Program) *node {
	return &node{
		path: path,
		ast:  ast,
		module: &Module{
			Name: path,
			AST:  ast,
		},
	}
}
<commit_msg>remove dead code<commit_after>package linker

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"plaid/parser"
)

type node struct {
	flag     int
	path     string
	ast      *parser.Program
	children []*node
	parents  []*node
	module   *Module
}

type graph struct {
	root  *node
	nodes map[string]*node
}

func (g *graph) resetFlags() {
	for _, n := range g.nodes {
		n.flag = 0
	}
}

// Link does some stuff
func Link(path string, ast *parser.Program, builtins ...*Module) (*Module, error) {
	order, err := resolve(path, ast)
	if err != nil {
		return nil, err
	}

	// Link ordered modules.
	for _, n := range order {
		for _, child := range n.children {
			n.module.Imports = append(n.module.Imports, child.module)
		}
	}

	return order[len(order)-1].module, nil
}

// resolve determines if a module has any dependency cycles
func resolve(path string, ast *parser.Program) ([]*node, error) {
	n := makeNode(path, ast)
	g, err := buildGraph(n, getDependencyPaths, loadDependency)
	if err != nil {
		return nil, err
	}

	if cycle := findCycle(g.root, nil); cycle != nil {
		return nil, fmt.Errorf("Dependency cycle: %s", routeToString(cycle))
	}

	order := orderDependencies(g)
	return order, nil
}

func orderDependencies(g *graph) (order []*node) {
	const FlagTemp = 1
	const FlagPerm = 2

	var visit func(*node)
	visit = func(n *node) {
		if n.flag == FlagPerm {
			return
		} else if n.flag == FlagTemp {
			panic("not a DAG")
		} else {
			n.flag = FlagTemp
			for _, m := range n.children {
				visit(m)
			}
			n.flag = FlagPerm
			order = append(order, n)
		}
	}

	g.resetFlags()
	visit(g.root)
	return order
}

func routeToString(route []*node) (out string) {
	if len(route) == 0 {
		return "empty route"
	}

	for i, n := range route {
		if i == len(route)-1 {
			out += filepath.Base(n.path)
		} else {
			out += fmt.Sprintf("%s <- ", filepath.Base(n.path))
		}
	}
	return out
}

func findCycle(n *node, route []*node) (cycle []*node) {
	for _, child := range n.children {
		newRoute := append(route, n)

		if containsNode(newRoute, child) {
			return extractCycle(append(newRoute, child))
		}

		if cycle := findCycle(child, newRoute); cycle != nil {
			return cycle
		}
	}

	return nil
}

func containsNode(list []*node, goal *node) bool {
	for _, n := range list {
		if goal == n {
			return true
		}
	}

	return false
}

// extractCycle takes a slice of nodes and--assuming the last node in the slice
// is the start of a cycle--works backward through the slice trying to find a
// repetition of the node route[len(route)-1].
func extractCycle(route []*node) (cycle []*node) {
	for i := len(route) - 1; i >= 0; i-- {
		if len(cycle) > 0 && route[i] == cycle[0] {
			return append(cycle, route[i])
		}

		cycle = append(cycle, route[i])
	}

	return nil
}

func buildGraph(n *node, branch func(*node) []string, load func(string) (*node, error)) (g *graph, err error) {
	g = &graph{n, map[string]*node{}}
	done := map[string]*node{}
	todo := []*node{n}
	g.nodes[n.path] = n
	done[n.path] = n

	for len(todo) > 0 {
		n, todo = todo[0], todo[1:]
		for _, path := range branch(n) {
			if dep := done[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
			} else if dep := g.nodes[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
			} else if dep, err = load(path); err == nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
				g.nodes[path] = dep
			} else {
				return nil, err
			}
		}
		addDone(done, n)
	}

	return g, nil
}

func getDependencyPaths(n *node) (paths []string) {
	for _, stmt := range n.ast.Stmts {
		if stmt, ok := stmt.(*parser.UseStmt); ok {
			dir := filepath.Dir(n.path)
			path := filepath.Join(dir, stmt.Path.Val)
			paths = append(paths, path)
		}
	}

	return paths
}

func addParent(child *node, parent *node) {
	child.parents = append(child.parents, parent)
}

func addChild(parent *node, child *node) {
	parent.children = append(parent.children, child)
}

func addTodo(todo *[]*node, n *node) {
	*todo = append(*todo, n)
}

func addDone(done map[string]*node, n *node) {
	done[n.path] = n
}

func loadDependency(path string) (n *node, err error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	ast, err := parser.Parse(path, string(buf))
	if err != nil {
		return nil, err
	}

	return makeNode(path, ast), nil
}

func makeNode(path string, ast *parser.Program) *node {
	return &node{
		path: path,
		ast:  ast,
		module: &Module{
			Name: path,
			AST:  ast,
		},
	}
}
<|endoftext|>


<commit_before>package s2tools

import (
	"github.com/golang/geo/s2"
	"github.com/twpayne/go-geom"
	"github.com/twpayne/go-geom/encoding/geojson"
)

// CellUnionToGeoJSON helpers to display s2 cells on maps with GeoJSON
// exports cell union into its GeoJSON representation
func CellUnionToGeoJSON(cu s2.CellUnion) []byte {
	fc := geojson.FeatureCollection{}
	for _, cid := range cu {
		f := &geojson.Feature{}
		f.Properties = make(map[string]interface{})
		f.Properties["id"] = cid.ToToken()
		f.Properties["uid"] = uint64(cid)
		f.Properties["level"] = cid.Level()

		c := s2.CellFromCellID(cid)
		coords := make([]float64, 5*2)
		for i := 0; i < 4; i++ {
			p := c.Vertex(i)
			ll := s2.LatLngFromPoint(p)
			coords[i*2] = ll.Lng.Degrees()
			coords[i*2+1] = ll.Lat.Degrees()
		}
		// last is first
		coords[8], coords[9] = coords[0], coords[1]
		ng := geom.NewPolygonFlat(geom.XY, coords, []int{10})
		f.Geometry = ng
		fc.Features = append(fc.Features, f)
	}
	b, _ := fc.MarshalJSON()
	return b
}

// CellUnionToTokens a cell union to a token string list
func CellUnionToTokens(cu s2.CellUnion) []string {
	res := make([]string, len(cu))

	for i, c := range cu {
		res[i] = c.ToToken()
	}
	return res
}
<commit_msg>added str representation<commit_after>package s2tools

import (
	"github.com/golang/geo/s2"
	"github.com/twpayne/go-geom"
	"github.com/twpayne/go-geom/encoding/geojson"
)

// CellUnionToGeoJSON helpers to display s2 cells on maps with GeoJSON
// exports cell union into its GeoJSON representation
func CellUnionToGeoJSON(cu s2.CellUnion) []byte {
	fc := geojson.FeatureCollection{}
	for _, cid := range cu {
		f := &geojson.Feature{}
		f.Properties = make(map[string]interface{})
		f.Properties["id"] = cid.ToToken()
		f.Properties["uid"] = uint64(cid)
		f.Properties["str"] = cid.String()
		f.Properties["level"] = cid.Level()

		c := s2.CellFromCellID(cid)
		coords := make([]float64, 5*2)
		for i := 0; i < 4; i++ {
			p := c.Vertex(i)
			ll := s2.LatLngFromPoint(p)
			coords[i*2] = ll.Lng.Degrees()
			coords[i*2+1] = ll.Lat.Degrees()
		}
		// last is first
		coords[8], coords[9] = coords[0], coords[1]
		ng := geom.NewPolygonFlat(geom.XY, coords, []int{10})
		f.Geometry = ng
		fc.Features = append(fc.Features, f)
	}
	b, _ := fc.MarshalJSON()
	return b
}

// CellUnionToTokens a cell union to a token string list
func CellUnionToTokens(cu s2.CellUnion) []string {
	res := make([]string, len(cu))

	for i, c := range cu {
		res[i] = c.ToToken()
	}
	return res
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package common

import (
	"context"
	"reflect"
	"strings"

	"github.com/dop251/goja"
	"github.com/pkg/errors"
	"github.com/serenize/snaker"
)

var (
	ctxPtrT = reflect.TypeOf((*context.Context)(nil))
	ctxT    = reflect.TypeOf((*context.Context)(nil)).Elem()
	errorT  = reflect.TypeOf((*error)(nil)).Elem()
	jsValT  = reflect.TypeOf((*goja.Value)(nil)).Elem()
	fnCallT = reflect.TypeOf((*goja.FunctionCall)(nil)).Elem()

	constructWrap = goja.MustCompile(
		"__constructor__",
		`(function(impl) { return function() { return impl.apply(this, arguments); } })`,
		true,
	)
)

// Returns the JS name for an exported struct field. The name is snake_cased, with respect for
// certain common initialisms (URL, ID, HTTP, etc).
func FieldName(t reflect.Type, f reflect.StructField) string {
	// PkgPath is non-empty for unexported fields.
	if f.PkgPath != "" {
		return ""
	}

	// Allow a `js:"name"` tag to override the default name.
	if tag := f.Tag.Get("js"); tag != "" {
		// Matching encoding/json, `js:"-"` hides a field.
		if tag == "-" {
			return ""
		}
		return tag
	}

	// Default to lowercasing the first character of the field name.
	return snaker.CamelToSnake(f.Name)
}

// Returns the JS name for an exported method. The first letter of the method's name is
// lowercased, otherwise it is unaltered.
func MethodName(t reflect.Type, m reflect.Method) string {
	// A field with a name beginning with an X is a constructor, and just gets the prefix stripped.
	// Note: They also get some special treatment from Bridge(), see further down.
	if m.Name[0] == 'X' {
		return m.Name[1:]
	}

	// Lowercase the first character of the method name.
	return strings.ToLower(m.Name[0:1]) + m.Name[1:]
}

// FieldNameMapper for goja.Runtime.SetFieldNameMapper()
type FieldNameMapper struct{}

func (FieldNameMapper) FieldName(t reflect.Type, f reflect.StructField) string { return FieldName(t, f) }

func (FieldNameMapper) MethodName(t reflect.Type, m reflect.Method) string { return MethodName(t, m) }

// Binds an object's members to the global scope. Returns a function that un-binds them.
// Note that this will panic if passed something that isn't a struct; please don't do that.
func BindToGlobal(rt *goja.Runtime, data map[string]interface{}) func() {
	keys := make([]string, len(data))
	i := 0
	for k, v := range data {
		rt.Set(k, v)
		keys[i] = k
		i++
	}

	return func() {
		for _, k := range keys {
			rt.Set(k, goja.Undefined())
		}
	}
}

func Bind(rt *goja.Runtime, v interface{}, ctxPtr *context.Context) map[string]interface{} {
	exports := make(map[string]interface{})

	val := reflect.ValueOf(v)
	typ := val.Type()
	for i := 0; i < typ.NumMethod(); i++ {
		meth := typ.Method(i)
		name := MethodName(typ, meth)
		fn := val.Method(i)

		// Figure out if we want to do any wrapping of it.
		fnT := fn.Type()
		numIn := fnT.NumIn()
		numOut := fnT.NumOut()
		hasError := (numOut > 1 && fnT.Out(1) == errorT)
		wantsContext := false
		wantsContextPtr := false
		if numIn > 0 {
			in0 := fnT.In(0)
			switch in0 {
			case ctxT:
				wantsContext = true
			case ctxPtrT:
				wantsContextPtr = true
			}
		}
		if hasError || wantsContext || wantsContextPtr {
			isVaradic := fnT.IsVariadic()
			realFn := fn
			fn = reflect.ValueOf(func(call goja.FunctionCall) goja.Value {
				// Number of arguments: the higher number between the function's required arguments
				// and the number of arguments actually given.
				args := make([]reflect.Value, numIn)

				// Inject any requested parameters, and reserve them to offset user args.
				reservedArgs := 0
				if wantsContext {
					if ctxPtr == nil || *ctxPtr == nil {
						Throw(rt, errors.Errorf("%s() can only be called from within default()", name))
					}
					args[0] = reflect.ValueOf(*ctxPtr)
					reservedArgs++
				} else if wantsContextPtr {
					args[0] = reflect.ValueOf(ctxPtr)
					reservedArgs++
				}

				// Copy over arguments.
				for i := 0; i < numIn; i++ {
					if i < reservedArgs {
						continue
					}

					T := fnT.In(i)

					// A function that takes a goja.FunctionCall takes only that arg (+ injected).
					if T == fnCallT {
						args[i] = reflect.ValueOf(call)
						break
					}

					// The last arg to a varadic function is a slice of the remainder.
					if isVaradic && i == numIn-1 {
						varArgsLen := len(call.Arguments) - (i - reservedArgs)
						if varArgsLen <= 0 {
							args[i] = reflect.Zero(T)
							break
						}
						varArgs := reflect.MakeSlice(T, varArgsLen, varArgsLen)
						emT := T.Elem()
						for j := 0; j < varArgsLen; j++ {
							arg := call.Arguments[i+j-reservedArgs]
							v := reflect.New(emT)
							if err := rt.ExportTo(arg, v.Interface()); err != nil {
								Throw(rt, err)
							}
							varArgs.Index(j).Set(v.Elem())
						}
						args[i] = varArgs
						break
					}

					arg := call.Argument(i - reservedArgs)

					// Optimization: no need to allocate a pointer and export for a zero value.
					if goja.IsUndefined(arg) {
						if T == jsValT {
							args[i] = reflect.ValueOf(goja.Undefined())
							continue
						}
						args[i] = reflect.Zero(T)
						continue
					}

					// Allocate a T* and export the JS value to it.
					v := reflect.New(T)
					if err := rt.ExportTo(arg, v.Interface()); err != nil {
						Throw(rt, err)
					}
					args[i] = v.Elem()
				}

				var ret []reflect.Value
				if isVaradic {
					ret = realFn.CallSlice(args)
				} else {
					ret = realFn.Call(args)
				}

				if len(ret) > 0 {
					if hasError && !ret[1].IsNil() {
						Throw(rt, ret[1].Interface().(error))
					}
					return rt.ToValue(ret[0].Interface())
				}
				return goja.Undefined()
			})
		}

		// X-Prefixed methods are assumed to be constructors; use a closure to wrap them in a
		// pure-JS function to allow them to be `new`d. (This is an awful hack...)
		if meth.Name[0] == 'X' {
			wrapperV, _ := rt.RunProgram(constructWrap)
			wrapper, _ := goja.AssertFunction(wrapperV)
			v, _ := wrapper(goja.Undefined(), rt.ToValue(fn.Interface()))
			exports[name] = v
		} else {
			exports[name] = fn.Interface()
		}
	}

	// If v is a pointer, we need to indirect it to access fields.
	if typ.Kind() == reflect.Ptr {
		val = val.Elem()
		typ = val.Type()
	}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := FieldName(typ, field)
		if name != "" {
			exports[name] = val.Field(i).Interface()
		}
	}

	return exports
}
<commit_msg>Fix typo<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package common

import (
	"context"
	"reflect"
	"strings"

	"github.com/dop251/goja"
	"github.com/pkg/errors"
	"github.com/serenize/snaker"
)

var (
	ctxPtrT = reflect.TypeOf((*context.Context)(nil))
	ctxT    = reflect.TypeOf((*context.Context)(nil)).Elem()
	errorT  = reflect.TypeOf((*error)(nil)).Elem()
	jsValT  = reflect.TypeOf((*goja.Value)(nil)).Elem()
	fnCallT = reflect.TypeOf((*goja.FunctionCall)(nil)).Elem()

	constructWrap = goja.MustCompile(
		"__constructor__",
		`(function(impl) { return function() { return impl.apply(this, arguments); } })`,
		true,
	)
)

// Returns the JS name for an exported struct field. The name is snake_cased, with respect for
// certain common initialisms (URL, ID, HTTP, etc).
func FieldName(t reflect.Type, f reflect.StructField) string {
	// PkgPath is non-empty for unexported fields.
	if f.PkgPath != "" {
		return ""
	}

	// Allow a `js:"name"` tag to override the default name.
	if tag := f.Tag.Get("js"); tag != "" {
		// Matching encoding/json, `js:"-"` hides a field.
		if tag == "-" {
			return ""
		}
		return tag
	}

	// Default to lowercasing the first character of the field name.
	return snaker.CamelToSnake(f.Name)
}

// Returns the JS name for an exported method. The first letter of the method's name is
// lowercased, otherwise it is unaltered.
func MethodName(t reflect.Type, m reflect.Method) string {
	// A field with a name beginning with an X is a constructor, and just gets the prefix stripped.
	// Note: They also get some special treatment from Bridge(), see further down.
	if m.Name[0] == 'X' {
		return m.Name[1:]
	}

	// Lowercase the first character of the method name.
	return strings.ToLower(m.Name[0:1]) + m.Name[1:]
}

// FieldNameMapper for goja.Runtime.SetFieldNameMapper()
type FieldNameMapper struct{}

func (FieldNameMapper) FieldName(t reflect.Type, f reflect.StructField) string { return FieldName(t, f) }

func (FieldNameMapper) MethodName(t reflect.Type, m reflect.Method) string { return MethodName(t, m) }

// Binds an object's members to the global scope. Returns a function that un-binds them.
// Note that this will panic if passed something that isn't a struct; please don't do that.
func BindToGlobal(rt *goja.Runtime, data map[string]interface{}) func() {
	keys := make([]string, len(data))
	i := 0
	for k, v := range data {
		rt.Set(k, v)
		keys[i] = k
		i++
	}

	return func() {
		for _, k := range keys {
			rt.Set(k, goja.Undefined())
		}
	}
}

func Bind(rt *goja.Runtime, v interface{}, ctxPtr *context.Context) map[string]interface{} {
	exports := make(map[string]interface{})

	val := reflect.ValueOf(v)
	typ := val.Type()
	for i := 0; i < typ.NumMethod(); i++ {
		meth := typ.Method(i)
		name := MethodName(typ, meth)
		fn := val.Method(i)

		// Figure out if we want to do any wrapping of it.
		fnT := fn.Type()
		numIn := fnT.NumIn()
		numOut := fnT.NumOut()
		hasError := (numOut > 1 && fnT.Out(1) == errorT)
		wantsContext := false
		wantsContextPtr := false
		if numIn > 0 {
			in0 := fnT.In(0)
			switch in0 {
			case ctxT:
				wantsContext = true
			case ctxPtrT:
				wantsContextPtr = true
			}
		}
		if hasError || wantsContext || wantsContextPtr {
			isVariadic := fnT.IsVariadic()
			realFn := fn
			fn = reflect.ValueOf(func(call goja.FunctionCall) goja.Value {
				// Number of arguments: the higher number between the function's required arguments
				// and the number of arguments actually given.
				args := make([]reflect.Value, numIn)

				// Inject any requested parameters, and reserve them to offset user args.
				reservedArgs := 0
				if wantsContext {
					if ctxPtr == nil || *ctxPtr == nil {
						Throw(rt, errors.Errorf("%s() can only be called from within default()", name))
					}
					args[0] = reflect.ValueOf(*ctxPtr)
					reservedArgs++
				} else if wantsContextPtr {
					args[0] = reflect.ValueOf(ctxPtr)
					reservedArgs++
				}

				// Copy over arguments.
				for i := 0; i < numIn; i++ {
					if i < reservedArgs {
						continue
					}

					T := fnT.In(i)

					// A function that takes a goja.FunctionCall takes only that arg (+ injected).
					if T == fnCallT {
						args[i] = reflect.ValueOf(call)
						break
					}

					// The last arg to a varadic function is a slice of the remainder.
					if isVariadic && i == numIn-1 {
						varArgsLen := len(call.Arguments) - (i - reservedArgs)
						if varArgsLen <= 0 {
							args[i] = reflect.Zero(T)
							break
						}
						varArgs := reflect.MakeSlice(T, varArgsLen, varArgsLen)
						emT := T.Elem()
						for j := 0; j < varArgsLen; j++ {
							arg := call.Arguments[i+j-reservedArgs]
							v := reflect.New(emT)
							if err := rt.ExportTo(arg, v.Interface()); err != nil {
								Throw(rt, err)
							}
							varArgs.Index(j).Set(v.Elem())
						}
						args[i] = varArgs
						break
					}

					arg := call.Argument(i - reservedArgs)

					// Optimization: no need to allocate a pointer and export for a zero value.
					if goja.IsUndefined(arg) {
						if T == jsValT {
							args[i] = reflect.ValueOf(goja.Undefined())
							continue
						}
						args[i] = reflect.Zero(T)
						continue
					}

					// Allocate a T* and export the JS value to it.
					v := reflect.New(T)
					if err := rt.ExportTo(arg, v.Interface()); err != nil {
						Throw(rt, err)
					}
					args[i] = v.Elem()
				}

				var ret []reflect.Value
				if isVariadic {
					ret = realFn.CallSlice(args)
				} else {
					ret = realFn.Call(args)
				}

				if len(ret) > 0 {
					if hasError && !ret[1].IsNil() {
						Throw(rt, ret[1].Interface().(error))
					}
					return rt.ToValue(ret[0].Interface())
				}
				return goja.Undefined()
			})
		}

		// X-Prefixed methods are assumed to be constructors; use a closure to wrap them in a
		// pure-JS function to allow them to be `new`d. (This is an awful hack...)
		if meth.Name[0] == 'X' {
			wrapperV, _ := rt.RunProgram(constructWrap)
			wrapper, _ := goja.AssertFunction(wrapperV)
			v, _ := wrapper(goja.Undefined(), rt.ToValue(fn.Interface()))
			exports[name] = v
		} else {
			exports[name] = fn.Interface()
		}
	}

	// If v is a pointer, we need to indirect it to access fields.
	if typ.Kind() == reflect.Ptr {
		val = val.Elem()
		typ = val.Type()
	}
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := FieldName(typ, field)
		if name != "" {
			exports[name] = val.Field(i).Interface()
		}
	}

	return exports
}
<|endoftext|>


<commit_before>// This package will create a CSCC notification config that sends all active findings to the
// specified Pub/Sub topic.
//
// Download the service account's key and save to `./credentials/auth.json`. Set this as your
// default credentials by running:
//
// `export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/credentials.auth.json`
//
// To authorize this client you'll need to create a service account with the following roles:
//
// 	```
// 	gcloud beta organizations add-iam-policy-binding \
//	$ORGANIZATION_ID \
//	--member="serviceAccount:$ACCOUNT" \
//	--role='roles/securitycenter.notificationConfigEditor'
// 	```
//
// The account you run the above gcloud command must have Organization Admin privileges. Once a new
// notification config is created you'll receive the name of the automatically generated service
// account associated with CSCC notifications. You'll then need to grant that service account publish
// writes to create Pub/Sub messages.
//
// ```
//	gcloud beta pubsub topics add-iam-policy-binding \
//	projects/$PROJECT_ID/topics/$TOPIC_ID \
//	--member="serviceAccount:service-997507777601@gcp-sa-scc-notification.iam.gserviceaccount.com" \
//	--role="roles/pubsub.admin"
// ```
//
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://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 main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	securitycenter "cloud.google.com/go/securitycenter/apiv1p1alpha1"
	"google.golang.org/api/iterator"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1p1alpha1"
)

var (
	cmd   = flag.String("command", "list", "command to run {list,create}")
	orgID = flag.String("orgID", "", "organization ID")
	topic = flag.String("topic", "", "pubsub topic name to use")
)

func main() {
	flag.Parse()
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		log.Fatalf("failed to init client: %q", err)
		os.Exit(1)
	}
	switch *cmd {
	case "list":
		if *orgID == "" || *topic == "" {
			log.Fatalf("orgID and topic flags required")
			os.Exit(1)
		}
		if err := list(ctx, client, *orgID, *topic); err != nil {
			log.Fatalf("failed to init client: %q", err)
			os.Exit(1)
		}
	case "create":
		// TODO(tomfitzgerald): Finish this.
		fmt.Println("NYI")
	default:
		fmt.Printf("%s command not supported", *cmd)
	}

}

func list(ctx context.Context, client *securitycenter.Client, orgID string, pubsubTopic string) error {
	defer client.Close()
	it := client.ListNotificationConfigs(ctx, &securitycenterpb.ListNotificationConfigsRequest{
		Parent: "organizations/" + orgID,
	})
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("id: %s\n", result)
	}
	return nil
}
<commit_msg>correct cli imports<commit_after>// This package will create a CSCC notification config that sends all active findings to the
// specified Pub/Sub topic.
//
// Download the service account's key and save to `./credentials/auth.json`. Set this as your
// default credentials by running:
//
// `export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/credentials.auth.json`
//
// To authorize this client you'll need to create a service account with the following roles:
//
// 	```
// 	gcloud beta organizations add-iam-policy-binding \
//	$ORGANIZATION_ID \
//	--member="serviceAccount:$ACCOUNT" \
//	--role='roles/securitycenter.notificationConfigEditor'
// 	```
//
// The account you run the above gcloud command must have Organization Admin privileges. Once a new
// notification config is created you'll receive the name of the automatically generated service
// account associated with CSCC notifications. You'll then need to grant that service account publish
// writes to create Pub/Sub messages.
//
// ```
//	gcloud beta pubsub topics add-iam-policy-binding \
//	projects/$PROJECT_ID/topics/$TOPIC_ID \
//	--member="serviceAccount:service-997507777601@gcp-sa-scc-notification.iam.gserviceaccount.com" \
//	--role="roles/pubsub.admin"
// ```
//
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://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 main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"

	securitycenter "github.com/googlecloudplatform/threat-automation/clients/cscc/apiv1p1alpha1"
	securitycenterpb "github.com/googlecloudplatform/threat-automation/clients/cscc/v1p1alpha1"
	"google.golang.org/api/iterator"
)

var (
	cmd   = flag.String("command", "list", "command to run {list,create}")
	orgID = flag.String("orgID", "", "organization ID")
	topic = flag.String("topic", "", "pubsub topic name to use")
)

func main() {
	flag.Parse()
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		log.Fatalf("failed to init client: %q", err)
		os.Exit(1)
	}
	// s
	switch *cmd {
	case "list":
		if *orgID == "" || *topic == "" {
			log.Fatalf("orgID and topic flags required")
			os.Exit(1)
		}
		if err := list(ctx, client, *orgID, *topic); err != nil {
			log.Fatalf("failed to init client: %q", err)
			os.Exit(1)
		}
	case "create":
		// TODO(tomfitzgerald): Finish this.
		fmt.Println("NYI")
	default:
		fmt.Printf("%s command not supported", *cmd)
	}

}

func list(ctx context.Context, client *securitycenter.Client, orgID string, pubsubTopic string) error {
	defer client.Close()
	it := client.ListNotificationConfigs(ctx, &securitycenterpb.ListNotificationConfigsRequest{
		Parent: "organizations/" + orgID,
	})
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Printf("id: %s\n", result)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/go-martini/martini"
	"log"
	"net/http"
	"os"
)

var clipboard string

func ClipboardGroup(r martini.Router) {
	r.Get("", CopyClipboard)
	r.Post("", PasteClipboard)
}

func CopyClipboard() (int, string) {
	log.Printf("Copied %s\n", clipboard)
	return 200, clipboard
}

func PasteClipboard(w http.ResponseWriter, r *http.Request) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Body)
	s := buf.String()
	clipboard = s
	log.Printf("Pasted %s\n", clipboard)
	fmt.Fprintf(w, "ok")
}

func main() {
	m := martini.Classic()
	//http.HandleFunc("/realclipper/api/clipboard", handler)
	m.Group("/realclipper/api/clipboard", ClipboardGroup)
	env_port := os.Getenv("REALCLIPPER_API_PORT")
	if env_port == "" {
		env_port = "8080"
	}
	port := fmt.Sprintf(":%s", env_port)
	log.Fatal(http.ListenAndServe(port, m))
}
<commit_msg>Adds support for CORS to the API<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/cors"
	"log"
	"net/http"
	"os"
)

var clipboard string

func ClipboardGroup(r martini.Router) {
	r.Get("", CopyClipboard)
	r.Post("", PasteClipboard)
}

func CopyClipboard() (int, string) {
	log.Printf("Copied %s\n", clipboard)
	return 200, clipboard
}

func PasteClipboard(w http.ResponseWriter, r *http.Request) {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Body)
	s := buf.String()
	clipboard = s
	log.Printf("Pasted %s\n", clipboard)
	fmt.Fprintf(w, "ok")
}

func main() {
	m := martini.Classic()
	//http.HandleFunc("/realclipper/api/clipboard", handler)
	m.Use(cors.Allow(&cors.Options{
		AllowOrigins: []string{"http://localhost:8080"},
	  }))
	m.Group("/realclipper/api/clipboard", ClipboardGroup)
	env_port := os.Getenv("REALCLIPPER_API_PORT")
	if env_port == "" {
		env_port = "8080"
	}
	port := fmt.Sprintf(":%s", env_port)
	log.Fatal(http.ListenAndServe(port, m))
}
<|endoftext|>


<commit_before>package app

import (
	"crypto/rand"
	"encoding/base64"
	"errors"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"text/template"

	"github.com/braintree/manners"
	"github.com/elazarl/go-bindata-assetfs"
	"github.com/gorilla/websocket"
	"github.com/hashicorp/hcl"
	"github.com/kr/pty"
)

type App struct {
	command []string
	options *Options

	upgrader *websocket.Upgrader
	server   *manners.GracefulServer

	titleTemplate *template.Template
}

type Options struct {
	Address         string                 `hcl:"address"`
	Port            string                 `hcl:"port"`
	PermitWrite     bool                   `hcl:"permit_write"`
	EnableBasicAuth bool                   `hcl:"enable_basic_auth"`
	Credential      string                 `hcl:"credential"`
	EnableRandomUrl bool                   `hcl:"enable_random_url"`
	RandomUrlLength int                    `hcl:"random_url_length"`
	IndexFile       string                 `hcl:"index_file"`
	EnableTLS       bool                   `hcl:"enable_tls"`
	TLSCrtFile      string                 `hcl:"tls_crt_file"`
	TLSKeyFile      string                 `hcl:"tls_key_file"`
	TitleFormat     string                 `hcl:"title_format"`
	EnableReconnect bool                   `hcl:"enable_reconnect"`
	ReconnectTime   int                    `hcl:"reconnect_time"`
	Once            bool                   `hcl:"once"`
	Preferences     map[string]interface{} `hcl:"preferences"`
}

var DefaultOptions = Options{
	Address:         "",
	Port:            "8080",
	PermitWrite:     false,
	EnableBasicAuth: false,
	Credential:      "",
	EnableRandomUrl: false,
	RandomUrlLength: 8,
	IndexFile:       "",
	EnableTLS:       false,
	TLSCrtFile:      "~/.gotty.crt",
	TLSKeyFile:      "~/.gotty.key",
	TitleFormat:     "GoTTY - {{ .Command }} ({{ .Hostname }})",
	EnableReconnect: false,
	ReconnectTime:   10,
	Once:            false,
	Preferences:     make(map[string]interface{}),
}

func New(command []string, options *Options) (*App, error) {
	titleTemplate, err := template.New("title").Parse(options.TitleFormat)
	if err != nil {
		return nil, errors.New("Title format string syntax error")
	}

	return &App{
		command: command,
		options: options,

		upgrader: &websocket.Upgrader{
			ReadBufferSize:  1024,
			WriteBufferSize: 1024,
			Subprotocols:    []string{"gotty"},
		},

		titleTemplate: titleTemplate,
	}, nil
}

func ApplyConfigFile(options *Options, filePath string) error {
	filePath = ExpandHomeDir(filePath)
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return err
	}

	fileString := []byte{}
	log.Printf("Loading config file at: %s", filePath)
	fileString, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	if err := hcl.Decode(options, string(fileString)); err != nil {
		return err
	}

	return nil
}

func (app *App) Run() error {
	if app.options.PermitWrite {
		log.Printf("Permitting clients to write input to the PTY.")
	}

	if app.options.Once {
		log.Printf("Once option is provided, accepting only one client")
	}

	path := ""
	if app.options.EnableRandomUrl {
		path += "/" + generateRandomString(app.options.RandomUrlLength)
	}

	endpoint := net.JoinHostPort(app.options.Address, app.options.Port)

	wsHandler := http.HandlerFunc(app.handleWS)
	customIndexHandler := http.HandlerFunc(app.handleCustomIndex)
	authTokenHandler := http.HandlerFunc(app.handleAuthToken)
	staticHandler := http.FileServer(
		&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "static"},
	)

	var siteMux = http.NewServeMux()

	if app.options.IndexFile != "" {
		log.Printf("Using index file at " + app.options.IndexFile)
		siteMux.Handle(path+"/", customIndexHandler)
	} else {
		siteMux.Handle(path+"/", http.StripPrefix(path+"/", staticHandler))
	}
	siteMux.Handle(path+"/auth_token.js", authTokenHandler)
	siteMux.Handle(path+"/js/", http.StripPrefix(path+"/", staticHandler))
	siteMux.Handle(path+"/favicon.png", http.StripPrefix(path+"/", staticHandler))

	siteHandler := http.Handler(siteMux)

	if app.options.EnableBasicAuth {
		log.Printf("Using Basic Authentication")
		siteHandler = wrapBasicAuth(siteHandler, app.options.Credential)
	}

	wsMux := http.NewServeMux()
	wsMux.Handle("/", siteHandler)
	wsMux.Handle(path+"/ws", wsHandler)
	siteHandler = (http.Handler(wsMux))

	siteHandler = wrapLogger(siteHandler)

	scheme := "http"
	if app.options.EnableTLS {
		scheme = "https"
	}
	log.Printf(
		"Server is starting with command: %s",
		strings.Join(app.command, " "),
	)
	if app.options.Address != "" {
		log.Printf(
			"URL: %s",
			(&url.URL{Scheme: scheme, Host: endpoint, Path: path + "/"}).String(),
		)
	} else {
		for _, address := range listAddresses() {
			log.Printf(
				"URL: %s",
				(&url.URL{
					Scheme: scheme,
					Host:   net.JoinHostPort(address, app.options.Port),
					Path:   path + "/",
				}).String(),
			)
		}
	}

	var err error
	app.server = manners.NewWithServer(
		&http.Server{Addr: endpoint, Handler: siteHandler},
	)
	if app.options.EnableTLS {
		crtFile := ExpandHomeDir(app.options.TLSCrtFile)
		keyFile := ExpandHomeDir(app.options.TLSKeyFile)
		log.Printf("TLS crt file: " + crtFile)
		log.Printf("TLS key file: " + keyFile)
		err = app.server.ListenAndServeTLS(crtFile, keyFile)
	} else {
		err = app.server.ListenAndServe()
	}
	if err != nil {
		return err
	}

	log.Printf("Exiting...")

	return nil
}

func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
	log.Printf("New client connected: %s", r.RemoteAddr)

	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	conn, err := app.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("Failed to upgrade connection: " + err.Error())
		return
	}

	_, initMessage, err := conn.ReadMessage()
	if err != nil || string(initMessage) != app.options.Credential {
		log.Print("Failed to authenticate websocket connection")
		conn.Close()
		return
	}

	cmd := exec.Command(app.command[0], app.command[1:]...)
	ptyIo, err := pty.Start(cmd)
	if err != nil {
		log.Print("Failed to execute command")
		return
	}
	log.Printf("Command is running for client %s with PID %d", r.RemoteAddr, cmd.Process.Pid)

	context := &clientContext{
		app:        app,
		request:    r,
		connection: conn,
		command:    cmd,
		pty:        ptyIo,
	}

	context.goHandleClient()
}

func (app *App) handleCustomIndex(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, ExpandHomeDir(app.options.IndexFile))
}

func (app *App) handleAuthToken(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("var gotty_auth_token = '" + app.options.Credential + "';"))
}

func (app *App) Exit() (firstCall bool) {
	if app.server != nil {
		firstCall = app.server.Close()
		if firstCall {
			log.Printf("Received Exit command, waiting for all clients to close sessions...")
		}
		return firstCall
	}
	return true
}

func wrapLogger(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		rw := &responseWrapper{w, 200}
		handler.ServeHTTP(rw, r)
		log.Printf("%s %d %s %s", r.RemoteAddr, rw.status, r.Method, r.URL.Path)
	})
}

func wrapBasicAuth(handler http.Handler, credential string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token := strings.SplitN(r.Header.Get("Authorization"), " ", 2)

		if len(token) != 2 || strings.ToLower(token[0]) != "basic" {
			w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
			http.Error(w, "Bad Request", http.StatusUnauthorized)
			return
		}

		payload, err := base64.StdEncoding.DecodeString(token[1])
		if err != nil {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}

		if credential != string(payload) {
			w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
			http.Error(w, "authorization failed", http.StatusUnauthorized)
			return
		}

		log.Printf("Basic Authentication Succeeded: %s", r.RemoteAddr)
		handler.ServeHTTP(w, r)
	})
}

func generateRandomString(length int) string {
	const base = 36
	size := big.NewInt(base)
	n := make([]byte, length)
	for i, _ := range n {
		c, _ := rand.Int(rand.Reader, size)
		n[i] = strconv.FormatInt(c.Int64(), base)[0]
	}
	return string(n)
}

func listAddresses() (addresses []string) {
	ifaces, _ := net.Interfaces()

	addresses = make([]string, 0, len(ifaces))

	for _, iface := range ifaces {
		ifAddrs, _ := iface.Addrs()
		for _, ifAddr := range ifAddrs {
			switch v := ifAddr.(type) {
			case *net.IPNet:
				addresses = append(addresses, v.IP.String())
			case *net.IPAddr:
				addresses = append(addresses, v.IP.String())
			}
		}
	}

	return
}

func ExpandHomeDir(path string) string {
	if path[0:2] == "~/" {
		return os.Getenv("HOME") + path[1:]
	} else {
		return path
	}
}
<commit_msg>Add client certificate fields to the configuration struct Add relevant logic<commit_after>package app

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"errors"
	"io/ioutil"
	"log"
	"math/big"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"text/template"

	"github.com/braintree/manners"
	"github.com/elazarl/go-bindata-assetfs"
	"github.com/gorilla/websocket"
	"github.com/hashicorp/hcl"
	"github.com/kr/pty"
)

type App struct {
	command []string
	options *Options

	upgrader *websocket.Upgrader
	server   *manners.GracefulServer

	titleTemplate *template.Template
}

type Options struct {
	Address                             string                 `hcl:"address"`
	Port                                string                 `hcl:"port"`
	PermitWrite                         bool                   `hcl:"permit_write"`
	EnableBasicAuth                     bool                   `hcl:"enable_basic_auth"`
	Credential                          string                 `hcl:"credential"`
	EnableRandomUrl                     bool                   `hcl:"enable_random_url"`
	RandomUrlLength                     int                    `hcl:"random_url_length"`
	IndexFile                           string                 `hcl:"index_file"`
	EnableTLS                           bool                   `hcl:"enable_tls"`
	TLSCrtFile                          string                 `hcl:"tls_crt_file"`
	TLSKeyFile                          string                 `hcl:"tls_key_file"`
	EnableClientCertificate             bool                   `hcl:"enable_client_certificate"`
	ClientCAFile                        string                 `hcl:"client_ca_file"`
	EnableClientCertificateVerification bool                   `hcl:"enable_client_certificate_verification"`
	TitleFormat                         string                 `hcl:"title_format"`
	EnableReconnect                     bool                   `hcl:"enable_reconnect"`
	ReconnectTime                       int                    `hcl:"reconnect_time"`
	Once                                bool                   `hcl:"once"`
	Preferences                         map[string]interface{} `hcl:"preferences"`
}

var DefaultOptions = Options{
	Address:                             "",
	Port:                                "8080",
	PermitWrite:                         false,
	EnableBasicAuth:                     false,
	Credential:                          "",
	EnableRandomUrl:                     false,
	RandomUrlLength:                     8,
	IndexFile:                           "",
	EnableTLS:                           false,
	TLSCrtFile:                          "~/.gotty.crt",
	TLSKeyFile:                          "~/.gotty.key",
	EnableClientCertificate:             false,
	ClientCAFile:                        "~/.gotty.ca.crt",
	EnableClientCertificateVerification: false,
	TitleFormat:                         "GoTTY - {{ .Command }} ({{ .Hostname }})",
	EnableReconnect:                     false,
	ReconnectTime:                       10,
	Once:                                false,
	Preferences:                         make(map[string]interface{}),
}

func New(command []string, options *Options) (*App, error) {
	titleTemplate, err := template.New("title").Parse(options.TitleFormat)
	if err != nil {
		return nil, errors.New("Title format string syntax error")
	}

	return &App{
		command: command,
		options: options,

		upgrader: &websocket.Upgrader{
			ReadBufferSize:  1024,
			WriteBufferSize: 1024,
			Subprotocols:    []string{"gotty"},
		},

		titleTemplate: titleTemplate,
	}, nil
}

func ApplyConfigFile(options *Options, filePath string) error {
	filePath = ExpandHomeDir(filePath)
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return err
	}

	fileString := []byte{}
	log.Printf("Loading config file at: %s", filePath)
	fileString, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	if err := hcl.Decode(options, string(fileString)); err != nil {
		return err
	}

	return nil
}

func (app *App) Run() error {
	if app.options.PermitWrite {
		log.Printf("Permitting clients to write input to the PTY.")
	}

	if app.options.Once {
		log.Printf("Once option is provided, accepting only one client")
	}

	path := ""
	if app.options.EnableRandomUrl {
		path += "/" + generateRandomString(app.options.RandomUrlLength)
	}

	endpoint := net.JoinHostPort(app.options.Address, app.options.Port)

	wsHandler := http.HandlerFunc(app.handleWS)
	customIndexHandler := http.HandlerFunc(app.handleCustomIndex)
	authTokenHandler := http.HandlerFunc(app.handleAuthToken)
	staticHandler := http.FileServer(
		&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "static"},
	)

	var siteMux = http.NewServeMux()

	if app.options.IndexFile != "" {
		log.Printf("Using index file at " + app.options.IndexFile)
		siteMux.Handle(path+"/", customIndexHandler)
	} else {
		siteMux.Handle(path+"/", http.StripPrefix(path+"/", staticHandler))
	}
	siteMux.Handle(path+"/auth_token.js", authTokenHandler)
	siteMux.Handle(path+"/js/", http.StripPrefix(path+"/", staticHandler))
	siteMux.Handle(path+"/favicon.png", http.StripPrefix(path+"/", staticHandler))

	siteHandler := http.Handler(siteMux)

	if app.options.EnableBasicAuth {
		log.Printf("Using Basic Authentication")
		siteHandler = wrapBasicAuth(siteHandler, app.options.Credential)
	}

	wsMux := http.NewServeMux()
	wsMux.Handle("/", siteHandler)
	wsMux.Handle(path+"/ws", wsHandler)
	siteHandler = (http.Handler(wsMux))

	siteHandler = wrapLogger(siteHandler)

	scheme := "http"
	if app.options.EnableTLS {
		scheme = "https"
	}
	log.Printf(
		"Server is starting with command: %s",
		strings.Join(app.command, " "),
	)
	if app.options.Address != "" {
		log.Printf(
			"URL: %s",
			(&url.URL{Scheme: scheme, Host: endpoint, Path: path + "/"}).String(),
		)
	} else {
		for _, address := range listAddresses() {
			log.Printf(
				"URL: %s",
				(&url.URL{
					Scheme: scheme,
					Host:   net.JoinHostPort(address, app.options.Port),
					Path:   path + "/",
				}).String(),
			)
		}
	}

	var err error
	app.server = manners.NewWithServer(
		&http.Server{Addr: endpoint, Handler: siteHandler},
	)
	if app.options.EnableTLS {
		crtFile := ExpandHomeDir(app.options.TLSCrtFile)
		keyFile := ExpandHomeDir(app.options.TLSKeyFile)
		log.Printf("TLS crt file: " + crtFile)
		log.Printf("TLS key file: " + keyFile)
		if app.options.EnableClientCertificate {
			caFile := ExpandHomeDir(app.options.ClientCAFile)
			log.Printf("Client CA file: " + caFile)
			caCert, err := ioutil.ReadFile(caFile)
			if err != nil {
				return errors.New("Cannot open CA file " + caFile)
			}
			caCertPool := x509.NewCertPool()
			if !caCertPool.AppendCertsFromPEM(caCert) {
				return errors.New("Cannot parse CA file data in " + caFile)
			}
			tlsVerifyPolicy := tls.RequireAnyClientCert
			if app.options.EnableClientCertificateVerification {
				log.Print("Enabling verification of client certificate")
				tlsVerifyPolicy = tls.RequireAndVerifyClientCert
			}
			tlsConfig := &tls.Config{
				ClientCAs:  caCertPool,
				ClientAuth: tlsVerifyPolicy,
			}
			app.server.TLSConfig = tlsConfig
		}
		err = app.server.ListenAndServeTLS(crtFile, keyFile)
	} else {
		err = app.server.ListenAndServe()
	}
	if err != nil {
		return err
	}

	log.Printf("Exiting...")

	return nil
}

func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
	log.Printf("New client connected: %s", r.RemoteAddr)

	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	conn, err := app.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("Failed to upgrade connection: " + err.Error())
		return
	}

	_, initMessage, err := conn.ReadMessage()
	if err != nil || string(initMessage) != app.options.Credential {
		log.Print("Failed to authenticate websocket connection")
		conn.Close()
		return
	}

	cmd := exec.Command(app.command[0], app.command[1:]...)
	ptyIo, err := pty.Start(cmd)
	if err != nil {
		log.Print("Failed to execute command")
		return
	}
	log.Printf("Command is running for client %s with PID %d", r.RemoteAddr, cmd.Process.Pid)

	context := &clientContext{
		app:        app,
		request:    r,
		connection: conn,
		command:    cmd,
		pty:        ptyIo,
	}

	context.goHandleClient()
}

func (app *App) handleCustomIndex(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, ExpandHomeDir(app.options.IndexFile))
}

func (app *App) handleAuthToken(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("var gotty_auth_token = '" + app.options.Credential + "';"))
}

func (app *App) Exit() (firstCall bool) {
	if app.server != nil {
		firstCall = app.server.Close()
		if firstCall {
			log.Printf("Received Exit command, waiting for all clients to close sessions...")
		}
		return firstCall
	}
	return true
}

func wrapLogger(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		rw := &responseWrapper{w, 200}
		handler.ServeHTTP(rw, r)
		log.Printf("%s %d %s %s", r.RemoteAddr, rw.status, r.Method, r.URL.Path)
	})
}

func wrapBasicAuth(handler http.Handler, credential string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token := strings.SplitN(r.Header.Get("Authorization"), " ", 2)

		if len(token) != 2 || strings.ToLower(token[0]) != "basic" {
			w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
			http.Error(w, "Bad Request", http.StatusUnauthorized)
			return
		}

		payload, err := base64.StdEncoding.DecodeString(token[1])
		if err != nil {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}

		if credential != string(payload) {
			w.Header().Set("WWW-Authenticate", `Basic realm="GoTTY"`)
			http.Error(w, "authorization failed", http.StatusUnauthorized)
			return
		}

		log.Printf("Basic Authentication Succeeded: %s", r.RemoteAddr)
		handler.ServeHTTP(w, r)
	})
}

func generateRandomString(length int) string {
	const base = 36
	size := big.NewInt(base)
	n := make([]byte, length)
	for i, _ := range n {
		c, _ := rand.Int(rand.Reader, size)
		n[i] = strconv.FormatInt(c.Int64(), base)[0]
	}
	return string(n)
}

func listAddresses() (addresses []string) {
	ifaces, _ := net.Interfaces()

	addresses = make([]string, 0, len(ifaces))

	for _, iface := range ifaces {
		ifAddrs, _ := iface.Addrs()
		for _, ifAddr := range ifAddrs {
			switch v := ifAddr.(type) {
			case *net.IPNet:
				addresses = append(addresses, v.IP.String())
			case *net.IPAddr:
				addresses = append(addresses, v.IP.String())
			}
		}
	}

	return
}

func ExpandHomeDir(path string) string {
	if path[0:2] == "~/" {
		return os.Getenv("HOME") + path[1:]
	} else {
		return path
	}
}
<|endoftext|>


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

package logger

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
)

const schema = "LogData7"

type Service struct {
	sync.Mutex

	stats  Stats
	origin string

	esIndex elasticsearch.IIndex
	id      int
}

func (service *Service) Init(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) error {
	var err error

	service.stats.CreatedOn = time.Now()
	/***
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	***/

	ok, err := esIndex.IndexExists()
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating index: %s", esIndex.IndexName())
		err = esIndex.Create("")
		if err != nil {
			log.Fatal(err)
		}
	}

	ok, err = esIndex.TypeExists(schema)
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating type: %s", schema)

		mapping :=
			`{
			"LogData7":{
				"dynamic": "strict",
				"properties": {
					"service": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"address": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"createdOn": {
						"type": "date",
						"store": true,
						"index": "not_analyzed"
					},
					"severity": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"message": {
						"type": "string",
						"store": true,
						"index": "analyzed"
					}
				}
			}
		}`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	service.esIndex = esIndex

	service.origin = string(sys.Name)

	return nil
}

func (service *Service) newInternalErrorResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusInternalServerError,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) newBadRequestResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusBadRequest,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) GetRoot() *piazza.JsonResponse {
	resp := &piazza.JsonResponse{
		StatusCode: 200,
		Data:       "Hi. I'm pz-logger.",
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) PostMessage(mssg *Message) *piazza.JsonResponse {
	err := mssg.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	_, err = service.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	service.stats.NumMessages++

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       mssg,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetStats() *piazza.JsonResponse {
	service.Lock()
	t := service.stats
	service.Unlock()

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       t,
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetMessage(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	pagination, err := piazza.NewJsonPagination(params)
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	dsl, err := createQueryDslAsString(pagination, params)
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	var searchResult *elasticsearch.SearchResult

	if dsl == "" {
		searchResult, err = service.esIndex.FilterByMatchAll(schema, pagination)
	} else {
		searchResult, err = service.esIndex.SearchByJSON(schema, dsl)
	}

	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	var lines = make([]Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var msg Message
			err = json.Unmarshal(*hit.Source, &msg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}

func createQueryDslAsString(
	pagination *piazza.JsonPagination,
	params *piazza.HttpQueryParams) (string, error) {

	must := []map[string]interface{}{}

	service, err := params.GetAsString("service", "")
	if err != nil {
		return "", err
	}

	contains, err := params.GetAsString("contains", "")
	if err != nil {
		return "", err
	}

	before, err := params.GetBefore(time.Time{})
	if err != nil {
		return "", err
	}

	after, err := params.GetAfter(time.Time{})
	if err != nil {
		return "", err
	}

	if service != "" {
		must = append(must, map[string]interface{}{
			"match": map[string]interface{}{
				"service": service,
			},
		})
	}

	if contains != "" {
		must = append(must, map[string]interface{}{
			"multi_match": map[string]interface{}{
				"query":  contains,
				"fields": []string{"address", "message", "service", "severity"},
			},
		})
	}

	if !after.IsZero() || !before.IsZero() {
		rangeParams := map[string]time.Time{}

		if !after.IsZero() {
			rangeParams["gte"] = after
		}

		if !before.IsZero() {
			rangeParams["lte"] = before
		}

		must = append(must, map[string]interface{}{
			"range": map[string]interface{}{
				"createdOn": rangeParams,
			},
		})
	}

	if len(must) == 0 {
		return "", nil
	}

	dsl := map[string]interface{}{
		"query": map[string]interface{}{
			"filtered": map[string]interface{}{
				"query": map[string]interface{}{
					"bool": map[string]interface{}{
						"must": must,
					},
				},
			},
		},
		"size": pagination.PerPage,
		"from": pagination.PerPage * pagination.Page,
	}

	dsl["sort"] = map[string]string{
		pagination.SortBy: string(pagination.Order),
	}

	output, err := json.Marshal(dsl)
	if err != nil {
		return "", err
	}

	return string(output), nil
}

func (service *Service) PostSyslog(mNew *piazza.SyslogMessage) *piazza.JsonResponse {
	err := mNew.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	rfc := mNew.String()
	mssgOld := Message{CreatedOn: time.Now(), Message: rfc}

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	_, err = service.esIndex.PostData(schema, idStr, mssgOld)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       rfc,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

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

package logger

import (
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
)

const schema = "LogData7"

type Service struct {
	sync.Mutex

	stats  Stats
	origin string

	esIndex elasticsearch.IIndex
	id      int
}

func (service *Service) Init(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) error {
	var err error

	service.stats.CreatedOn = time.Now()
	/***
	err = esIndex.Delete()
	if err != nil {
		log.Fatal(err)
	}
	if esIndex.IndexExists() {
		log.Fatal("index still exists")
	}
	err = esIndex.Create()
	if err != nil {
		log.Fatal(err)
	}
	***/

	ok, err := esIndex.IndexExists()
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating index: %s", esIndex.IndexName())
		err = esIndex.Create("")
		if err != nil {
			log.Fatal(err)
		}
	}

	ok, err = esIndex.TypeExists(schema)
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating type: %s", schema)

		mapping :=
			`{
			"LogData7":{
				"dynamic": "strict",
				"properties": {
					"service": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"address": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"createdOn": {
						"type": "date",
						"store": true,
						"index": "not_analyzed"
					},
					"severity": {
						"type": "string",
						"store": true,
						"index": "not_analyzed"
					},
					"message": {
						"type": "string",
						"store": true,
						"index": "analyzed"
					}
				}
			}
		}`

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	service.esIndex = esIndex

	service.origin = string(sys.Name)

	return nil
}

func (service *Service) newInternalErrorResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusInternalServerError,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) newBadRequestResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusBadRequest,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) GetRoot() *piazza.JsonResponse {
	resp := &piazza.JsonResponse{
		StatusCode: 200,
		Data:       "Hi. I'm pz-logger.",
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) PostMessage(mssg *Message) *piazza.JsonResponse {
	err := mssg.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	_, err = service.esIndex.PostData(schema, idStr, mssg)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	service.stats.NumMessages++

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       mssg,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetStats() *piazza.JsonResponse {
	service.Lock()
	t := service.stats
	service.Unlock()

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       t,
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetMessage(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	pagination, err := piazza.NewJsonPagination(params)
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	dsl, err := createQueryDslAsString(pagination, params)
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	var searchResult *elasticsearch.SearchResult

	if dsl == "" {
		searchResult, err = service.esIndex.FilterByMatchAll(schema, pagination)
	} else {
		searchResult, err = service.esIndex.SearchByJSON(schema, dsl)
	}

	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	var lines = make([]Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var msg Message
			err = json.Unmarshal(*hit.Source, &msg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}

func createQueryDslAsString(
	pagination *piazza.JsonPagination,
	params *piazza.HttpQueryParams) (string, error) {

	must := []map[string]interface{}{}

	service, err := params.GetAsString("service", "")
	if err != nil {
		return "", err
	}

	contains, err := params.GetAsString("contains", "")
	if err != nil {
		return "", err
	}

	before, err := params.GetBefore(time.Time{})
	if err != nil {
		return "", err
	}

	after, err := params.GetAfter(time.Time{})
	if err != nil {
		return "", err
	}

	if service != "" {
		must = append(must, map[string]interface{}{
			"match": map[string]interface{}{
				"service": service,
			},
		})
	}

	if contains != "" {
		must = append(must, map[string]interface{}{
			"multi_match": map[string]interface{}{
				"query":  contains,
				"fields": []string{"address", "message", "service", "severity"},
			},
		})
	}

	if !after.IsZero() || !before.IsZero() {
		rangeParams := map[string]time.Time{}

		if !after.IsZero() {
			rangeParams["gte"] = after
		}

		if !before.IsZero() {
			rangeParams["lte"] = before
		}

		must = append(must, map[string]interface{}{
			"range": map[string]interface{}{
				"createdOn": rangeParams,
			},
		})
	}

	if len(must) == 0 {
		return "", nil
	}

	dsl := map[string]interface{}{
		"query": map[string]interface{}{
			"filtered": map[string]interface{}{
				"query": map[string]interface{}{
					"bool": map[string]interface{}{
						"must": must,
					},
				},
			},
		},
		"size": pagination.PerPage,
		"from": pagination.PerPage * pagination.Page,
	}

	dsl["sort"] = map[string]string{
		pagination.SortBy: string(pagination.Order),
	}

	output, err := json.Marshal(dsl)
	if err != nil {
		return "", err
	}

	return string(output), nil
}

func (service *Service) PostSyslog(mNew *piazza.SyslogMessage) *piazza.JsonResponse {
	err := mNew.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	rfc := mNew.String()
	mssgOld := Message{
		CreatedOn: time.Now(),
		Service:   "alpha",
		Address:   "1.2.3.4",
		Severity:  "Debug",
		Message:   rfc,
	}
	err = mssgOld.Validate()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	_, err = service.esIndex.PostData(schema, idStr, mssgOld)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       rfc,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}
<|endoftext|>


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

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"sync/atomic"
	"time"
)

type log struct {
	level           Level
	name            string
	nextSeqid       uint64
	levelno         int
	levelname       string
	pathname        string
	filename        string
	module          string
	lineno          int
	funcName        string
	created         int64
	asctime         string
	msecs           int64
	relativeCreated int64
	thread          int
	threadName      string
	process         int
	message         string
	timestamp       int64
}

type field func(*logging, *log) interface{}

var fields = map[string]field{
	"name":            (*logging).lname,
	"nextSeqid":       (*logging).nextSeqid,
	"levelno":         (*logging).levelno,
	"levelname":       (*logging).levelname,
	"pathname":        (*logging).pathname,
	"filename":        (*logging).filename,
	"module":          (*logging).module,
	"lineno":          (*logging).lineno,
	"funcName":        (*logging).funcName,
	"created":         (*logging).created,
	"asctime":         (*logging).asctime,
	"msecs":           (*logging).msecs,
	"relativeCreated": (*logging).relativeCreated,
	"thread":          (*logging).thread,
	"threadName":      (*logging).threadName,
	"process":         (*logging).process,
	"message":         (*logging).message,
	"timestamp":       (*logging).timestamp,
}

const errString = "???"

// GetGoId returns the id of goroutine, which is defined in ./get_go_id.c
func GetGoId() int32

// generate the runtime information, including pathname, function name,
// filename, line number.
func genRuntime(l *log) {
	calldepth := 5
	pc, file, line, ok := runtime.Caller(calldepth)
	if ok {
		// generate short function name
		fname := runtime.FuncForPC(pc).Name()
		fshort := fname
		for i := len(fname) - 1; i > 0; i-- {
			if fname[i] == '.' {
				fshort = fname[i+1:]
				break
			}
		}

		l.pathname = file
		l.funcName = fshort
		l.filename = path.Base(file)
		l.lineno = line
	} else {
		l.pathname = errString
		l.funcName = errString
		l.filename = errString
		l.lineno = 0
	}
}

func (logger *logging) lname(l *log) interface{} {
	return logger.name
}

func (logger *logging) nextSeqid(l *log) interface{} {
	return atomic.AddUint64(&(logger.seqid), 1)
}

func (logger *logging) levelno(l *log) interface{} {
	return int(l.level)
}

func (logger *logging) levelname(l *log) interface{} {
	return levelNames[l.level]
}

func (logger *logging) pathname(l *log) interface{} {
	if l.pathname == "" {
		genRuntime(l)
	}
	return l.pathname
}

func (logger *logging) filename(l *log) interface{} {
	if l.filename == "" {
		genRuntime(l)
	}
	return l.filename
}

func (logger *logging) module(l *log) interface{} {
	return ""
}

func (logger *logging) lineno(l *log) interface{} {
	if l.lineno == 0 {
		genRuntime(l)
	}
	return l.lineno
}

func (logger *logging) funcName(l *log) interface{} {
	if l.funcName == "" {
		genRuntime(l)
	}
	return l.funcName
}

func (logger *logging) created(l *log) interface{} {
	return logger.startTime
}

func (logger *logging) asctime(l *log) interface{} {
	if l.asctime == "" {
		l.asctime = time.Now().String()
	}
	return l.asctime
}

func (logger *logging) msecs(l *log) interface{} {
	if l.msecs == 0 {
		l.msecs = logger.startTime % 1000
	}
	return l.msecs
}

func (logger *logging) timestamp(l *log) interface{} {
	if l.timestamp == 0 {
		l.timestamp = time.Now().UnixNano()
	}
	return l.timestamp
}

func (logger *logging) relativeCreated(l *log) interface{} {
	if l.relativeCreated == 0 {
		l.relativeCreated = time.Now().UnixNano() - logger.startTime
	}
	return l.relativeCreated
}

func (logger *logging) thread(l *log) interface{} {
	if l.thread == 0 {
		l.thread = int(GetGoId())
	}
	return l.thread
}

func (logger *logging) threadName(l *log) interface{} {
	if l.threadName == "" {
		l.threadName = fmt.Sprintf("Thread-%d", GetGoId())
	}
	return l.threadName
}

// Process ID
func (logger *logging) process(l *log) interface{} {
	if l.process == 0 {
		l.process = os.Getpid()
	}
	return l.process
}

func (logger *logging) message(l *log) interface{} {
	return l.message
}
<commit_msg>fix seqid issue<commit_after>// Copyright 2013, Cong Ding. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: Cong Ding <dinggnu@gmail.com>
//
package logging

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"sync/atomic"
	"time"
)

type log struct {
	level           Level
	name            string
	seqid           uint64
	levelno         int
	levelname       string
	pathname        string
	filename        string
	module          string
	lineno          int
	funcName        string
	created         int64
	asctime         string
	msecs           int64
	relativeCreated int64
	thread          int
	threadName      string
	process         int
	message         string
	timestamp       int64
}

type field func(*logging, *log) interface{}

var fields = map[string]field{
	"name":            (*logging).lname,
	"seqid":           (*logging).nextSeqid,
	"levelno":         (*logging).levelno,
	"levelname":       (*logging).levelname,
	"pathname":        (*logging).pathname,
	"filename":        (*logging).filename,
	"module":          (*logging).module,
	"lineno":          (*logging).lineno,
	"funcName":        (*logging).funcName,
	"created":         (*logging).created,
	"asctime":         (*logging).asctime,
	"msecs":           (*logging).msecs,
	"relativeCreated": (*logging).relativeCreated,
	"thread":          (*logging).thread,
	"threadName":      (*logging).threadName,
	"process":         (*logging).process,
	"message":         (*logging).message,
	"timestamp":       (*logging).timestamp,
}

const errString = "???"

// GetGoId returns the id of goroutine, which is defined in ./get_go_id.c
func GetGoId() int32

// generate the runtime information, including pathname, function name,
// filename, line number.
func genRuntime(l *log) {
	calldepth := 5
	pc, file, line, ok := runtime.Caller(calldepth)
	if ok {
		// generate short function name
		fname := runtime.FuncForPC(pc).Name()
		fshort := fname
		for i := len(fname) - 1; i > 0; i-- {
			if fname[i] == '.' {
				fshort = fname[i+1:]
				break
			}
		}

		l.pathname = file
		l.funcName = fshort
		l.filename = path.Base(file)
		l.lineno = line
	} else {
		l.pathname = errString
		l.funcName = errString
		l.filename = errString
		l.lineno = 0
	}
}

func (logger *logging) lname(l *log) interface{} {
	return logger.name
}

func (logger *logging) nextSeqid(l *log) interface{} {
	if l.seqid == 0 {
		l.seqid = atomic.AddUint64(&(logger.seqid), 1)
	}
	return l.seqid
}

func (logger *logging) levelno(l *log) interface{} {
	return int(l.level)
}

func (logger *logging) levelname(l *log) interface{} {
	return levelNames[l.level]
}

func (logger *logging) pathname(l *log) interface{} {
	if l.pathname == "" {
		genRuntime(l)
	}
	return l.pathname
}

func (logger *logging) filename(l *log) interface{} {
	if l.filename == "" {
		genRuntime(l)
	}
	return l.filename
}

func (logger *logging) module(l *log) interface{} {
	return ""
}

func (logger *logging) lineno(l *log) interface{} {
	if l.lineno == 0 {
		genRuntime(l)
	}
	return l.lineno
}

func (logger *logging) funcName(l *log) interface{} {
	if l.funcName == "" {
		genRuntime(l)
	}
	return l.funcName
}

func (logger *logging) created(l *log) interface{} {
	return logger.startTime
}

func (logger *logging) asctime(l *log) interface{} {
	if l.asctime == "" {
		l.asctime = time.Now().String()
	}
	return l.asctime
}

func (logger *logging) msecs(l *log) interface{} {
	if l.msecs == 0 {
		l.msecs = logger.startTime % 1000
	}
	return l.msecs
}

func (logger *logging) timestamp(l *log) interface{} {
	if l.timestamp == 0 {
		l.timestamp = time.Now().UnixNano()
	}
	return l.timestamp
}

func (logger *logging) relativeCreated(l *log) interface{} {
	if l.relativeCreated == 0 {
		l.relativeCreated = time.Now().UnixNano() - logger.startTime
	}
	return l.relativeCreated
}

func (logger *logging) thread(l *log) interface{} {
	if l.thread == 0 {
		l.thread = int(GetGoId())
	}
	return l.thread
}

func (logger *logging) threadName(l *log) interface{} {
	if l.threadName == "" {
		l.threadName = fmt.Sprintf("Thread-%d", GetGoId())
	}
	return l.threadName
}

// Process ID
func (logger *logging) process(l *log) interface{} {
	if l.process == 0 {
		l.process = os.Getpid()
	}
	return l.process
}

func (logger *logging) message(l *log) interface{} {
	return l.message
}
<|endoftext|>