<commit_before>// Copyright (C) 2019 Google 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 adreno

import (
	"context"
	"fmt"

	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/gapis/perfetto"
	perfetto_service "github.com/google/gapid/gapis/perfetto/service"
	"github.com/google/gapid/gapis/service"
)

var (
	slicesQuery = "" +
		"SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " +
		"FROM gpu_track t LEFT JOIN gpu_slice s " +
		"ON s.track_id = t.id AND t.scope = 'gpu_render_stage'"
	argsQueryFmt = "" +
		"SELECT key, string_value FROM args WHERE args.arg_set_id = %d"
	counterTracksQuery = "" +
		"SELECT id, name, unit, description FROM gpu_counter_track ORDER BY id"
	countersQueryFmt = "" +
		"SELECT ts, value FROM counter c WHERE c.track_id = %d ORDER BY ts"
)

func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) {
	slices, err := processGpuSlices(ctx, processor, handleMapping)
	if err != nil {
		log.Err(ctx, err, "Failed to get GPU slices")
	}
	counters, err := processCounters(ctx, processor, desc)
	if err != nil {
		log.Err(ctx, err, "Failed to get GPU counters")
	}
	return &service.ProfilingData{Slices: slices, Counters: counters}, nil
}

func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData_GpuSlices, error) {
	slicesQueryResult, err := processor.Query(slicesQuery)
	if err != nil {
		return nil, log.Errf(ctx, err, "SQL query failed: %v", slicesQuery)
	}

	trackIdCache := make(map[int64]bool)
	argsQueryCache := make(map[int64]*perfetto_service.QueryResult)
	slicesColumns := slicesQueryResult.GetColumns()
	numSliceRows := slicesQueryResult.GetNumRecords()
	slices := make([]*service.ProfilingData_GpuSlices_Slice, numSliceRows)
	var tracks []*service.ProfilingData_GpuSlices_Track
	// Grab all the column values. Depends on the order of columns selected in slicesQuery

	contextIds := slicesColumns[0].GetLongValues()
	for i, v := range contextIds {
		if m, ok := (*handleMapping)[uint64(v)]; ok {
			contextIds[i] = int64(m[0].TraceValue)
		} else {
			log.E(ctx, "Context Id could not found: %v", v)
		}
	}

	renderTargets := slicesColumns[1].GetLongValues()
	for i, v := range renderTargets {
		if m, ok := (*handleMapping)[uint64(v)]; ok {
			renderTargets[i] = int64(m[0].TraceValue)
		} else {
			log.E(ctx, "Render Target could not found: %v", v)
		}
	}

	frameIds := slicesColumns[2].GetLongValues()
	submissionIds := slicesColumns[3].GetLongValues()
	hwQueueIds := slicesColumns[4].GetLongValues()
	timestamps := slicesColumns[5].GetLongValues()
	durations := slicesColumns[6].GetLongValues()
	names := slicesColumns[7].GetStringValues()
	depths := slicesColumns[8].GetLongValues()
	argSetIds := slicesColumns[9].GetLongValues()
	trackIds := slicesColumns[10].GetLongValues()
	trackNames := slicesColumns[11].GetStringValues()

	for i := uint64(0); i < numSliceRows; i++ {
		var argsQueryResult *perfetto_service.QueryResult
		var ok bool
		if argsQueryResult, ok = argsQueryCache[argSetIds[i]]; !ok {
			argsQuery := fmt.Sprintf(argsQueryFmt, argSetIds[i])
			argsQueryResult, err = processor.Query(argsQuery)
			if err != nil {
				log.W(ctx, "SQL query failed: %v", argsQuery)
			}
			argsQueryCache[argSetIds[i]] = argsQueryResult
		}
		argsColumns := argsQueryResult.GetColumns()
		numArgsRows := argsQueryResult.GetNumRecords()
		var extras []*service.ProfilingData_GpuSlices_Slice_Extra
		for j := uint64(0); j < numArgsRows; j++ {
			keys := argsColumns[0].GetStringValues()
			values := argsColumns[1].GetStringValues()
			extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
				Name:  keys[j],
				Value: &service.ProfilingData_GpuSlices_Slice_Extra_StringValue{StringValue: values[j]},
			})
		}
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "contextId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(contextIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "renderTarget",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(renderTargets[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "frameId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(frameIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "submissionId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(submissionIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "hwQueueId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])},
		})

		slices[i] = &service.ProfilingData_GpuSlices_Slice{
			Ts:      uint64(timestamps[i]),
			Dur:     uint64(durations[i]),
			Label:   names[i],
			Depth:   int32(depths[i]),
			Extras:  extras,
			TrackId: int32(trackIds[i]),
		}

		if _, ok := trackIdCache[trackIds[i]]; !ok {
			trackIdCache[trackIds[i]] = true
			tracks = append(tracks, &service.ProfilingData_GpuSlices_Track{
				Id:   int32(trackIds[i]),
				Name: trackNames[i],
			})
		}
	}

	return &service.ProfilingData_GpuSlices{
		Slices: slices,
		Tracks: tracks,
	}, nil
}

func processCounters(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor) ([]*service.ProfilingData_Counter, error) {
	counterTracksQueryResult, err := processor.Query(counterTracksQuery)
	if err != nil {
		return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
	}
	// t.id, name, unit, description, ts, value
	tracksColumns := counterTracksQueryResult.GetColumns()
	numTracksRows := counterTracksQueryResult.GetNumRecords()
	counters := make([]*service.ProfilingData_Counter, numTracksRows)
	// Grab all the column values. Depends on the order of columns selected in countersQuery
	trackIds := tracksColumns[0].GetLongValues()
	names := tracksColumns[1].GetStringValues()
	units := tracksColumns[2].GetStringValues()
	descriptions := tracksColumns[3].GetStringValues()

	for i := uint64(0); i < numTracksRows; i++ {
		countersQuery := fmt.Sprintf(countersQueryFmt, trackIds[i])
		countersQueryResult, err := processor.Query(countersQuery)
		countersColumns := countersQueryResult.GetColumns()
		if err != nil {
			return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
		}
		timestampsLong := countersColumns[0].GetLongValues()
		timestamps := make([]uint64, len(timestampsLong))
		for i, t := range timestampsLong {
			timestamps[i] = uint64(t)
		}
		values := countersColumns[1].GetDoubleValues()
		// TODO(apbodnar) Populate the `default` field once the trace processor supports it (b/147432390)
		counters[i] = &service.ProfilingData_Counter{
			Id:          uint32(trackIds[i]),
			Name:        names[i],
			Unit:        units[i],
			Description: descriptions[i],
			Timestamps:  timestamps,
			Values:      values,
		}
	}
	return counters, nil
}
<commit_msg>Add translation for command buffer handles in GPU slices (#3674)<commit_after>// Copyright (C) 2019 Google 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 adreno

import (
	"context"
	"fmt"

	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/gapis/perfetto"
	perfetto_service "github.com/google/gapid/gapis/perfetto/service"
	"github.com/google/gapid/gapis/service"
)

var (
	slicesQuery = "" +
		"SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " +
		"FROM gpu_track t LEFT JOIN gpu_slice s " +
		"ON s.track_id = t.id AND t.scope = 'gpu_render_stage'"
	argsQueryFmt = "" +
		"SELECT key, string_value FROM args WHERE args.arg_set_id = %d"
	counterTracksQuery = "" +
		"SELECT id, name, unit, description FROM gpu_counter_track ORDER BY id"
	countersQueryFmt = "" +
		"SELECT ts, value FROM counter c WHERE c.track_id = %d ORDER BY ts"
)

func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) {
	slices, err := processGpuSlices(ctx, processor, handleMapping)
	if err != nil {
		log.Err(ctx, err, "Failed to get GPU slices")
	}
	counters, err := processCounters(ctx, processor, desc)
	if err != nil {
		log.Err(ctx, err, "Failed to get GPU counters")
	}
	return &service.ProfilingData{Slices: slices, Counters: counters}, nil
}

func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData_GpuSlices, error) {
	slicesQueryResult, err := processor.Query(slicesQuery)
	if err != nil {
		return nil, log.Errf(ctx, err, "SQL query failed: %v", slicesQuery)
	}

	trackIdCache := make(map[int64]bool)
	argsQueryCache := make(map[int64]*perfetto_service.QueryResult)
	slicesColumns := slicesQueryResult.GetColumns()
	numSliceRows := slicesQueryResult.GetNumRecords()
	slices := make([]*service.ProfilingData_GpuSlices_Slice, numSliceRows)
	var tracks []*service.ProfilingData_GpuSlices_Track
	// Grab all the column values. Depends on the order of columns selected in slicesQuery

	contextIds := slicesColumns[0].GetLongValues()
	for i, v := range contextIds {
		if m, ok := (*handleMapping)[uint64(v)]; ok {
			contextIds[i] = int64(m[0].TraceValue)
		} else {
			log.E(ctx, "Context Id not found: %v", v)
		}
	}

	renderTargets := slicesColumns[1].GetLongValues()
	for i, v := range renderTargets {
		if m, ok := (*handleMapping)[uint64(v)]; ok {
			renderTargets[i] = int64(m[0].TraceValue)
		} else {
			log.E(ctx, "Render Target not found: %v", v)
		}
	}

	commandBuffers := slicesColumns[5].GetLongValues()
	for i, v := range commandBuffers {
		if m, ok := (*handleMapping)[uint64(v)]; ok {
			commandBuffers[i] = int64(m[0].TraceValue)
		} else {
			log.E(ctx, "Command Buffer not found: %v", v)
		}
	}

	frameIds := slicesColumns[2].GetLongValues()
	submissionIds := slicesColumns[3].GetLongValues()
	hwQueueIds := slicesColumns[4].GetLongValues()
	timestamps := slicesColumns[6].GetLongValues()
	durations := slicesColumns[7].GetLongValues()
	names := slicesColumns[8].GetStringValues()
	depths := slicesColumns[9].GetLongValues()
	argSetIds := slicesColumns[10].GetLongValues()
	trackIds := slicesColumns[11].GetLongValues()
	trackNames := slicesColumns[12].GetStringValues()

	for i := uint64(0); i < numSliceRows; i++ {
		var argsQueryResult *perfetto_service.QueryResult
		var ok bool
		if argsQueryResult, ok = argsQueryCache[argSetIds[i]]; !ok {
			argsQuery := fmt.Sprintf(argsQueryFmt, argSetIds[i])
			argsQueryResult, err = processor.Query(argsQuery)
			if err != nil {
				log.W(ctx, "SQL query failed: %v", argsQuery)
			}
			argsQueryCache[argSetIds[i]] = argsQueryResult
		}
		argsColumns := argsQueryResult.GetColumns()
		numArgsRows := argsQueryResult.GetNumRecords()
		var extras []*service.ProfilingData_GpuSlices_Slice_Extra
		for j := uint64(0); j < numArgsRows; j++ {
			keys := argsColumns[0].GetStringValues()
			values := argsColumns[1].GetStringValues()
			extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
				Name:  keys[j],
				Value: &service.ProfilingData_GpuSlices_Slice_Extra_StringValue{StringValue: values[j]},
			})
		}
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "contextId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(contextIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "renderTarget",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(renderTargets[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "commandBuffer",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(commandBuffers[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "frameId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(frameIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "submissionId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(submissionIds[i])},
		})
		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
			Name:  "hwQueueId",
			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])},
		})

		slices[i] = &service.ProfilingData_GpuSlices_Slice{
			Ts:      uint64(timestamps[i]),
			Dur:     uint64(durations[i]),
			Label:   names[i],
			Depth:   int32(depths[i]),
			Extras:  extras,
			TrackId: int32(trackIds[i]),
		}

		if _, ok := trackIdCache[trackIds[i]]; !ok {
			trackIdCache[trackIds[i]] = true
			tracks = append(tracks, &service.ProfilingData_GpuSlices_Track{
				Id:   int32(trackIds[i]),
				Name: trackNames[i],
			})
		}
	}

	return &service.ProfilingData_GpuSlices{
		Slices: slices,
		Tracks: tracks,
	}, nil
}

func processCounters(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor) ([]*service.ProfilingData_Counter, error) {
	counterTracksQueryResult, err := processor.Query(counterTracksQuery)
	if err != nil {
		return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
	}
	// t.id, name, unit, description, ts, value
	tracksColumns := counterTracksQueryResult.GetColumns()
	numTracksRows := counterTracksQueryResult.GetNumRecords()
	counters := make([]*service.ProfilingData_Counter, numTracksRows)
	// Grab all the column values. Depends on the order of columns selected in countersQuery
	trackIds := tracksColumns[0].GetLongValues()
	names := tracksColumns[1].GetStringValues()
	units := tracksColumns[2].GetStringValues()
	descriptions := tracksColumns[3].GetStringValues()

	for i := uint64(0); i < numTracksRows; i++ {
		countersQuery := fmt.Sprintf(countersQueryFmt, trackIds[i])
		countersQueryResult, err := processor.Query(countersQuery)
		countersColumns := countersQueryResult.GetColumns()
		if err != nil {
			return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
		}
		timestampsLong := countersColumns[0].GetLongValues()
		timestamps := make([]uint64, len(timestampsLong))
		for i, t := range timestampsLong {
			timestamps[i] = uint64(t)
		}
		values := countersColumns[1].GetDoubleValues()
		// TODO(apbodnar) Populate the `default` field once the trace processor supports it (b/147432390)
		counters[i] = &service.ProfilingData_Counter{
			Id:          uint32(trackIds[i]),
			Name:        names[i],
			Unit:        units[i],
			Description: descriptions[i],
			Timestamps:  timestamps,
			Values:      values,
		}
	}
	return counters, nil
}
<|endoftext|>


<commit_before>package compat

import (
	"github.com/gonfire/jsonapi"
	"github.com/labstack/echo/engine/standard"
	"net/http"
)

// ParseRequest is a convenience method to parse a standard http.Request.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#ParseRequest.
func ParseRequest(r *http.Request, prefix string) (*jsonapi.Request, error) {
	return jsonapi.ParseRequest(standard.NewRequest(r, nil), prefix)
}

// WriteResponse is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResponse.
func WriteResponse(res http.ResponseWriter, status int, doc *jsonapi.Document) error {
	return jsonapi.WriteResponse(standard.NewResponse(res, nil), status, doc)
}

// WriteResource is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResource.
func WriteResource(w http.ResponseWriter, status int, resource *jsonapi.Resource, links *jsonapi.DocumentLinks, included ...*jsonapi.Resource) error {
	return jsonapi.WriteResource(standard.NewResponse(w, nil), status, resource, links, included...)
}

// WriteResources is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResources.
func WriteResources(w http.ResponseWriter, status int, resources []*jsonapi.Resource, links *jsonapi.DocumentLinks, included ...*jsonapi.Resource) error {
	return jsonapi.WriteResources(standard.NewResponse(w, nil), status, resources, links, included...)
}

// WriteError is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteError.
func WriteError(w http.ResponseWriter, err error) error {
	return jsonapi.WriteError(standard.NewResponse(w, nil), err)
}

// WriteErrorList is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteErrorList.
func WriteErrorList(w http.ResponseWriter, errors ...*jsonapi.Error) error {
	return jsonapi.WriteErrorList(standard.NewResponse(w, nil), errors...)
}
<commit_msg>cleanup<commit_after>package compat

import (
	"net/http"

	"github.com/gonfire/jsonapi"
	"github.com/labstack/echo/engine/standard"
)

// ParseRequest is a convenience method to parse a standard http.Request.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#ParseRequest.
func ParseRequest(r *http.Request, prefix string) (*jsonapi.Request, error) {
	return jsonapi.ParseRequest(standard.NewRequest(r, nil), prefix)
}

// WriteResponse is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResponse.
func WriteResponse(res http.ResponseWriter, status int, doc *jsonapi.Document) error {
	return jsonapi.WriteResponse(standard.NewResponse(res, nil), status, doc)
}

// WriteResource is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResource.
func WriteResource(w http.ResponseWriter, status int, resource *jsonapi.Resource, links *jsonapi.DocumentLinks, included ...*jsonapi.Resource) error {
	return jsonapi.WriteResource(standard.NewResponse(w, nil), status, resource, links, included...)
}

// WriteResources is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteResources.
func WriteResources(w http.ResponseWriter, status int, resources []*jsonapi.Resource, links *jsonapi.DocumentLinks, included ...*jsonapi.Resource) error {
	return jsonapi.WriteResources(standard.NewResponse(w, nil), status, resources, links, included...)
}

// WriteError is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteError.
func WriteError(w http.ResponseWriter, err error) error {
	return jsonapi.WriteError(standard.NewResponse(w, nil), err)
}

// WriteErrorList is a convenience method to write to a standard
// http.ResponseWriter.
//
// See: https://godoc.org/github.com/gonfire/jsonapi#WriteErrorList.
func WriteErrorList(w http.ResponseWriter, errors ...*jsonapi.Error) error {
	return jsonapi.WriteErrorList(standard.NewResponse(w, nil), errors...)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2022 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// 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/>.

//go:build (linux && arm) || (linux && ppc64) || (linux && ppc64le) || (linux && s390x)
// +build linux,arm linux,ppc64 linux,ppc64le linux,s390x

package kernel

func utsnameStr(in []uint8) string {
	out := make([]byte, 0, len(in))
	for i := 0; i < len(in); i++ {
		if in[i] == 0x00 {
			break
		}
		out = append(out, byte(in[i]))
	}
	return string(out)
}
<commit_msg>Add riscv64 support (#14601)<commit_after>// Copyright (c) 2015-2022 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// 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/>.

//go:build (linux && arm) || (linux && ppc64) || (linux && ppc64le) || (linux && s390x)|| (linux && riscv64)
// +build linux,arm linux,ppc64 linux,ppc64le linux,s390x linux,riscv64

package kernel

func utsnameStr(in []uint8) string {
	out := make([]byte, 0, len(in))
	for i := 0; i < len(in); i++ {
		if in[i] == 0x00 {
			break
		}
		out = append(out, byte(in[i]))
	}
	return string(out)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/urfave/cli"
)

func CrawlTrending(lang string, count int) error {
	doc, err := goquery.NewDocument("https://github.com/trending/" + lang)
	if err != nil {
		log.Fatal(err)
		return err
	}

	repoList := doc.Find(".d-inline-block > h3 > a").Slice(0, count)

	repoList.Each(func(i int, s *goquery.Selection) {
		repoName := strings.Trim(s.Text(), " \n")
		fmt.Printf("%d - %s\n", i+1, repoName)
	})
	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "gorending"
	app.Usage = "Show Github trending in Terminal!"
	app.Version = "1.0.0"
	app.Compiled = time.Now()
	app.Copyright = "(c) 2017 Myungseo Kang"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Myungseo Kang",
			Email: "l3opold7@gmail.com",
		},
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "lang, l",
			Value: "",
			Usage: "language that you want to see, default all language",
		},
		cli.IntFlag{
			Name:  "count, c",
			Value: 10,
			Usage: "count that you want to see, defalut 10",
		},
	}

	app.Action = func(c *cli.Context) error {
		lang := c.String("lang")
		count := c.Int("count")

		err := CrawlTrending(lang, count)
		if err != nil {
			return err
		}

		return nil
	}

	app.Run(os.Args)
}
<commit_msg>Add comment for CrawlTrending function<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/urfave/cli"
)

// CrawlTrending is function for printing parsed trending
func CrawlTrending(lang string, count int) error {
	doc, err := goquery.NewDocument("https://github.com/trending/" + lang)
	if err != nil {
		log.Fatal(err)
		return err
	}

	repoList := doc.Find(".d-inline-block > h3 > a").Slice(0, count)

	repoList.Each(func(i int, s *goquery.Selection) {
		repoName := strings.Trim(s.Text(), " \n")
		fmt.Printf("%d - %s\n", i+1, repoName)
	})
	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "gorending"
	app.Usage = "Show Github trending in Terminal!"
	app.Version = "1.0.0"
	app.Compiled = time.Now()
	app.Copyright = "(c) 2017 Myungseo Kang"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Myungseo Kang",
			Email: "l3opold7@gmail.com",
		},
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "lang, l",
			Value: "",
			Usage: "language that you want to see, default all language",
		},
		cli.IntFlag{
			Name:  "count, c",
			Value: 10,
			Usage: "count that you want to see, defalut 10",
		},
	}

	app.Action = func(c *cli.Context) error {
		lang := c.String("lang")
		count := c.Int("count")

		err := CrawlTrending(lang, count)
		if err != nil {
			return err
		}

		return nil
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	goopt "github.com/droundy/goopt"
	"os"
	"path"
	"fmt"
	"regexp"
	"bytes"
	"./highlight"
)

var Pattern *regexp.Regexp
var byteNewLine []byte = []byte("\n")

func main() {
	goopt.Description = func() string {
		return "Go search and replace in files"
	}
	goopt.Version = "0.1"
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	var err os.Error
	Pattern, err = regexp.Compile(goopt.Args[0])
	errhandle(err, "can't compile regexp %s", goopt.Args[0])

	searchFiles()
}

func errhandle(err os.Error, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err,
		fmt.Sprintf(moreinfo, a...))
	os.Exit(1)
}

type Visitor struct{}

func (v *Visitor) VisitDir(p string, fi *os.FileInfo) bool {
	if fi.Name == ".hg" {
		return false
	}
	return true
}

func (v *Visitor) VisitFile(p string, fi *os.FileInfo) {
	if fi.Size >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", p, fi.Size)
		return
	}

	if fi.Size == 0 {
		return
	}

	f, err := os.Open(p, os.O_RDONLY, 0666)
	errhandle(err, "can't open file %s", p)

	content := make([]byte, fi.Size)
	n, err := f.Read(content)
	errhandle(err, "can't read file %s", p)
	if int64(n) != fi.Size {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size))
	}

	searchFile(p, content)

	f.Close()
}

func searchFile(p string, content []byte) {
	linenum := 1
	last := 0
	hadOutput := false
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, bounds := range Pattern.FindAllIndex(content, -1) {
		if binary {
			fmt.Printf("Binary file %s matches\n", p)
			hadOutput = true
			break
		}

		if !hadOutput {
			highlight.Printf("green", "%s\n", p)
			hadOutput = true
		}

		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])

		if content[begin] == '\r' {
			begin += 1
		}

		highlight.Printf("bold yellow", "%d:", linenum)
		highlight.Reprintf("on_yellow", Pattern, "%s\n", content[begin:end])
	}

	if hadOutput {
		fmt.Println("")
	}
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			// skip newline itself
			begin = i + 1
			break
		}
	}

	for i := finish; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

func searchFiles() {
	v := &Visitor{}

	errors := make(chan os.Error, 64)

	path.Walk(".", v, errors)

	select {
	case err := <-errors:
		errhandle(err, "some error")
	default:
	}
}
<commit_msg>file exclusion by mask<commit_after>package main

import (
	"os"
	"path"
	"fmt"
	"regexp"
	"bytes"
	goopt "github.com/droundy/goopt"
	"./highlight"
)

var byteNewLine []byte = []byte("\n")
// Used to prevent appear of sparse newline at the end of output
var prependNewLine = false

type StringList []string
var IgnoreDirs = StringList{"autom4te.cache", "blib", "_build", ".bzr", ".cdv",
	"cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib",
    ".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn"}

type RegexpList []*regexp.Regexp
var IgnoreFiles = regexpList([]string{`~$`, `#.+#$`, `[._].*\.swp$`, `core\.[0-9]+$`,
	`\.pyc$`, `\.o$`, `\.6$`})

var onlyName = goopt.Flag([]string{"-n", "--filename"}, []string{},
	"print only filenames", "")
var ignoreFiles = goopt.Strings([]string{"-x", "--exclude"}, "RE",
	"exclude files that match the regexp from search")

func main() {
	goopt.Description = func() string {
		return "Go search and replace in files"
	}
	goopt.Version = "0.1"
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	IgnoreFiles = append(IgnoreFiles, regexpList(*ignoreFiles)...)

	pattern, err := regexp.Compile(goopt.Args[0])
	errhandle(err, "can't compile regexp %s", goopt.Args[0])

	searchFiles(pattern)
}

func errhandle(err os.Error, moreinfo string, a ...interface{}) {
	if err == nil {
		return
	}
	fmt.Fprintf(os.Stderr, "ERR %s\n%s\n", err,
		fmt.Sprintf(moreinfo, a...))
	os.Exit(1)
}

func regexpList(sa []string) RegexpList {
	ra := make(RegexpList, len(sa))
	for i, s := range sa {
		ra[i] = regexp.MustCompile(s)
	}
	return ra
}

func searchFiles(pattern *regexp.Regexp) {
	v := &GRVisitor{pattern}

	errors := make(chan os.Error, 64)

	path.Walk(".", v, errors)

	select {
	case err := <-errors:
		errhandle(err, "some error")
	default:
	}
}

type GRVisitor struct{
	pattern *regexp.Regexp
}

func (v *GRVisitor) VisitDir(fn string, fi *os.FileInfo) bool {
	if IgnoreDirs.Contains(fi.Name) {
		return false
	}
	return true
}

func (v *GRVisitor) VisitFile(fn string, fi *os.FileInfo) {
	if IgnoreFiles.Match(fn) {
		return
	}

	if fi.Size >= 1024*1024*10 {
		fmt.Fprintf(os.Stderr, "Skipping %s, too big: %d\n", fn, fi.Size)
		return
	}

	if fi.Size == 0 {
		return
	}

	f, err := os.Open(fn, os.O_RDONLY, 0666)
	errhandle(err, "can't open file %s", fn)

	content := make([]byte, fi.Size)
	n, err := f.Read(content)
	errhandle(err, "can't read file %s", fn)
	if int64(n) != fi.Size {
		panic(fmt.Sprintf("Not whole file was read, only %d from %d",
			n, fi.Size))
	}

	v.SearchFile(fn, content)

	f.Close()
}

func (v *GRVisitor) SearchFile(p string, content []byte) {
	linenum := 1
	last := 0
	hadOutput := false
	binary := false

	if bytes.IndexByte(content, 0) != -1 {
		binary = true
	}

	for _, bounds := range v.pattern.FindAllIndex(content, -1) {
		if prependNewLine {
			fmt.Println("")
			prependNewLine = false
		}

		if !hadOutput {
			hadOutput = true
			if binary && !*onlyName{
				fmt.Printf("Binary file %s matches\n", p)
				break
			} else {
				highlight.Printf("green", "%s\n", p)
			}
		}

		if *onlyName {
			return
		}

		linenum += bytes.Count(content[last:bounds[0]], byteNewLine)
		last = bounds[0]
		begin, end := beginend(content, bounds[0], bounds[1])

		if content[begin] == '\r' {
			begin += 1
		}

		highlight.Printf("bold yellow", "%d:", linenum)
		highlight.Reprintf("on_yellow", v.pattern, "%s\n", content[begin:end])
	}

	if hadOutput {
		prependNewLine = true
	}
}

// Given a []byte, start and finish of some inner slice, will find nearest
// newlines on both ends of this slice
func beginend(s []byte, start int, finish int) (begin int, end int) {
	begin = 0
	end = len(s)

	for i := start; i >= 0; i-- {
		if s[i] == byteNewLine[0] {
			// skip newline itself
			begin = i + 1
			break
		}
	}

	for i := finish; i < len(s); i++ {
		if s[i] == byteNewLine[0] {
			end = i
			break
		}
	}

	return
}

func (sl StringList) Contains(s string) bool {
	for _, x := range sl {
		if x == s {
			return true
		}
	}
	return false
}

func (rl RegexpList) Match(s string) bool {
	for _, x := range rl {
		if x.Match([]byte(s)) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gosh

import "testing"

func TestGosh(t *testing.T) {
	EchoTime = true
	EchoIn = true
	EchoOut = true
	err := Run("date")
	if err != nil {
		t.Error("gosh run error.")
	}
}
<commit_msg>update test case.<commit_after>package gosh

import "testing"

func TestGosh(t *testing.T) {
	err := Run("date")
	if err != nil {
		t.Error("gosh run error.")
	}
}
<|endoftext|>


<commit_before>package game

import (
	"errors"
	"strconv"
	"strings"

	"github.com/ghthor/engine/net/protocol"
	"github.com/ghthor/engine/rpg2d"
	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

type actorCmd struct {
	timeIssued stime.Time
	cmd        string
	params     string
}

type moveRequest struct {
	stime.Time
	coord.Direction
}

type actorCmdRequest struct {
	moveRequest
}

type actorConn struct {
	// Comm interface to muxer used by WriteInput() method
	submitCmd chan<- actorCmd

	// Comm interface to muxer used by getEntity() method
	readCmdReq <-chan actorCmdRequest

	// Comm interface to muxer used by SendState() method
	sendState chan<- *rpg2d.WorldState

	// Comm interface to muxer used by stopIO() method
	stop chan<- chan<- struct{}

	// External connection used to publish the world state
	protocol.Conn

	lastState rpg2d.WorldState
}

func newActorConn(conn protocol.Conn) actorConn {
	return actorConn{Conn: conn}
}

// Object stored in the quad tree
type actorEntity struct {
	id int64

	name string

	cell   coord.Cell
	facing coord.Direction

	pathAction *coord.PathAction
}

type actorEntityState struct {
	EntityId int64 `json:"id"`

	Name string `json:"name"`

	Facing string     `json:"facing"`
	Cell   coord.Cell `json:"cell"`
	bounds coord.Bounds

	PathAction *coord.PathAction `json:"pathAction"`
}

type actor struct {
	actorEntity
	actorConn
}

func (a actor) Entity() entity.Entity  { return a.actorEntity }
func (e actorEntity) Id() int64        { return e.id }
func (e actorEntity) Cell() coord.Cell { return e.cell }
func (e actorEntity) Bounds() coord.Bounds {
	bounds := coord.Bounds{
		e.cell,
		e.cell,
	}

	if e.pathAction != nil {
		bounds = coord.JoinBounds(bounds, e.pathAction.Bounds())
	}

	return bounds
}

func (e actorEntity) ToState() entity.State {
	return actorEntityState{
		EntityId: e.id,

		Cell:   e.cell,
		Facing: e.facing.String(),

		bounds: e.Bounds(),

		PathAction: e.pathAction,
	}
}

func (e actorEntityState) Id() int64            { return e.EntityId }
func (e actorEntityState) Bounds() coord.Bounds { return e.bounds }
func (e actorEntityState) IsDifferentFrom(other entity.State) bool {
	o := other.(actorEntityState)

	switch {
	case e.Facing != o.Facing:
		return true

	case e.PathAction != nil && o.PathAction != nil:
		if *e.PathAction != *o.PathAction {
			return true
		}

	case e.PathAction == nil && o.PathAction != nil:
		return true
	case e.PathAction != nil && o.PathAction == nil:
		return true
	}

	return false
}

func (a *actorConn) startIO() {
	// Setup communication channels
	cmdCh := make(chan actorCmd)
	cmdReqCh := make(chan actorCmdRequest)
	outputCh := make(chan *rpg2d.WorldState)
	stopCh := make(chan chan<- struct{})

	// Set the channels accessible to the outside world
	a.submitCmd = cmdCh
	a.readCmdReq = cmdReqCh
	a.sendState = outputCh
	a.stop = stopCh

	// Establish the channel endpoints used inside the go routine
	var newCmd <-chan actorCmd
	var sendCmdReq chan<- actorCmdRequest
	var newState <-chan *rpg2d.WorldState
	var stopReq <-chan chan<- struct{}

	newCmd = cmdCh
	sendCmdReq = cmdReqCh
	newState = outputCh
	stopReq = stopCh

	go func() {
		var hasStopped chan<- struct{}

		// Buffer of 1 used to store the most recently
		// received actor cmd from the network.
		var cmdReq actorCmdRequest

		updateCmdReqWith := func(c actorCmd) {
			switch c.cmd {
			case "move":
				// TODO This is a shit place to be having an error to deal with
				// TODO It needs to be dealt with at the packet handler level
				d, _ := coord.NewDirectionWithString(c.params)

				cmdReq.moveRequest = moveRequest{
					Time:      stime.Time(c.timeIssued),
					Direction: d,
				}
			}
		}

	unlocked:
		// # This select prioritizes the following events.
		// ## 2 potential events to respond to
		// 1. ReadCmdRequest() method requests the actor command request
		// 2. stopIO() method has been called
		select {
		case sendCmdReq <- cmdReq:
			// Transition: unlocked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: unlocked -> exit
			goto exit
		default:
		}

		// ## 3 potential events to respond to
		// 1. SubmitInput() method has been called with a new command
		// 2. ReadCmdRequest() method requests the actor command request
		// 3. stopIO() method has been called
		select {
		case c := <-newCmd:
			updateCmdReqWith(c)

			// Transition: unlocked -> unlocked
			goto unlocked

		case sendCmdReq <- cmdReq:
			// Transition: unlocked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: unlocked -> exit
			goto exit
		}

		panic("unclosed case in unlocked state select")

	locked:
		// Accepting and processing input commands is now on hold

		// ## 3 potential events to respond to
		// 1. WriteState() method has been called with a new world state
		// 2. ReadCmdRequest() method requests the actor command request.. again!
		// 3. stopIO() method has been called
		select {
		case state := <-newState:
			if state != nil {
				a.SendJson("update", state)
			}

			// Reset the cmdReq object
			cmdReq = actorCmdRequest{}

			// Transition: locked -> unlocked
			goto unlocked

		case sendCmdReq <- cmdReq:
			// Transition: locked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: locked -> exit
			goto exit
		}

		panic("unclosed case in locked state select")
	exit:
		hasStopped <- struct{}{}
	}()
}

func (c actorConn) SubmitCmd(cmd, params string) error {
	parts := strings.Split(cmd, "=")

	if len(parts) != 2 {
		return errors.New("invalid command")
	}

	timeIssued, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return err
	}

	c.submitCmd <- actorCmd{
		timeIssued: stime.Time(timeIssued),
		cmd:        parts[0],
		params:     params,
	}

	return nil
}

// Culls the world state to the actor's viewport
func (a *actor) WriteState(state rpg2d.WorldState) {
	c := a.Cell()

	state = state.Cull(coord.Bounds{
		c.Add(-26, 26),
		c.Add(26, -26),
	})

	a.actorConn.WriteState(state)
}

// Diffs the world state so only the changes are sent
func (a *actorConn) WriteState(state rpg2d.WorldState) {
	diff := a.lastState.Diff(state)
	a.lastState = state

	// Will need this when I start comparing for terrain type changes
	// a.lastState.Prepare()

	if len(diff.Entities) > 0 || len(diff.Removed) > 0 || diff.TerrainMap != nil {
		diff.Prepare()
		a.sendState <- &diff
	} else {
		a.sendState <- nil
	}
}

func (a actorConn) stopIO() {
	hasStopped := make(chan struct{})

	a.stop <- hasStopped
	<-hasStopped
}
<commit_msg>Implement a method used by the input phase to retrieve the command request<commit_after>package game

import (
	"errors"
	"strconv"
	"strings"

	"github.com/ghthor/engine/net/protocol"
	"github.com/ghthor/engine/rpg2d"
	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

type actorCmd struct {
	timeIssued stime.Time
	cmd        string
	params     string
}

type moveRequest struct {
	stime.Time
	coord.Direction
}

type actorCmdRequest struct {
	moveRequest
}

type actorConn struct {
	// Comm interface to muxer used by WriteInput() method
	submitCmd chan<- actorCmd

	// Comm interface to muxer used by getEntity() method
	readCmdReq <-chan actorCmdRequest

	// Comm interface to muxer used by SendState() method
	sendState chan<- *rpg2d.WorldState

	// Comm interface to muxer used by stopIO() method
	stop chan<- chan<- struct{}

	// External connection used to publish the world state
	protocol.Conn

	lastState rpg2d.WorldState
}

func newActorConn(conn protocol.Conn) actorConn {
	return actorConn{Conn: conn}
}

// Object stored in the quad tree
type actorEntity struct {
	id int64

	name string

	cell   coord.Cell
	facing coord.Direction

	pathAction *coord.PathAction
}

type actorEntityState struct {
	EntityId int64 `json:"id"`

	Name string `json:"name"`

	Facing string     `json:"facing"`
	Cell   coord.Cell `json:"cell"`
	bounds coord.Bounds

	PathAction *coord.PathAction `json:"pathAction"`
}

type actor struct {
	actorEntity
	actorConn
}

func (a actor) Entity() entity.Entity  { return a.actorEntity }
func (e actorEntity) Id() int64        { return e.id }
func (e actorEntity) Cell() coord.Cell { return e.cell }
func (e actorEntity) Bounds() coord.Bounds {
	bounds := coord.Bounds{
		e.cell,
		e.cell,
	}

	if e.pathAction != nil {
		bounds = coord.JoinBounds(bounds, e.pathAction.Bounds())
	}

	return bounds
}

func (e actorEntity) ToState() entity.State {
	return actorEntityState{
		EntityId: e.id,

		Cell:   e.cell,
		Facing: e.facing.String(),

		bounds: e.Bounds(),

		PathAction: e.pathAction,
	}
}

func (e actorEntityState) Id() int64            { return e.EntityId }
func (e actorEntityState) Bounds() coord.Bounds { return e.bounds }
func (e actorEntityState) IsDifferentFrom(other entity.State) bool {
	o := other.(actorEntityState)

	switch {
	case e.Facing != o.Facing:
		return true

	case e.PathAction != nil && o.PathAction != nil:
		if *e.PathAction != *o.PathAction {
			return true
		}

	case e.PathAction == nil && o.PathAction != nil:
		return true
	case e.PathAction != nil && o.PathAction == nil:
		return true
	}

	return false
}

func (a *actorConn) startIO() {
	// Setup communication channels
	cmdCh := make(chan actorCmd)
	cmdReqCh := make(chan actorCmdRequest)
	outputCh := make(chan *rpg2d.WorldState)
	stopCh := make(chan chan<- struct{})

	// Set the channels accessible to the outside world
	a.submitCmd = cmdCh
	a.readCmdReq = cmdReqCh
	a.sendState = outputCh
	a.stop = stopCh

	// Establish the channel endpoints used inside the go routine
	var newCmd <-chan actorCmd
	var sendCmdReq chan<- actorCmdRequest
	var newState <-chan *rpg2d.WorldState
	var stopReq <-chan chan<- struct{}

	newCmd = cmdCh
	sendCmdReq = cmdReqCh
	newState = outputCh
	stopReq = stopCh

	go func() {
		var hasStopped chan<- struct{}

		// Buffer of 1 used to store the most recently
		// received actor cmd from the network.
		var cmdReq actorCmdRequest

		updateCmdReqWith := func(c actorCmd) {
			switch c.cmd {
			case "move":
				// TODO This is a shit place to be having an error to deal with
				// TODO It needs to be dealt with at the packet handler level
				d, _ := coord.NewDirectionWithString(c.params)

				cmdReq.moveRequest = moveRequest{
					Time:      stime.Time(c.timeIssued),
					Direction: d,
				}
			}
		}

	unlocked:
		// # This select prioritizes the following events.
		// ## 2 potential events to respond to
		// 1. ReadCmdRequest() method requests the actor command request
		// 2. stopIO() method has been called
		select {
		case sendCmdReq <- cmdReq:
			// Transition: unlocked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: unlocked -> exit
			goto exit
		default:
		}

		// ## 3 potential events to respond to
		// 1. SubmitInput() method has been called with a new command
		// 2. ReadCmdRequest() method requests the actor command request
		// 3. stopIO() method has been called
		select {
		case c := <-newCmd:
			updateCmdReqWith(c)

			// Transition: unlocked -> unlocked
			goto unlocked

		case sendCmdReq <- cmdReq:
			// Transition: unlocked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: unlocked -> exit
			goto exit
		}

		panic("unclosed case in unlocked state select")

	locked:
		// Accepting and processing input commands is now on hold

		// ## 3 potential events to respond to
		// 1. WriteState() method has been called with a new world state
		// 2. ReadCmdRequest() method requests the actor command request.. again!
		// 3. stopIO() method has been called
		select {
		case state := <-newState:
			if state != nil {
				a.SendJson("update", state)
			}

			// Reset the cmdReq object
			cmdReq = actorCmdRequest{}

			// Transition: locked -> unlocked
			goto unlocked

		case sendCmdReq <- cmdReq:
			// Transition: locked -> locked
			goto locked

		case hasStopped = <-stopReq:
			// Transition: locked -> exit
			goto exit
		}

		panic("unclosed case in locked state select")
	exit:
		hasStopped <- struct{}{}
	}()
}

func (c actorConn) SubmitCmd(cmd, params string) error {
	parts := strings.Split(cmd, "=")

	if len(parts) != 2 {
		return errors.New("invalid command")
	}

	timeIssued, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return err
	}

	c.submitCmd <- actorCmd{
		timeIssued: stime.Time(timeIssued),
		cmd:        parts[0],
		params:     params,
	}

	return nil
}

func (c actorConn) ReadCmdRequest() actorCmdRequest {
	return <-c.readCmdReq
}

// Culls the world state to the actor's viewport
func (a *actor) WriteState(state rpg2d.WorldState) {
	c := a.Cell()

	state = state.Cull(coord.Bounds{
		c.Add(-26, 26),
		c.Add(26, -26),
	})

	a.actorConn.WriteState(state)
}

// Diffs the world state so only the changes are sent
func (a *actorConn) WriteState(state rpg2d.WorldState) {
	diff := a.lastState.Diff(state)
	a.lastState = state

	// Will need this when I start comparing for terrain type changes
	// a.lastState.Prepare()

	if len(diff.Entities) > 0 || len(diff.Removed) > 0 || diff.TerrainMap != nil {
		diff.Prepare()
		a.sendState <- &diff
	} else {
		a.sendState <- nil
	}
}

func (a actorConn) stopIO() {
	hasStopped := make(chan struct{})

	a.stop <- hasStopped
	<-hasStopped
}
<|endoftext|>


<commit_before>package game

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

type updatePhase struct {
	index actorIndex
}

type inputPhase struct {
	index  actorIndex
	nextId func() entity.Id
}

func (phase updatePhase) Update(e entity.Entity, now stime.Time) entity.Entity {
	switch e := e.(type) {
	case actorEntity:
		actor := phase.index[e.ActorId()]

		// Remove any movement actions that have completed
		if actor.pathAction != nil && actor.pathAction.End() <= now {
			actor.lastMoveAction = actor.pathAction
			actor.cell = actor.pathAction.Dest
			actor.pathAction = nil
		}

		return actor.Entity()

	case assailEntity:
		// Destroy all assail entities
		return nil

	case sayEntity:
		// TODO parametize server fps
		if e.saidAt+(sayEntityDuration*40) <= now {
			// Destroy all say entities
			return nil
		}

		return e

	default:
		panic(fmt.Sprint("unexpected entity type:", e))
	}
}

func (phase inputPhase) ApplyInputsTo(e entity.Entity, now stime.Time) []entity.Entity {
	switch e := e.(type) {
	case actorEntity:
		var entities []entity.Entity
		actor := phase.index[e.ActorId()]

		phase.processMoveCmd(actor, now)
		entities = append(entities,
			phase.processUseCmd(actor, now)...,
		)

		entities = append(entities,
			phase.processChatCmd(actor, now)...,
		)

		return append(entities, actor.Entity())

	case sayEntity:
		return []entity.Entity{e}

	default:
		panic(fmt.Sprint("unexpected entity type:", e))
	}
}

type moveRequestType int

const (
	MR_ERROR moveRequestType = iota
	MR_MOVE
	MR_MOVE_CANCEL
)

type moveRequest struct {
	moveRequestType
	stime.Time
	coord.Direction
}

type moveCmd struct {
	stime.Time
	coord.Direction
}

type useRequestType int

const (
	UR_ERROR useRequestType = iota
	UR_USE
	UR_USE_CANCEL
)

type useRequest struct {
	useRequestType
	stime.Time
	skill string
}

type useCmd struct {
	stime.Time
	skill string
}

type chatType int

const (
	CR_ERROR chatType = iota
	CR_SAY
)

type chatRequest struct {
	chatType
	stime.Time
	msg string
}

type chatCmd struct {
	chatType
	stime.Time
	msg string
}

func newMoveRequest(t moveRequestType, timeIssued stime.Time, params string) (moveRequest, error) {
	d, err := coord.NewDirectionWithString(params)
	if err != nil {
		return moveRequest{}, err
	}

	return moveRequest{
		t,
		timeIssued,
		d,
	}, nil
}

func newUseRequest(t useRequestType, timeIssued stime.Time, params string) (useRequest, error) {
	switch params {
	case "assail":
		return useRequest{t, timeIssued, params}, nil
	default:
		return useRequest{}, fmt.Errorf("unknown skill: %s", params)
	}
}

func newChatRequest(t chatType, timeIssued stime.Time, params string) (chatRequest, error) {
	if len(params) > 120 {
		return chatRequest{}, errors.New("chat message exceeded 120 char limit")
	}

	return chatRequest{
		chatType: t,
		Time:     timeIssued,
		msg:      params,
	}, nil
}

// If the cmd and params are a valid combination
// a request will be made and passed into the
// IO muxer. SubmitCmd() will return an error
// if the submitted cmd and params are invalid.
func (c actorConn) SubmitCmd(cmd, params string) error {
	parts := strings.Split(cmd, "=")

	if len(parts) != 2 {
		return errors.New("invalid command syntax")
	}

	timeIssued, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return err
	}

	switch parts[0] {
	case "move":
		r, err := newMoveRequest(MR_MOVE, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitMoveRequest <- r

	case "moveCancel":
		r, err := newMoveRequest(MR_MOVE_CANCEL, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitMoveRequest <- r

	case "use":
		r, err := newUseRequest(UR_USE, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitUseRequest <- r

	case "useCancel":
		r, err := newUseRequest(UR_USE_CANCEL, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitUseRequest <- r

	case "say":
		r, err := newChatRequest(CR_SAY, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitChatRequest <- r

	default:
		return fmt.Errorf("unknown command: %s", parts[0])
	}

	return nil
}

func (c actorConn) ReadMoveCmd() *moveCmd {
	return <-c.readMoveCmd
}

func (a *actor) applyPathAction(pa *coord.PathAction) {
	prevPathAction := a.pathAction
	prevFacing := a.facing

	a.undoLastMoveAction = func() {
		a.pathAction = prevPathAction
		a.facing = prevFacing
		a.undoLastMoveAction = nil
	}

	a.pathAction = pa
	a.facing = pa.Direction()
}

func (a *actor) applyTurnAction(ta coord.TurnAction) {
	prevAction := a.lastMoveAction
	prevFacing := a.facing

	a.undoLastMoveAction = func() {
		a.lastMoveAction = prevAction
		a.facing = prevFacing
		a.undoLastMoveAction = nil
	}

	a.lastMoveAction = ta
	a.facing = ta.To
}

func (a *actor) revertMoveAction() {
	if a.undoLastMoveAction != nil {
		a.undoLastMoveAction()
	}
}

func (phase inputPhase) processMoveCmd(a *actor, now stime.Time) {
	cmd := a.ReadMoveCmd()
	if cmd == nil {
		// The client has canceled all move requests
		return
	}

	// Actor is already moving so the moveRequest won't be
	// consumed until the path action has been completed
	if a.pathAction != nil {
		return
	}

	// Actor may be able to move
	pathAction := &coord.PathAction{
		Span: stime.NewSpan(now, now+stime.Time(a.speed)),
		Orig: a.Cell(),
		Dest: a.Cell().Neighbor(cmd.Direction),
	}

	if pathAction.CanHappenAfter(a.lastMoveAction) {
		a.applyPathAction(pathAction)
		return
	}

	// Actor must change facing
	if a.facing != cmd.Direction {
		turnAction := coord.TurnAction{
			From: a.facing,
			To:   cmd.Direction,
			Time: now,
		}

		if turnAction.CanHappenAfter(a.lastMoveAction) {
			a.applyTurnAction(turnAction)
		}
	}
}

// In frames
const assailCooldown = 40

type assailEntity struct {
	id entity.Id

	spawnedBy entity.Id
	spawnedAt stime.Time

	cell coord.Cell

	damage int
}

type assailEntityState struct {
	Type string `json:"type"`

	EntityId entity.Id `json:"id"`

	SpawnedBy entity.Id  `json:"spawnedBy"`
	SpawnedAt stime.Time `json:"spawnedAt"`

	Cell coord.Cell `json:"cell"`
}

func (e assailEntity) Id() entity.Id    { return e.id }
func (e assailEntity) Cell() coord.Cell { return e.cell }
func (e assailEntity) Bounds() coord.Bounds {
	return coord.Bounds{e.cell, e.cell}
}

func (e assailEntity) ToState() entity.State {
	return assailEntityState{
		Type: "assail",

		EntityId: e.id,

		SpawnedBy: e.spawnedBy,
		SpawnedAt: e.spawnedAt,

		Cell: e.cell,
	}
}

func (e assailEntityState) Id() entity.Id { return e.EntityId }
func (e assailEntityState) Bounds() coord.Bounds {
	return coord.Bounds{e.Cell, e.Cell}
}

func (e assailEntityState) IsDifferentFrom(entity.State) bool {
	return true
}

func (c actorConn) ReadUseCmd() *useCmd {
	return <-c.readUseCmd
}

func (phase inputPhase) processUseCmd(a *actor, now stime.Time) []entity.Entity {
	cmd := a.ReadUseCmd()
	if cmd == nil {
		return nil
	}

	// TODO Only allow when stationary
	// TODO Trigger a cooldown
	switch cmd.skill {
	case "assail":
		// Implement a cooldown
		if a.lastAssail.spawnedAt+assailCooldown > now {
			return nil
		}

		e := assailEntity{
			id: phase.nextId(),

			spawnedBy: a.actorEntity.Id(),
			spawnedAt: now,

			cell: a.Cell().Neighbor(a.facing),

			damage: 25,
		}

		a.lastAssail = e

		return []entity.Entity{e}
	}
	return nil
}

// In seconds
const sayEntityDuration = 3

type sayEntity struct {
	id entity.Id

	saidBy entity.Id
	saidAt stime.Time

	cell coord.Cell

	msg string
}

type sayEntityState struct {
	Type string `json:"type"`

	EntityId entity.Id `json:"id"`

	SaidBy entity.Id  `json:"saidBy"`
	SaidAt stime.Time `json:"saidAt"`

	Cell coord.Cell `json:"cell"`

	Msg string `json:"msg"`
}

func (e sayEntity) Id() entity.Id    { return e.id }
func (e sayEntity) Cell() coord.Cell { return e.cell }
func (e sayEntity) Bounds() coord.Bounds {
	return coord.Bounds{e.cell, e.cell}
}

func (e sayEntity) ToState() entity.State {
	return sayEntityState{
		Type: "say",

		EntityId: e.id,

		SaidBy: e.saidBy,
		SaidAt: e.saidAt,

		Cell: e.cell,

		Msg: e.msg,
	}
}

func (e sayEntityState) Id() entity.Id { return e.EntityId }
func (e sayEntityState) Bounds() coord.Bounds {
	return coord.Bounds{e.Cell, e.Cell}
}
func (e sayEntityState) IsDifferentFrom(other entity.State) bool {
	return false
}

func (a *actor) ReadChatCmd() *chatCmd {
	return <-a.readChatCmd
}

func (phase inputPhase) processChatCmd(a *actor, now stime.Time) []entity.Entity {
	cmd := a.ReadChatCmd()
	if cmd == nil {
		return nil
	}

	switch cmd.chatType {
	case CR_SAY:
		return []entity.Entity{sayEntity{
			id: phase.nextId(),

			saidBy: a.actorEntity.Id(),
			saidAt: now,

			cell: a.Cell(),

			msg: cmd.msg,
		}}
	}

	return nil
}
<commit_msg>[game] publicize Assail and Say entity states<commit_after>package game

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/sim/stime"
)

type updatePhase struct {
	index actorIndex
}

type inputPhase struct {
	index  actorIndex
	nextId func() entity.Id
}

func (phase updatePhase) Update(e entity.Entity, now stime.Time) entity.Entity {
	switch e := e.(type) {
	case actorEntity:
		actor := phase.index[e.ActorId()]

		// Remove any movement actions that have completed
		if actor.pathAction != nil && actor.pathAction.End() <= now {
			actor.lastMoveAction = actor.pathAction
			actor.cell = actor.pathAction.Dest
			actor.pathAction = nil
		}

		return actor.Entity()

	case assailEntity:
		// Destroy all assail entities
		return nil

	case sayEntity:
		// TODO parametize server fps
		if e.saidAt+(sayEntityDuration*40) <= now {
			// Destroy all say entities
			return nil
		}

		return e

	default:
		panic(fmt.Sprint("unexpected entity type:", e))
	}
}

func (phase inputPhase) ApplyInputsTo(e entity.Entity, now stime.Time) []entity.Entity {
	switch e := e.(type) {
	case actorEntity:
		var entities []entity.Entity
		actor := phase.index[e.ActorId()]

		phase.processMoveCmd(actor, now)
		entities = append(entities,
			phase.processUseCmd(actor, now)...,
		)

		entities = append(entities,
			phase.processChatCmd(actor, now)...,
		)

		return append(entities, actor.Entity())

	case sayEntity:
		return []entity.Entity{e}

	default:
		panic(fmt.Sprint("unexpected entity type:", e))
	}
}

type moveRequestType int

const (
	MR_ERROR moveRequestType = iota
	MR_MOVE
	MR_MOVE_CANCEL
)

type moveRequest struct {
	moveRequestType
	stime.Time
	coord.Direction
}

type moveCmd struct {
	stime.Time
	coord.Direction
}

type useRequestType int

const (
	UR_ERROR useRequestType = iota
	UR_USE
	UR_USE_CANCEL
)

type useRequest struct {
	useRequestType
	stime.Time
	skill string
}

type useCmd struct {
	stime.Time
	skill string
}

type chatType int

const (
	CR_ERROR chatType = iota
	CR_SAY
)

type chatRequest struct {
	chatType
	stime.Time
	msg string
}

type chatCmd struct {
	chatType
	stime.Time
	msg string
}

func newMoveRequest(t moveRequestType, timeIssued stime.Time, params string) (moveRequest, error) {
	d, err := coord.NewDirectionWithString(params)
	if err != nil {
		return moveRequest{}, err
	}

	return moveRequest{
		t,
		timeIssued,
		d,
	}, nil
}

func newUseRequest(t useRequestType, timeIssued stime.Time, params string) (useRequest, error) {
	switch params {
	case "assail":
		return useRequest{t, timeIssued, params}, nil
	default:
		return useRequest{}, fmt.Errorf("unknown skill: %s", params)
	}
}

func newChatRequest(t chatType, timeIssued stime.Time, params string) (chatRequest, error) {
	if len(params) > 120 {
		return chatRequest{}, errors.New("chat message exceeded 120 char limit")
	}

	return chatRequest{
		chatType: t,
		Time:     timeIssued,
		msg:      params,
	}, nil
}

// If the cmd and params are a valid combination
// a request will be made and passed into the
// IO muxer. SubmitCmd() will return an error
// if the submitted cmd and params are invalid.
func (c actorConn) SubmitCmd(cmd, params string) error {
	parts := strings.Split(cmd, "=")

	if len(parts) != 2 {
		return errors.New("invalid command syntax")
	}

	timeIssued, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return err
	}

	switch parts[0] {
	case "move":
		r, err := newMoveRequest(MR_MOVE, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitMoveRequest <- r

	case "moveCancel":
		r, err := newMoveRequest(MR_MOVE_CANCEL, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitMoveRequest <- r

	case "use":
		r, err := newUseRequest(UR_USE, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitUseRequest <- r

	case "useCancel":
		r, err := newUseRequest(UR_USE_CANCEL, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitUseRequest <- r

	case "say":
		r, err := newChatRequest(CR_SAY, stime.Time(timeIssued), params)
		if err != nil {
			return err
		}

		c.submitChatRequest <- r

	default:
		return fmt.Errorf("unknown command: %s", parts[0])
	}

	return nil
}

func (c actorConn) ReadMoveCmd() *moveCmd {
	return <-c.readMoveCmd
}

func (a *actor) applyPathAction(pa *coord.PathAction) {
	prevPathAction := a.pathAction
	prevFacing := a.facing

	a.undoLastMoveAction = func() {
		a.pathAction = prevPathAction
		a.facing = prevFacing
		a.undoLastMoveAction = nil
	}

	a.pathAction = pa
	a.facing = pa.Direction()
}

func (a *actor) applyTurnAction(ta coord.TurnAction) {
	prevAction := a.lastMoveAction
	prevFacing := a.facing

	a.undoLastMoveAction = func() {
		a.lastMoveAction = prevAction
		a.facing = prevFacing
		a.undoLastMoveAction = nil
	}

	a.lastMoveAction = ta
	a.facing = ta.To
}

func (a *actor) revertMoveAction() {
	if a.undoLastMoveAction != nil {
		a.undoLastMoveAction()
	}
}

func (phase inputPhase) processMoveCmd(a *actor, now stime.Time) {
	cmd := a.ReadMoveCmd()
	if cmd == nil {
		// The client has canceled all move requests
		return
	}

	// Actor is already moving so the moveRequest won't be
	// consumed until the path action has been completed
	if a.pathAction != nil {
		return
	}

	// Actor may be able to move
	pathAction := &coord.PathAction{
		Span: stime.NewSpan(now, now+stime.Time(a.speed)),
		Orig: a.Cell(),
		Dest: a.Cell().Neighbor(cmd.Direction),
	}

	if pathAction.CanHappenAfter(a.lastMoveAction) {
		a.applyPathAction(pathAction)
		return
	}

	// Actor must change facing
	if a.facing != cmd.Direction {
		turnAction := coord.TurnAction{
			From: a.facing,
			To:   cmd.Direction,
			Time: now,
		}

		if turnAction.CanHappenAfter(a.lastMoveAction) {
			a.applyTurnAction(turnAction)
		}
	}
}

// In frames
const assailCooldown = 40

type assailEntity struct {
	id entity.Id

	spawnedBy entity.Id
	spawnedAt stime.Time

	cell coord.Cell

	damage int
}

type AssailEntityState struct {
	Type string `json:"type"`

	EntityId entity.Id `json:"id"`

	SpawnedBy entity.Id  `json:"spawnedBy"`
	SpawnedAt stime.Time `json:"spawnedAt"`

	Cell coord.Cell `json:"cell"`
}

func (e assailEntity) Id() entity.Id    { return e.id }
func (e assailEntity) Cell() coord.Cell { return e.cell }
func (e assailEntity) Bounds() coord.Bounds {
	return coord.Bounds{e.cell, e.cell}
}

func (e assailEntity) ToState() entity.State {
	return AssailEntityState{
		Type: "assail",

		EntityId: e.id,

		SpawnedBy: e.spawnedBy,
		SpawnedAt: e.spawnedAt,

		Cell: e.cell,
	}
}

func (e AssailEntityState) Id() entity.Id { return e.EntityId }
func (e AssailEntityState) Bounds() coord.Bounds {
	return coord.Bounds{e.Cell, e.Cell}
}

func (e AssailEntityState) IsDifferentFrom(entity.State) bool {
	return true
}

func (c actorConn) ReadUseCmd() *useCmd {
	return <-c.readUseCmd
}

func (phase inputPhase) processUseCmd(a *actor, now stime.Time) []entity.Entity {
	cmd := a.ReadUseCmd()
	if cmd == nil {
		return nil
	}

	// TODO Only allow when stationary
	// TODO Trigger a cooldown
	switch cmd.skill {
	case "assail":
		// Implement a cooldown
		if a.lastAssail.spawnedAt+assailCooldown > now {
			return nil
		}

		e := assailEntity{
			id: phase.nextId(),

			spawnedBy: a.actorEntity.Id(),
			spawnedAt: now,

			cell: a.Cell().Neighbor(a.facing),

			damage: 25,
		}

		a.lastAssail = e

		return []entity.Entity{e}
	}
	return nil
}

// In seconds
const sayEntityDuration = 3

type sayEntity struct {
	id entity.Id

	saidBy entity.Id
	saidAt stime.Time

	cell coord.Cell

	msg string
}

type SayEntityState struct {
	Type string `json:"type"`

	EntityId entity.Id `json:"id"`

	SaidBy entity.Id  `json:"saidBy"`
	SaidAt stime.Time `json:"saidAt"`

	Cell coord.Cell `json:"cell"`

	Msg string `json:"msg"`
}

func (e sayEntity) Id() entity.Id    { return e.id }
func (e sayEntity) Cell() coord.Cell { return e.cell }
func (e sayEntity) Bounds() coord.Bounds {
	return coord.Bounds{e.cell, e.cell}
}

func (e sayEntity) ToState() entity.State {
	return SayEntityState{
		Type: "say",

		EntityId: e.id,

		SaidBy: e.saidBy,
		SaidAt: e.saidAt,

		Cell: e.cell,

		Msg: e.msg,
	}
}

func (e SayEntityState) Id() entity.Id { return e.EntityId }
func (e SayEntityState) Bounds() coord.Bounds {
	return coord.Bounds{e.Cell, e.Cell}
}
func (e SayEntityState) IsDifferentFrom(other entity.State) bool {
	return false
}

func (a *actor) ReadChatCmd() *chatCmd {
	return <-a.readChatCmd
}

func (phase inputPhase) processChatCmd(a *actor, now stime.Time) []entity.Entity {
	cmd := a.ReadChatCmd()
	if cmd == nil {
		return nil
	}

	switch cmd.chatType {
	case CR_SAY:
		return []entity.Entity{sayEntity{
			id: phase.nextId(),

			saidBy: a.actorEntity.Id(),
			saidAt: now,

			cell: a.Cell(),

			msg: cmd.msg,
		}}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.

   This file is licensed under the Apache License, Version 2.0 (the "License").
   You may not use this file except in compliance with the License. A copy of
   the License is located at

    http://aws.amazon.com/apache2.0/

   This file 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 (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/cloudwatch"

    "fmt"
)

func main() {
    if len(os.Args) != 4 {
        fmt.Println("You must supply a metric name, dimension, value, and namespace")
        os.Exit(1)
    }

    metric := os.Args[1]
    dimensions := os.Args[3]
    namespace := os.Args[2]

    // Initialize a session that the SDK uses to load
    // credentials from the shared credentials file ~/.aws/credentials
    // and configuration from the shared configuration file ~/.aws/config.
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    // Create new cloudwatch client.
    svc := cloudwatch.New(sess)

    // This will disable the alarm.
    result, err := svc.PutMetricData(&cloudwatch.PutMetricDataInput{
        MetricData: []*cloudwatch.MetricDatum{
            &cloudwatch.MetricDatum{
                MetricName: aws.String(metric),
                Unit:       aws.String(cloudwatch.StandardUnitNone),
                Value:      aws.Float64(1.0),
                Dimensions: []*cloudwatch.Dimension{
                    &cloudwatch.Dimension{
                        Name:  aws.String(dimension),
                        Value: aws.String(value),
                    },
                },
            },
        },
        Namespace: aws.String(namespace),
    })
    if err != nil {
        fmt.Println("Error", err)
        return
    }

    fmt.Println("Success", result)
}
<commit_msg>Updated Go CloudWatch example<commit_after>/*
   Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.

   This file is licensed under the Apache License, Version 2.0 (the "License").
   You may not use this file except in compliance with the License. A copy of
   the License is located at

    http://aws.amazon.com/apache2.0/

   This file 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 (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/cloudwatch"

    "fmt"
)

func main() {
    // Initialize a session that the SDK uses to load
    // credentials from the shared credentials file ~/.aws/credentials
    // and configuration from the shared configuration file ~/.aws/config.
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    // Create new cloudwatch client.
    svc := cloudwatch.New(sess)

    _, err := svc.PutMetricData(&cloudwatch.PutMetricDataInput{
        Namespace: aws.String("Site/Traffic"),
        MetricData: []*cloudwatch.MetricDatum{
            &cloudwatch.MetricDatum{
                MetricName: aws.String("UniqueVisitors"),
                Unit:       aws.String("Count"),
                Value:      aws.Float64(5885.0),
                Dimensions: []*cloudwatch.Dimension{
                    &cloudwatch.Dimension{
                        Name:  aws.String("SiteName"),
                        Value: aws.String("example.com"),
                    },
                },
            },
            &cloudwatch.MetricDatum{
                MetricName: aws.String("UniqueVisits"),
                Unit:       aws.String("Count"),
                Value:      aws.Float64(8628.0),
                Dimensions: []*cloudwatch.Dimension{
                    &cloudwatch.Dimension{
                        Name:  aws.String("SiteName"),
                        Value: aws.String("example.com"),
                    },
                },
            },
            &cloudwatch.MetricDatum{
                MetricName: aws.String("PageViews"),
                Unit:       aws.String("Count"),
                Value:      aws.Float64(18057.0),
                Dimensions: []*cloudwatch.Dimension{
                    &cloudwatch.Dimension{
                        Name:  aws.String("PageURL"),
                        Value: aws.String("my-page.html"),
                    },
                },
            },
        },
    })
    if err != nil {
        fmt.Println("Error adding metrics:", err.Error())
        return
    }

    // Get information about metrics
    result, err := svc.ListMetrics(&cloudwatch.ListMetricsInput{
        Namespace: aws.String("Site/Traffic"),
    })
    if err != nil {
        fmt.Println("Error getting metrics:", err.Error())
        return
    }

    for _, metric := range result.Metrics {
        fmt.Println(*metric.MetricName)

        for _, dim := range metric.Dimensions {
            fmt.Println(*dim.Name + ":", *dim.Value)
            fmt.Println()
        }
    }
}
<|endoftext|>


<commit_before>package koding

import (
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/multierrors"
	"koding/kites/kloud/protocol"
	"sync"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

var (
	// Be cautious if your try to lower this. A build might really last more
	// than 10 minutes.
	CleanUpTimeout = time.Minute * 10
)

// RunCleaner runs the given cleaners for the given timeout duration. It cleans
// up/resets machine documents and VM leftovers.
func (p *Provider) RunCleaners(interval time.Duration) {
	cleaners := func() {
		// run for the first time
		if err := p.CleanLocks(CleanUpTimeout); err != nil {
			p.Log.Warning("Cleaning locks: %s", err)
		}

		if err := p.CleanDeletedVMs(); err != nil {
			p.Log.Warning("Cleaning deleted vms: %s", err)
		}

		if err := p.CleanStates(CleanUpTimeout); err != nil {
			p.Log.Warning("Cleaning states vms: %s", err)
		}
	}

	cleaners()
	for _ = range time.Tick(interval) {
		go cleaners() // do not block
	}
}

// CleanDeletedVMS deletes VMs that have userDeleted set to true. This happens
// when the user deletes their account but kloud couldn't delete/terminate
// their VM's. This can happen for example if the user deletes their VM during
// an ongoing (build, start, stop...) process. There will be a lock due Build
// which will prevent to delete it.
func (p *Provider) CleanDeletedVMs() error {
	machines := make([]MachineDocument, 0)

	query := func(c *mgo.Collection) error {
		deletedMachines := bson.M{
			"userDeleted": true,
		}

		machine := MachineDocument{}
		iter := c.Find(deletedMachines).Batch(50).Iter()
		for iter.Next(&machine) {
			machines = append(machines, machine)
		}

		return iter.Close()
	}

	if err := p.Session.Run("jMachines", query); err != nil {
		return err
	}

	deleteMachine := func(id string) error {
		// we don't use p.Get() because it checks the user existence too,
		// however for deleted machines there are no users
		machine := &MachineDocument{}
		if err := p.Session.Run("jMachines", func(c *mgo.Collection) error {
			return c.FindId(bson.ObjectIdHex(id)).One(&machine)
		}); err != nil {
			return err
		}

		m := &protocol.Machine{
			Id:          id,
			Username:    machine.Credential, // contains the username for koding provider
			Provider:    machine.Provider,
			Builder:     machine.Meta,
			State:       machine.State(),
			IpAddress:   machine.IpAddress,
			QueryString: machine.QueryString,
			Eventer:     &eventer.Events{},
		}
		m.Domain.Name = machine.Domain

		// if there is no instance Id just remove the document
		if _, ok := m.Builder["instanceId"]; !ok {
			return p.Delete(id)
		}

		p.Log.Info("[%s] cleaner: terminating user deleted machine. User %s",
			id, m.Username)

		p.Destroy(m)

		return p.Delete(id)
	}

	for _, machine := range machines {
		if err := deleteMachine(machine.Id.Hex()); err != nil {
			p.Log.Error("[%s] couldn't terminate user deleted machine: %s",
				machine.Id.Hex(), err.Error())
		}
	}

	machines = nil // garbage collect it

	return nil
}

// CleanLocks resets documents that where locked by workers who died and left
// the documents untouched/unlocked. These documents are *ghost* documents,
// because they have an assignee that is not nil no worker will pick it up. The
// given timeout specificies to look up documents from now on.
func (p *Provider) CleanLocks(timeout time.Duration) error {
	query := func(c *mgo.Collection) error {
		// machines that can't be updated because they seems to be in progress
		ghostMachines := bson.M{
			"assignee.inProgress": true,
			"assignee.assignedAt": bson.M{"$lt": time.Now().UTC().Add(-timeout)},
		}

		cleanMachines := bson.M{
			"assignee.inProgress": false,
			"assignee.assignedAt": time.Now().UTC(),
		}

		// reset all machines
		info, err := c.UpdateAll(ghostMachines, bson.M{"$set": cleanMachines})
		if err != nil {
			return err
		}

		// only show if there is something, that will prevent spamming the
		// output with the same content over and over
		if info.Updated != 0 {
			p.Log.Info("[checker] cleaned up %d documents", info.Updated)
		}

		return nil
	}

	return p.Session.Run("jMachines", query)
}

// CleanStates resets documents that has machine states in progress mode
// (building, stopping, etc..) which weren't updated since 10 minutes. This
// could be caused because of Kloud restarts or panics.
func (p *Provider) CleanStates(timeout time.Duration) error {
	cleanstateFunc := func(badstate, goodstate string) error {
		return p.Session.Run("jMachines", func(c *mgo.Collection) error {
			// machines that can't be updated because they seems to be in progress
			badstateMachines := bson.M{
				"status.state":      badstate,
				"status.modifiedAt": bson.M{"$lt": time.Now().UTC().Add(-timeout)},
			}

			cleanMachines := bson.M{
				"status.state":      goodstate,
				"status.modifiedAt": time.Now().UTC(),
			}

			// reset all machines
			info, err := c.UpdateAll(badstateMachines, bson.M{"$set": cleanMachines})
			if err != nil {
				return err
			}

			// only show if there is something, that will prevent spamming the
			// output with the same content over and over
			if info.Updated != 0 {
				p.Log.Info("[state cleaner] fixed %d documents from '%s' to '%s'",
					info.Updated, badstate, goodstate)
			}

			return nil
		})
	}

	progressModes := []struct {
		bad  string
		good string
	}{
		{machinestate.Building.String(), machinestate.NotInitialized.String()},
		{machinestate.Terminating.String(), machinestate.Terminated.String()},
		{machinestate.Stopping.String(), machinestate.Stopped.String()},
		{machinestate.Starting.String(), machinestate.Stopped.String()},
	}

	errs := multierrors.New()

	var wg sync.WaitGroup
	for _, state := range progressModes {
		wg.Add(1)
		go func(bad, good string) {
			defer wg.Done()
			err := cleanstateFunc(bad, good)
			errs.Add(err)
		}(state.bad, state.good)
	}

	wg.Wait()

	// if there is no errors just return a nil
	if errs.Len() == 0 {
		return nil
	}

	return errs
}
<commit_msg>kloud/cleaners: only update when there is no more any lock<commit_after>package koding

import (
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/multierrors"
	"koding/kites/kloud/protocol"
	"sync"
	"time"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

var (
	// Be cautious if your try to lower this. A build might really last more
	// than 10 minutes.
	CleanUpTimeout = time.Minute * 10
)

// RunCleaner runs the given cleaners for the given timeout duration. It cleans
// up/resets machine documents and VM leftovers.
func (p *Provider) RunCleaners(interval time.Duration) {
	cleaners := func() {
		// run for the first time
		if err := p.CleanLocks(CleanUpTimeout); err != nil {
			p.Log.Warning("Cleaning locks: %s", err)
		}

		if err := p.CleanDeletedVMs(); err != nil {
			p.Log.Warning("Cleaning deleted vms: %s", err)
		}

		if err := p.CleanStates(CleanUpTimeout); err != nil {
			p.Log.Warning("Cleaning states vms: %s", err)
		}
	}

	cleaners()
	for _ = range time.Tick(interval) {
		go cleaners() // do not block
	}
}

// CleanDeletedVMS deletes VMs that have userDeleted set to true. This happens
// when the user deletes their account but kloud couldn't delete/terminate
// their VM's. This can happen for example if the user deletes their VM during
// an ongoing (build, start, stop...) process. There will be a lock due Build
// which will prevent to delete it.
func (p *Provider) CleanDeletedVMs() error {
	machines := make([]MachineDocument, 0)

	query := func(c *mgo.Collection) error {
		deletedMachines := bson.M{
			"userDeleted": true,
		}

		machine := MachineDocument{}
		iter := c.Find(deletedMachines).Batch(50).Iter()
		for iter.Next(&machine) {
			machines = append(machines, machine)
		}

		return iter.Close()
	}

	if err := p.Session.Run("jMachines", query); err != nil {
		return err
	}

	deleteMachine := func(id string) error {
		// we don't use p.Get() because it checks the user existence too,
		// however for deleted machines there are no users
		machine := &MachineDocument{}
		if err := p.Session.Run("jMachines", func(c *mgo.Collection) error {
			return c.FindId(bson.ObjectIdHex(id)).One(&machine)
		}); err != nil {
			return err
		}

		m := &protocol.Machine{
			Id:          id,
			Username:    machine.Credential, // contains the username for koding provider
			Provider:    machine.Provider,
			Builder:     machine.Meta,
			State:       machine.State(),
			IpAddress:   machine.IpAddress,
			QueryString: machine.QueryString,
			Eventer:     &eventer.Events{},
		}
		m.Domain.Name = machine.Domain

		// if there is no instance Id just remove the document
		if _, ok := m.Builder["instanceId"]; !ok {
			return p.Delete(id)
		}

		p.Log.Info("[%s] cleaner: terminating user deleted machine. User %s",
			id, m.Username)

		p.Destroy(m)

		return p.Delete(id)
	}

	for _, machine := range machines {
		if err := deleteMachine(machine.Id.Hex()); err != nil {
			p.Log.Error("[%s] couldn't terminate user deleted machine: %s",
				machine.Id.Hex(), err.Error())
		}
	}

	machines = nil // garbage collect it

	return nil
}

// CleanLocks resets documents that where locked by workers who died and left
// the documents untouched/unlocked. These documents are *ghost* documents,
// because they have an assignee that is not nil no worker will pick it up. The
// given timeout specificies to look up documents from now on.
func (p *Provider) CleanLocks(timeout time.Duration) error {
	query := func(c *mgo.Collection) error {
		// machines that can't be updated because they seems to be in progress
		ghostMachines := bson.M{
			"assignee.inProgress": true,
			"assignee.assignedAt": bson.M{"$lt": time.Now().UTC().Add(-timeout)},
		}

		cleanMachines := bson.M{
			"assignee.inProgress": false,
			"assignee.assignedAt": time.Now().UTC(),
		}

		// reset all machines
		info, err := c.UpdateAll(ghostMachines, bson.M{"$set": cleanMachines})
		if err != nil {
			return err
		}

		// only show if there is something, that will prevent spamming the
		// output with the same content over and over
		if info.Updated != 0 {
			p.Log.Info("[checker] cleaned up %d documents", info.Updated)
		}

		return nil
	}

	return p.Session.Run("jMachines", query)
}

// CleanStates resets documents that has machine states in progress mode
// (building, stopping, etc..) which weren't updated since 10 minutes. This
// could be caused because of Kloud restarts or panics.
func (p *Provider) CleanStates(timeout time.Duration) error {
	cleanstateFunc := func(badstate, goodstate string) error {
		return p.Session.Run("jMachines", func(c *mgo.Collection) error {
			// machines that can't be updated because they seems to be in progress
			badstateMachines := bson.M{
				"assignee.inProgress": false, // never update during a onging process :)
				"status.state":        badstate,
				"status.modifiedAt":   bson.M{"$lt": time.Now().UTC().Add(-timeout)},
			}

			cleanMachines := bson.M{
				"status.state":      goodstate,
				"status.modifiedAt": time.Now().UTC(),
			}

			// reset all machines
			info, err := c.UpdateAll(badstateMachines, bson.M{"$set": cleanMachines})
			if err != nil {
				return err
			}

			// only show if there is something, that will prevent spamming the
			// output with the same content over and over
			if info.Updated != 0 {
				p.Log.Info("[state cleaner] fixed %d documents from '%s' to '%s'",
					info.Updated, badstate, goodstate)
			}

			return nil
		})
	}

	progressModes := []struct {
		bad  string
		good string
	}{
		{machinestate.Building.String(), machinestate.NotInitialized.String()},
		{machinestate.Terminating.String(), machinestate.Terminated.String()},
		{machinestate.Stopping.String(), machinestate.Stopped.String()},
		{machinestate.Starting.String(), machinestate.Stopped.String()},
	}

	errs := multierrors.New()

	var wg sync.WaitGroup
	for _, state := range progressModes {
		wg.Add(1)
		go func(bad, good string) {
			defer wg.Done()
			err := cleanstateFunc(bad, good)
			errs.Add(err)
		}(state.bad, state.good)
	}

	wg.Wait()

	// if there is no errors just return a nil
	if errs.Len() == 0 {
		return nil
	}

	return errs
}
<|endoftext|>