<commit_before>package app

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/fragmenta/server"
	"github.com/fragmenta/server/config"
	"github.com/fragmenta/server/log"
	"github.com/fragmenta/view"
)

// Serve static files (assets, images etc)
func fileHandler(w http.ResponseWriter, r *http.Request) error {

	// First try serving assets
	err := serveAsset(w, r)
	if err == nil {
		return nil
	}

	// If assets fail, try to serve file in public
	return serveFile(w, r)
}

// serveFile serves a file from ./public if it exists
func serveFile(w http.ResponseWriter, r *http.Request) error {

	// Try a local path in the public directory
	localPath := "./public" + path.Clean(r.URL.Path)
	s, err := os.Stat(localPath)
	if err != nil {
		// If file not found return 404
		if os.IsNotExist(err) {
			return server.NotFoundError(err)
		}

		// For other errors return not authorised
		return server.NotAuthorizedError(err)
	}

	// If not a file return immediately
	if s.IsDir() {
		return nil
	}

	// If the file exists and we can access it, serve it with cache control
	// if in production
	if config.Production() {
		// Cache for 30 days
		w.Header().Set("Cache-Control", "max-age:2592000")
		// For etag Just hash the path - static resources are assumed to have a fingerprint
		w.Header().Set("ETag", fmt.Sprintf("\"%s\"", hash(r.URL.Path)))
	}

	http.ServeFile(w, r, localPath)
	return nil
}

// hash returns the sha hash of a string
func hash(s string) string {
	sum := sha1.Sum([]byte(s))
	return hex.EncodeToString([]byte(sum[:]))
}

// serveAsset serves a file from ./public/assets usings appAssets
func serveAsset(w http.ResponseWriter, r *http.Request) error {

	p := path.Clean(r.URL.Path)

	// It must be under /assets, or we don't serve
	if !strings.HasPrefix(p, "/assets/") {
		return server.NotFoundError(nil)
	}

	// Try to find an asset in our list
	f := appAssets.File(path.Base(p))
	if f == nil {
		return server.NotFoundError(nil)
	}

	// Serve the local file, with cache control
	localPath := "./" + f.LocalPath()
	// If the file exists and we can access it, serve it with cache control in production
	if config.Production() {
		// Cache for 30 days
		w.Header().Set("Cache-Control", "max-age:2592000")
		// For etag Just hash the path - static resources are assumed to have a fingerprint
		w.Header().Set("ETag", fmt.Sprintf("\"%s\"", hash(r.URL.Path)))
	}
	http.ServeFile(w, r, localPath)
	return nil
}

// errHandler renders an error using error templates if available
func errHandler(w http.ResponseWriter, r *http.Request, e error) {

	// Cast the error to a status error if it is one, if not wrap it in a Status 500 error
	err := server.ToStatusError(e)
	log.Error(log.V{"error": err})

	view := view.NewWithPath("", w)
	view.AddKey("title", err.Title)
	view.AddKey("message", err.Message)
	// In production, provide no detail for security reasons
	if !config.Production() {
		view.AddKey("status", err.Status)
		view.AddKey("file", err.FileLine())
		view.AddKey("error", err.Err)
	}
	view.Template("app/views/error.html.got")
	w.WriteHeader(err.Status)
	view.Render()
}
<commit_msg>Add expires header to cache control<commit_after>package app

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"
	"time"

	"github.com/fragmenta/server"
	"github.com/fragmenta/server/config"
	"github.com/fragmenta/server/log"
	"github.com/fragmenta/view"
)

// Serve static files (assets, images etc)
func fileHandler(w http.ResponseWriter, r *http.Request) error {

	// First try serving assets
	err := serveAsset(w, r)
	if err == nil {
		return nil
	}

	// If assets fail, try to serve file in public
	return serveFile(w, r)
}

// serveFile serves a file from ./public if it exists
func serveFile(w http.ResponseWriter, r *http.Request) error {

	// Try a local path in the public directory
	localPath := "./public" + path.Clean(r.URL.Path)
	s, err := os.Stat(localPath)
	if err != nil {
		// If file not found return 404
		if os.IsNotExist(err) {
			return server.NotFoundError(err)
		}

		// For other errors return not authorised
		return server.NotAuthorizedError(err)
	}

	// If not a file return immediately
	if s.IsDir() {
		return nil
	}

	// If the file exists and we can access it, serve it with cache control
	if config.Production() {
		addCacheControl(w, r)
	}

	http.ServeFile(w, r, localPath)
	return nil
}

// serveAsset serves a file from ./public/assets usings appAssets
func serveAsset(w http.ResponseWriter, r *http.Request) error {

	p := path.Clean(r.URL.Path)

	// It must be under /assets, or we don't serve
	if !strings.HasPrefix(p, "/assets/") {
		return server.NotFoundError(nil)
	}

	// Try to find an asset in our list
	f := appAssets.File(path.Base(p))
	if f == nil {
		return server.NotFoundError(nil)
	}

	// Serve the local file, with cache control
	localPath := "./" + f.LocalPath()
	// If the file exists and we can access it, serve it with cache control in production
	if config.Production() {
		addCacheControl(w, r)
	}
	http.ServeFile(w, r, localPath)
	return nil
}

// errHandler renders an error using error templates if available
func errHandler(w http.ResponseWriter, r *http.Request, e error) {

	// Cast the error to a status error if it is one, if not wrap it in a Status 500 error
	err := server.ToStatusError(e)
	log.Error(log.V{"error": err})

	view := view.NewWithPath("", w)
	view.AddKey("title", err.Title)
	view.AddKey("message", err.Message)
	// In production, provide no detail for security reasons
	if !config.Production() {
		view.AddKey("status", err.Status)
		view.AddKey("file", err.FileLine())
		view.AddKey("error", err.Err)
	}
	view.Template("app/views/error.html.got")
	w.WriteHeader(err.Status)
	view.Render()
}

// hash returns the sha hash of a string
func hash(s string) string {
	sum := sha1.Sum([]byte(s))
	return hex.EncodeToString([]byte(sum[:]))
}

func addCacheControl(w http.ResponseWriter, r *http.Request) {
	// Cache for 30 days
	w.Header().Set("Cache-Control", "max-age:2592000")

	// Set an expires header Mon Jan 2 15:04:05 -0700 MST 2006
	w.Header().Set("Expires", time.Now().AddDate(0, 0, 30).UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"))

	// For etag Just hash the path - static resources are assumed to have a fingerprint
	w.Header().Set("ETag", fmt.Sprintf("\"%s\"", hash(r.URL.Path)))
}
<|endoftext|>


<commit_before>package dnsdisco

import (
	"fmt"
	"net"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/miekg/dns"
)

func TestDiscover(t *testing.T) {
	scenarios := []struct {
		description    string
		service        string
		proto          string
		name           string
		expectedTarget string
		expectedPort   uint16
		expectedError  error
	}{
		{
			description:    "it should retrieve the target correctly",
			service:        "jabber",
			proto:          "tcp",
			name:           "registro.br",
			expectedTarget: "jabber.registro.br.",
			expectedPort:   5269,
		},
		{
			description: "it should fail when the protocol is invalid",
			service:     "jabber",
			proto:       "xxx",
			name:        "registro.br",
			expectedError: &net.DNSError{
				Err:    "no such host",
				Name:   "_jabber._xxx.registro.br",
				Server: "200.160.3.2:53",
			},
		},
	}

	for i, item := range scenarios {
		target, port, err := Discover(item.service, item.proto, item.name)

		if target != item.expectedTarget {
			t.Errorf("scenario %d, “%s”: mismatch targets. Expecting: “%s”; found “%s”",
				i, item.description, item.expectedTarget, target)
		}

		if port != item.expectedPort {
			t.Errorf("scenario %d, “%s”: mismatch ports. Expecting: “%d”; found “%d”",
				i, item.description, item.expectedPort, port)
		}

		if !reflect.DeepEqual(err, item.expectedError) {
			t.Errorf("scenario %d, “%s”: mismatch errors. Expecting: “%v”; found “%v”",
				i, item.description, item.expectedError, err)
		}
	}
}

func ExampleDiscover() {
	target, port, err := Discover("jabber", "tcp", "registro.br")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Target: %s\nPort: %d\n", target, port)

	// Output:
	// Target: jabber.registro.br.
	// Port: 5269
}

func ExampleRetrieverFunc() {
	discovery := NewDiscovery("jabber", "tcp", "registro.br")
	discovery.Retriever = RetrieverFunc(func(service, proto, name string) (servers []*net.SRV, err error) {
		client := dns.Client{
			ReadTimeout:  2 * time.Second,
			WriteTimeout: 2 * time.Second,
		}

		name = strings.TrimRight(name, ".")
		z := fmt.Sprintf("_%s._%s.%s.", service, proto, name)

		var request dns.Msg
		request.SetQuestion(z, dns.TypeSRV)
		request.RecursionDesired = true

		response, _, err := client.Exchange(&request, "8.8.8.8:53")
		if err != nil {
			return nil, err
		}

		for _, rr := range response.Answer {
			if srv, ok := rr.(*dns.SRV); ok {
				servers = append(servers, &net.SRV{
					Target:   srv.Target,
					Port:     srv.Port,
					Priority: srv.Priority,
					Weight:   srv.Weight,
				})
			}
		}

		return
	})

	// Retrieve the servers
	if err := discovery.Refresh(); err != nil {
		fmt.Println(err)
		return
	}

	target, port := discovery.Choose()
	fmt.Printf("Target: %s\nPort: %d\n", target, port)

	// Output:
	// Target: jabber.registro.br.
	// Port: 5269
}
<commit_msg>Change package and fix resolver issue for DNSError<commit_after>package dnsdisco_test

import (
	"fmt"
	"net"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/miekg/dns"
	"github.com/rafaeljusto/dnsdisco"
)

func TestDiscover(t *testing.T) {
	scenarios := []struct {
		description    string
		service        string
		proto          string
		name           string
		expectedTarget string
		expectedPort   uint16
		expectedError  error
	}{
		{
			description:    "it should retrieve the target correctly",
			service:        "jabber",
			proto:          "tcp",
			name:           "registro.br",
			expectedTarget: "jabber.registro.br.",
			expectedPort:   5269,
		},
		{
			description: "it should fail when the protocol is invalid",
			service:     "jabber",
			proto:       "xxx",
			name:        "registro.br",
			expectedError: &net.DNSError{
				Err:    "no such host",
				Name:   "_jabber._xxx.registro.br",
			},
		},
	}

	for i, item := range scenarios {
		target, port, err := dnsdisco.Discover(item.service, item.proto, item.name)

		if target != item.expectedTarget {
			t.Errorf("scenario %d, “%s”: mismatch targets. Expecting: “%s”; found “%s”",
				i, item.description, item.expectedTarget, target)
		}

		if port != item.expectedPort {
			t.Errorf("scenario %d, “%s”: mismatch ports. Expecting: “%d”; found “%d”",
				i, item.description, item.expectedPort, port)
		}

		// As the resolver change between machines, we can't guess the DNSError name's attribute. So we
		// need to inject the value on the expected error
		dnsError, ok1 := err.(*net.DNSError)
		expectedDNSError, ok2 := item.expectedError.(*net.DNSError)

		if ok1 && ok2 {
			expectedDNSError.Server = dnsError.Server
		}

		if !reflect.DeepEqual(err, item.expectedError) {
			t.Errorf("scenario %d, “%s”: mismatch errors. Expecting: “%v”; found “%v”",
				i, item.description, item.expectedError, err)
		}
	}
}

func ExampleDiscover() {
	target, port, err := dnsdisco.Discover("jabber", "tcp", "registro.br")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Target: %s\nPort: %d\n", target, port)

	// Output:
	// Target: jabber.registro.br.
	// Port: 5269
}

func ExampleRetrieverFunc() {
	discovery := dnsdisco.NewDiscovery("jabber", "tcp", "registro.br")
	discovery.Retriever = dnsdisco.RetrieverFunc(func(service, proto, name string) (servers []*net.SRV, err error) {
		client := dns.Client{
			ReadTimeout:  2 * time.Second,
			WriteTimeout: 2 * time.Second,
		}

		name = strings.TrimRight(name, ".")
		z := fmt.Sprintf("_%s._%s.%s.", service, proto, name)

		var request dns.Msg
		request.SetQuestion(z, dns.TypeSRV)
		request.RecursionDesired = true

		response, _, err := client.Exchange(&request, "8.8.8.8:53")
		if err != nil {
			return nil, err
		}

		for _, rr := range response.Answer {
			if srv, ok := rr.(*dns.SRV); ok {
				servers = append(servers, &net.SRV{
					Target:   srv.Target,
					Port:     srv.Port,
					Priority: srv.Priority,
					Weight:   srv.Weight,
				})
			}
		}

		return
	})

	// Retrieve the servers
	if err := discovery.Refresh(); err != nil {
		fmt.Println(err)
		return
	}

	target, port := discovery.Choose()
	fmt.Printf("Target: %s\nPort: %d\n", target, port)

	// Output:
	// Target: jabber.registro.br.
	// Port: 5269
}
<|endoftext|>


<commit_before>package main

import twodee "../libs/twodee"

type AudioSystem struct {
	app                      *Application
	outdoorMusic             *twodee.Music
	exploreMusic             *twodee.Music
	warningMusic             *twodee.Music
	dangerMusic              *twodee.Music
	menuMoveEffect           *twodee.SoundEffect
	menuSelectEffect         *twodee.SoundEffect
	fallDownEffect           *twodee.SoundEffect
	climbUpEffect            *twodee.SoundEffect
	pickupItemEffect         *twodee.SoundEffect
	gameOverEffect           *twodee.SoundEffect
	victoryEffect            *twodee.SoundEffect
	outdoorMusicObserverId   int
	exploreMusicObserverId   int
	warningMusicObserverId   int
	dangerMusicObserverId    int
	pauseMusicObserverId     int
	resumeMusicObserverId    int
	menuPauseMusicObserverId int
	menuMoveObserverId       int
	menuSelectObserverId     int
	dryWalkObserverId        int
	wetWalkObserverId        int
	fallDownObserverId       int
	climbUpObserverId        int
	pickupItemObserverId     int
	gameOverObserverId       int
	victoryObserverId        int
	musicToggle              int32
}

func (a *AudioSystem) PlayOutdoorMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.outdoorMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayExploreMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.exploreMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayWarningMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.warningMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayDangerMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.dangerMusic.Play(-1)
	}
}

func (a *AudioSystem) PauseMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
	}
}

func (a *AudioSystem) ResumeMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPaused() {
			twodee.ResumeMusic()
		}
	}
}

func (a *AudioSystem) MenuPauseMusic(e twodee.GETyper) {
	if twodee.MusicIsPlaying() {
		twodee.PauseMusic()
	}
}

func (a *AudioSystem) PlayMenuMoveEffect(e twodee.GETyper) {
	a.menuMoveEffect.Play(1)
}

func (a *AudioSystem) PlayMenuSelectEffect(e twodee.GETyper) {
	a.menuSelectEffect.Play(1)
}

func (a *AudioSystem) PlayFallDownEffect(e twodee.GETyper) {
	a.fallDownEffect.PlayChannel(5, 1)
}

func (a *AudioSystem) PlayClimbUpEffect(e twodee.GETyper) {
	a.climbUpEffect.PlayChannel(5, 1)
}

func (a *AudioSystem) PlayPickupItemEffect(e twodee.GETyper) {
	a.pickupItemEffect.PlayChannel(6, 1)
}

func (a *AudioSystem) PlayGameOverEffect(e twodee.GETyper) {
	a.gameOverEffect.PlayChannel(7, 1)
}

func (a *AudioSystem) PlayVictoryEffect(e twodee.GETyper) {
	a.victoryEffect.PlayChannel(7, 1)
}

func (a *AudioSystem) Delete() {
	a.app.GameEventHandler.RemoveObserver(PlayOutdoorMusic, a.outdoorMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayExploreMusic, a.exploreMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayWarningMusic, a.warningMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayDangerMusic, a.dangerMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PauseMusic, a.pauseMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(ResumeMusic, a.resumeMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuPauseMusic, a.menuPauseMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuMove, a.menuMoveObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuSelect, a.menuSelectObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayFallDownEffect, a.fallDownObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayClimbUpEffect, a.climbUpObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayPickupItemEffect, a.pickupItemObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayGameOverEffect, a.gameOverObserverId)
	a.outdoorMusic.Delete()
	a.exploreMusic.Delete()
	a.warningMusic.Delete()
	a.dangerMusic.Delete()
	a.menuMoveEffect.Delete()
	a.menuSelectEffect.Delete()
	a.fallDownEffect.Delete()
	a.climbUpEffect.Delete()
	a.pickupItemEffect.Delete()
	a.gameOverEffect.Delete()
	a.victoryEffect.Delete()
}

func NewAudioSystem(app *Application) (audioSystem *AudioSystem, err error) {
	var (
		outdoorMusic     *twodee.Music
		exploreMusic     *twodee.Music
		warningMusic     *twodee.Music
		dangerMusic      *twodee.Music
		menuMoveEffect   *twodee.SoundEffect
		menuSelectEffect *twodee.SoundEffect
		fallDownEffect   *twodee.SoundEffect
		climbUpEffect    *twodee.SoundEffect
		pickupItemEffect *twodee.SoundEffect
		gameOverEffect   *twodee.SoundEffect
		victoryEffect    *twodee.SoundEffect
	)
	if outdoorMusic, err = twodee.NewMusic("assets/music/Outdoor_Theme.ogg"); err != nil {
		return
	}
	if exploreMusic, err = twodee.NewMusic("assets/music/Exploration_Theme.ogg"); err != nil {
		return
	}
	if warningMusic, err = twodee.NewMusic("assets/music/Warning_Theme.ogg"); err != nil {
		return
	}
	if dangerMusic, err = twodee.NewMusic("assets/music/Underwater_Theme.ogg"); err != nil {
		return
	}
	if menuMoveEffect, err = twodee.NewSoundEffect("assets/soundeffects/MenuMove.ogg"); err != nil {
		return
	}
	if menuSelectEffect, err = twodee.NewSoundEffect("assets/soundeffects/MenuSelect.ogg"); err != nil {
		return
	}
	if fallDownEffect, err = twodee.NewSoundEffect("assets/soundeffects/FallDown.ogg"); err != nil {
		return
	}
	if climbUpEffect, err = twodee.NewSoundEffect("assets/soundeffects/ClimbUp.ogg"); err != nil {
		return
	}
	if pickupItemEffect, err = twodee.NewSoundEffect("assets/soundeffects/PickupItem.ogg"); err != nil {
		return
	}
	if gameOverEffect, err = twodee.NewSoundEffect("assets/soundeffects/GameOver.ogg"); err != nil {
		return
	}
	if victoryEffect, err = twodee.NewSoundEffect("assets/soundeffects/Victory.ogg"); err != nil {
		return
	}
	audioSystem = &AudioSystem{
		app:              app,
		outdoorMusic:     outdoorMusic,
		exploreMusic:     exploreMusic,
		warningMusic:     warningMusic,
		dangerMusic:      dangerMusic,
		menuMoveEffect:   menuMoveEffect,
		menuSelectEffect: menuSelectEffect,
		fallDownEffect:   fallDownEffect,
		climbUpEffect:    climbUpEffect,
		pickupItemEffect: pickupItemEffect,
		gameOverEffect:   gameOverEffect,
		victoryEffect:    victoryEffect,
		musicToggle:      1,
	}
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayOutdoorMusic, audioSystem.PlayOutdoorMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayExploreMusic, audioSystem.PlayExploreMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayWarningMusic, audioSystem.PlayWarningMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayDangerMusic, audioSystem.PlayDangerMusic)
	audioSystem.pauseMusicObserverId = app.GameEventHandler.AddObserver(PauseMusic, audioSystem.PauseMusic)
	audioSystem.resumeMusicObserverId = app.GameEventHandler.AddObserver(ResumeMusic, audioSystem.ResumeMusic)
	audioSystem.menuPauseMusicObserverId = app.GameEventHandler.AddObserver(MenuPauseMusic, audioSystem.MenuPauseMusic)
	audioSystem.menuMoveObserverId = app.GameEventHandler.AddObserver(MenuMove, audioSystem.PlayMenuMoveEffect)
	audioSystem.menuSelectObserverId = app.GameEventHandler.AddObserver(MenuSelect, audioSystem.PlayMenuSelectEffect)
	audioSystem.fallDownObserverId = app.GameEventHandler.AddObserver(PlayFallDownEffect, audioSystem.PlayFallDownEffect)
	audioSystem.climbUpObserverId = app.GameEventHandler.AddObserver(PlayClimbUpEffect, audioSystem.PlayClimbUpEffect)
	audioSystem.pickupItemObserverId = app.GameEventHandler.AddObserver(PlayPickupItemEffect, audioSystem.PlayPickupItemEffect)
	audioSystem.gameOverObserverId = app.GameEventHandler.AddObserver(PlayGameOverEffect, audioSystem.PlayGameOverEffect)
	audioSystem.victoryObserverId = app.GameEventHandler.AddObserver(PlayVictoryEffect, audioSystem.PlayVictoryEffect)
	return
}
<commit_msg>Added rock breaking sound effect and listener<commit_after>package main

import twodee "../libs/twodee"

type AudioSystem struct {
	app                      *Application
	outdoorMusic             *twodee.Music
	exploreMusic             *twodee.Music
	warningMusic             *twodee.Music
	dangerMusic              *twodee.Music
	menuMoveEffect           *twodee.SoundEffect
	menuSelectEffect         *twodee.SoundEffect
	fallDownEffect           *twodee.SoundEffect
	climbUpEffect            *twodee.SoundEffect
	pickupItemEffect         *twodee.SoundEffect
	rockBreakEffect          *twodee.SoundEffect
	gameOverEffect           *twodee.SoundEffect
	victoryEffect            *twodee.SoundEffect
	outdoorMusicObserverId   int
	exploreMusicObserverId   int
	warningMusicObserverId   int
	dangerMusicObserverId    int
	pauseMusicObserverId     int
	resumeMusicObserverId    int
	menuPauseMusicObserverId int
	menuMoveObserverId       int
	menuSelectObserverId     int
	dryWalkObserverId        int
	wetWalkObserverId        int
	fallDownObserverId       int
	climbUpObserverId        int
	pickupItemObserverId     int
	rockBreakObserverId      int
	gameOverObserverId       int
	victoryObserverId        int
	musicToggle              int32
}

func (a *AudioSystem) PlayOutdoorMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.outdoorMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayExploreMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.exploreMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayWarningMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.warningMusic.Play(-1)
	}
}

func (a *AudioSystem) PlayDangerMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
		a.dangerMusic.Play(-1)
	}
}

func (a *AudioSystem) PauseMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPlaying() {
			twodee.PauseMusic()
		}
	}
}

func (a *AudioSystem) ResumeMusic(e twodee.GETyper) {
	if a.musicToggle == 1 {
		if twodee.MusicIsPaused() {
			twodee.ResumeMusic()
		}
	}
}

func (a *AudioSystem) MenuPauseMusic(e twodee.GETyper) {
	if twodee.MusicIsPlaying() {
		twodee.PauseMusic()
	}
}

func (a *AudioSystem) PlayMenuMoveEffect(e twodee.GETyper) {
	a.menuMoveEffect.Play(1)
}

func (a *AudioSystem) PlayMenuSelectEffect(e twodee.GETyper) {
	a.menuSelectEffect.Play(1)
}

func (a *AudioSystem) PlayFallDownEffect(e twodee.GETyper) {
	a.fallDownEffect.PlayChannel(5, 1)
}

func (a *AudioSystem) PlayClimbUpEffect(e twodee.GETyper) {
	a.climbUpEffect.PlayChannel(5, 1)
}

func (a *AudioSystem) PlayPickupItemEffect(e twodee.GETyper) {
	a.pickupItemEffect.PlayChannel(6, 1)
}

func (a *AudioSystem) PlayRockBreakEffect(e twodee.GETyper) {
	a.rockBreakEffect.PlayChannel(6, 1)
}

func (a *AudioSystem) PlayGameOverEffect(e twodee.GETyper) {
	a.gameOverEffect.PlayChannel(7, 1)
}

func (a *AudioSystem) PlayVictoryEffect(e twodee.GETyper) {
	a.victoryEffect.PlayChannel(7, 1)
}

func (a *AudioSystem) Delete() {
	a.app.GameEventHandler.RemoveObserver(PlayOutdoorMusic, a.outdoorMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayExploreMusic, a.exploreMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayWarningMusic, a.warningMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayDangerMusic, a.dangerMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(PauseMusic, a.pauseMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(ResumeMusic, a.resumeMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuPauseMusic, a.menuPauseMusicObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuMove, a.menuMoveObserverId)
	a.app.GameEventHandler.RemoveObserver(MenuSelect, a.menuSelectObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayFallDownEffect, a.fallDownObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayClimbUpEffect, a.climbUpObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayPickupItemEffect, a.pickupItemObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayerDestroyedItem, a.rockBreakObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayGameOverEffect, a.gameOverObserverId)
	a.app.GameEventHandler.RemoveObserver(PlayVictoryEffect, a.victoryObserverId)
	a.outdoorMusic.Delete()
	a.exploreMusic.Delete()
	a.warningMusic.Delete()
	a.dangerMusic.Delete()
	a.menuMoveEffect.Delete()
	a.menuSelectEffect.Delete()
	a.fallDownEffect.Delete()
	a.climbUpEffect.Delete()
	a.pickupItemEffect.Delete()
	a.rockBreakEffect.Delete()
	a.gameOverEffect.Delete()
	a.victoryEffect.Delete()
}

func NewAudioSystem(app *Application) (audioSystem *AudioSystem, err error) {
	var (
		outdoorMusic     *twodee.Music
		exploreMusic     *twodee.Music
		warningMusic     *twodee.Music
		dangerMusic      *twodee.Music
		menuMoveEffect   *twodee.SoundEffect
		menuSelectEffect *twodee.SoundEffect
		fallDownEffect   *twodee.SoundEffect
		climbUpEffect    *twodee.SoundEffect
		pickupItemEffect *twodee.SoundEffect
		rockBreakEffect  *twodee.SoundEffect
		gameOverEffect   *twodee.SoundEffect
		victoryEffect    *twodee.SoundEffect
	)
	if outdoorMusic, err = twodee.NewMusic("assets/music/Outdoor_Theme.ogg"); err != nil {
		return
	}
	if exploreMusic, err = twodee.NewMusic("assets/music/Exploration_Theme.ogg"); err != nil {
		return
	}
	if warningMusic, err = twodee.NewMusic("assets/music/Warning_Theme.ogg"); err != nil {
		return
	}
	if dangerMusic, err = twodee.NewMusic("assets/music/Underwater_Theme.ogg"); err != nil {
		return
	}
	if menuMoveEffect, err = twodee.NewSoundEffect("assets/soundeffects/MenuMove.ogg"); err != nil {
		return
	}
	if menuSelectEffect, err = twodee.NewSoundEffect("assets/soundeffects/MenuSelect.ogg"); err != nil {
		return
	}
	if fallDownEffect, err = twodee.NewSoundEffect("assets/soundeffects/FallDown.ogg"); err != nil {
		return
	}
	if climbUpEffect, err = twodee.NewSoundEffect("assets/soundeffects/ClimbUp.ogg"); err != nil {
		return
	}
	if pickupItemEffect, err = twodee.NewSoundEffect("assets/soundeffects/PickupItem.ogg"); err != nil {
		return
	}
	if rockBreakEffect, err = twodee.NewSoundEffect("assets/soundeffects/RockBreak.ogg"); err != nil {
		return
	}
	if gameOverEffect, err = twodee.NewSoundEffect("assets/soundeffects/GameOver.ogg"); err != nil {
		return
	}
	if victoryEffect, err = twodee.NewSoundEffect("assets/soundeffects/Victory.ogg"); err != nil {
		return
	}
	audioSystem = &AudioSystem{
		app:              app,
		outdoorMusic:     outdoorMusic,
		exploreMusic:     exploreMusic,
		warningMusic:     warningMusic,
		dangerMusic:      dangerMusic,
		menuMoveEffect:   menuMoveEffect,
		menuSelectEffect: menuSelectEffect,
		fallDownEffect:   fallDownEffect,
		climbUpEffect:    climbUpEffect,
		pickupItemEffect: pickupItemEffect,
		rockBreakEffect:  rockBreakEffect,
		gameOverEffect:   gameOverEffect,
		victoryEffect:    victoryEffect,
		musicToggle:      1,
	}
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayOutdoorMusic, audioSystem.PlayOutdoorMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayExploreMusic, audioSystem.PlayExploreMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayWarningMusic, audioSystem.PlayWarningMusic)
	audioSystem.exploreMusicObserverId = app.GameEventHandler.AddObserver(PlayDangerMusic, audioSystem.PlayDangerMusic)
	audioSystem.pauseMusicObserverId = app.GameEventHandler.AddObserver(PauseMusic, audioSystem.PauseMusic)
	audioSystem.resumeMusicObserverId = app.GameEventHandler.AddObserver(ResumeMusic, audioSystem.ResumeMusic)
	audioSystem.menuPauseMusicObserverId = app.GameEventHandler.AddObserver(MenuPauseMusic, audioSystem.MenuPauseMusic)
	audioSystem.menuMoveObserverId = app.GameEventHandler.AddObserver(MenuMove, audioSystem.PlayMenuMoveEffect)
	audioSystem.menuSelectObserverId = app.GameEventHandler.AddObserver(MenuSelect, audioSystem.PlayMenuSelectEffect)
	audioSystem.fallDownObserverId = app.GameEventHandler.AddObserver(PlayFallDownEffect, audioSystem.PlayFallDownEffect)
	audioSystem.climbUpObserverId = app.GameEventHandler.AddObserver(PlayClimbUpEffect, audioSystem.PlayClimbUpEffect)
	audioSystem.pickupItemObserverId = app.GameEventHandler.AddObserver(PlayPickupItemEffect, audioSystem.PlayPickupItemEffect)
	audioSystem.rockBreakObserverId = app.GameEventHandler.AddObserver(PlayerDestroyedItem, audioSystem.PlayRockBreakEffect)
	audioSystem.gameOverObserverId = app.GameEventHandler.AddObserver(PlayGameOverEffect, audioSystem.PlayGameOverEffect)
	audioSystem.victoryObserverId = app.GameEventHandler.AddObserver(PlayVictoryEffect, audioSystem.PlayVictoryEffect)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	sdk "github.com/dysolution/espsdk"
)

// A ContributionList contains zero or more Contribtions.
type ContributionList []Contribution

// Unmarshal attempts to deserialize the provided JSON payload into a slice of Contribution objects.
func (cl ContributionList) Unmarshal(payload []byte) sdk.ContributionList {
	return sdk.ContributionList{}.Unmarshal(payload)
}

// A Contribution wraps the verbs provided by the ESP API for Contributions,
// media assets that are associated with a Submission Batch.
type Contribution struct{ context *cli.Context }

// Index requests a list of all Contributions associated with the specified
// Submission Batch.
func (c Contribution) Index() sdk.ContributionList {
	return ContributionList{}.Unmarshal(get(childPath("contributions", c.context, "")))
}

// Get requests the metadata for a specific Contribution.
func (c Contribution) Get() sdk.Contribution {
	return contribution(c.id()).Get(&client, getBatchID(c.context))
}

// Create associates a new Contribution with the specified Submission Batch.
func (c Contribution) Create() sdk.Contribution {
	return sdk.Contribution{}.Create(&client, getBatchID(c.context), c.build())
}

// Update changes metadata for an existing Contribution.
func (c Contribution) Update() sdk.Contribution {
	return contribution(c.id()).Update(&client, getBatchID(c.context), c.buildUpdate())
}

// Delete destroys a specific Contribution.
func (c Contribution) Delete() { contribution(c.id()).Delete(&client, getBatchID(c.context)) }

func (c Contribution) id() int { return getContributionID(c.context) }

func (c Contribution) build() sdk.Contribution {
	return sdk.Contribution{
		CameraShotDate:       c.context.String("camera-shot-date"),
		CollectionCode:       c.context.String("collection-code"),
		ContentProviderName:  c.context.String("content-provider-name"),
		ContentProviderTitle: c.context.String("content-provider-title"),
		CountryOfShoot:       c.context.String("country-of-shoot"),
		CreditLine:           c.context.String("credit-line"),
		ExternalFileLocation: c.context.String("external-file-location"),
		FileName:             c.context.String("file-name"),
		FilePath:             c.context.String("file-path"),
		Headline:             c.context.String("headline"),
		ID:                   c.context.Int("contribution-id"),
		IptcCategory:         c.context.String("iptc-category"),
		MimeType:             c.context.String("mime-type"),
		ParentSource:         c.context.String("parent-source"),
		RecordedDate:         c.context.String("recorded-date"),
		RiskCategory:         c.context.String("risk-category"),
		ShotSpeed:            c.context.String("shot-speed"),
		SiteDestination:      c.context.StringSlice("site-destination"),
		Source:               c.context.String("source"),
		SubmissionBatchID:    c.context.Int("submission-batch-id"),
		SubmittedToReviewAt:  c.context.String("submitted-to-review-at"),
		UploadBucket:         uploadBucket,
		UploadID:             c.context.String("upload-id"),
	}
}

func (c Contribution) buildUpdate() sdk.ContributionUpdate {
	return sdk.ContributionUpdate{c.build()}
}

// Unmarshal attempts to deserialize the provided JSON payload into a Contribution object.
func (c Contribution) Unmarshal(payload []byte) sdk.Contribution {
	return sdk.Contribution{}.Unmarshal(payload)
}
<commit_msg>deprecate childPath<commit_after>package main

import (
	"github.com/codegangsta/cli"
	sdk "github.com/dysolution/espsdk"
)

// A ContributionList contains zero or more Contribtions.
type ContributionList []Contribution

// Unmarshal attempts to deserialize the provided JSON payload into a slice of Contribution objects.
func (cl ContributionList) Unmarshal(payload []byte) sdk.ContributionList {
	return sdk.ContributionList{}.Unmarshal(payload)
}

// A Contribution wraps the verbs provided by the ESP API for Contributions,
// media assets that are associated with a Submission Batch.
type Contribution struct{ context *cli.Context }

// Index requests a list of all Contributions associated with the specified
// Submission Batch.
func (c Contribution) Index() sdk.ContributionList {
	return ContributionList{}.Unmarshal(get(sdk.ContributionPath(getBatchID(c.context), 0)))
}

// Get requests the metadata for a specific Contribution.
func (c Contribution) Get() sdk.Contribution {
	return contribution(c.id()).Get(&client, getBatchID(c.context))
}

// Create associates a new Contribution with the specified Submission Batch.
func (c Contribution) Create() sdk.Contribution {
	return sdk.Contribution{}.Create(&client, getBatchID(c.context), c.build())
}

// Update changes metadata for an existing Contribution.
func (c Contribution) Update() sdk.Contribution {
	return contribution(c.id()).Update(&client, getBatchID(c.context), c.buildUpdate())
}

// Delete destroys a specific Contribution.
func (c Contribution) Delete() { contribution(c.id()).Delete(&client, getBatchID(c.context)) }

func (c Contribution) id() int { return getContributionID(c.context) }

func (c Contribution) build() sdk.Contribution {
	return sdk.Contribution{
		CameraShotDate:       c.context.String("camera-shot-date"),
		CollectionCode:       c.context.String("collection-code"),
		ContentProviderName:  c.context.String("content-provider-name"),
		ContentProviderTitle: c.context.String("content-provider-title"),
		CountryOfShoot:       c.context.String("country-of-shoot"),
		CreditLine:           c.context.String("credit-line"),
		ExternalFileLocation: c.context.String("external-file-location"),
		FileName:             c.context.String("file-name"),
		FilePath:             c.context.String("file-path"),
		Headline:             c.context.String("headline"),
		ID:                   c.context.Int("contribution-id"),
		IptcCategory:         c.context.String("iptc-category"),
		MimeType:             c.context.String("mime-type"),
		ParentSource:         c.context.String("parent-source"),
		RecordedDate:         c.context.String("recorded-date"),
		RiskCategory:         c.context.String("risk-category"),
		ShotSpeed:            c.context.String("shot-speed"),
		SiteDestination:      c.context.StringSlice("site-destination"),
		Source:               c.context.String("source"),
		SubmissionBatchID:    c.context.Int("submission-batch-id"),
		SubmittedToReviewAt:  c.context.String("submitted-to-review-at"),
		UploadBucket:         uploadBucket,
		UploadID:             c.context.String("upload-id"),
	}
}

func (c Contribution) buildUpdate() sdk.ContributionUpdate {
	return sdk.ContributionUpdate{c.build()}
}

// Unmarshal attempts to deserialize the provided JSON payload into a Contribution object.
func (c Contribution) Unmarshal(payload []byte) sdk.Contribution {
	return sdk.Contribution{}.Unmarshal(payload)
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/google/go-github/github"
	"github.com/k8s-community/cicd"
	githubWrap "github.com/k8s-community/github-integration/github"
	userManClient "github.com/k8s-community/user-manager/client"
	"github.com/takama/router"
	githubhook "gopkg.in/rjz/githubhook.v0"
	"github.com/AlekSi/pointer"
	"github.com/k8s-community/github-integration/models"
)

// WebHookHandler is common handler for web hooks (installation, repositories installation, push)
func (h *Handler) WebHookHandler(c *router.Control) {
	secret := []byte(h.Env["GITHUBINT_TOKEN"])

	hook, err := githubhook.Parse(secret, c.Request)
	if err != nil {
		h.Errlog.Printf("cannot parse hook (ID %s): %s", hook.Id, err)
		return
	}

	switch hook.Event {
	case "integration_installation":
		// Triggered when an integration has been installed or uninstalled by user.
		h.Infolog.Printf("initialization web hook (ID %s)", hook.Id)
		err = h.saveInstallation(hook)

	case "integration_installation_repositories":
		// Triggered when a repository is added or removed from an installation.
		h.Infolog.Printf("initialization web hook for user repositories (ID %s)", hook.Id)
		err = h.initialUserManagement(hook)

	case "push":
		// Any Git push to a Repository, including editing tags or branches.
		// Commits via API actions that update references are also counted. This is the default event.
		h.Infolog.Printf("push hook (ID %s)", hook.Id)
		err = h.runCiCdProcess(c, hook)
		if err != nil {
			h.Infolog.Printf("cannot run ci/cd process for hook (ID %s): %s", hook.Id, err)
			c.Code(http.StatusBadRequest).Body(nil)
			return
		}

	default:
		h.Infolog.Printf("not processed hook (ID %s), event = %s", hook.Id, hook.Event)
		c.Code(http.StatusNotFound).Body(nil)
		return
	}

	if err != nil {
		h.Errlog.Printf("cannot process hook (ID %s): %s", hook.Id, err)
		c.Code(http.StatusInternalServerError).Body(nil)
		return
	}

	h.Infolog.Printf("finished to process hook (ID %s)", hook.Id)
	c.Code(http.StatusOK).Body(nil)
}

// initialUserManagement is used for user activation in k8s system
func (h *Handler) initialUserManagement(hook *githubhook.Hook) error {
	evt := github.IntegrationInstallationRepositoriesEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	userManagerURL := h.Env["USERMAN_BASE_URL"]

	client, err := userManClient.NewClient(nil, userManagerURL)
	if err != nil {
		return err
	}

	h.Infolog.Print("Try to activate (sync) user in k8s system: ", *evt.Sender.Login)

	user := userManClient.NewUser(*evt.Sender.Login)

	code, err := client.User.Sync(user)
	if err != nil {
		return err
	}

	h.Infolog.Printf("Service user-man, method sync, returned code: %d", code)

	return nil
}

// runCiCdProcess is used for start CI/CD process for some repository from push hook
func (h *Handler) runCiCdProcess(c *router.Control, hook *githubhook.Hook) error {
	evt := github.PushEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	if !strings.HasPrefix(*evt.Ref, "refs/heads/" + h.Env["GITHUBINT_BRANCH"]) {
		return fmt.Errorf("incorrect branch %s for ci/cd process", *evt.Ref)
	}

	ciCdURL := h.Env["CICD_BASE_URL"]

	client := cicd.NewClient(ciCdURL)

	// set Pending sttatus to Github
	build := &githubWrap.BuildCallback{
		Username:   *evt.Repo.Owner.Name,
		Repository: *evt.Repo.Name,
		CommitHash: *evt.HeadCommit.ID,
		State:      "pending",
		BuildURL:   pointer.ToString("https://k8s.community"), // TODO fix it
		Context: pointer.ToString("k8s-community/cicd"), // move to constant!
		Description: pointer.ToString("Waiting for release..."),
	}
	err = h.updateCommitStatus(c, build)
	if err != nil {
		h.Errlog.Printf("cannot update commit status, build: %+v, err: %s", build, err)
	}

	// run CICD process
	req := &cicd.BuildRequest{
		Username:   *evt.Repo.Owner.Name,
		Repository: *evt.Repo.Name,
		CommitHash: *evt.HeadCommit.ID,
	}

	_, err = client.Build(req)
	if err != nil {
		return fmt.Errorf("cannot run ci/cd process for hook (ID %s): %s", hook.Id, err)
	}

	return nil
}

// saveInstallation saves installation in memory
func (h *Handler) saveInstallation(hook *githubhook.Hook) error {
	evt := github.IntegrationInstallationEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	h.Infolog.Printf("save installation for user %s (installation ID = %d)", *evt.Sender.Login, *evt.Installation.ID)

	// save installation for commit status update
	h.setInstallationID(*evt.Sender.Login, *evt.Installation.ID)

	return nil
}

// installationID gets installation from DB
func (h *Handler) installationID(username string) (*int, error) {
	st, err := h.DB.FindOneFrom(models.InstallationTable, "username", username)
	if err != nil {
		return nil, err
	}
	inst := st.(*models.Installation)

	return pointer.ToInt(inst.InstallationID), nil
}

func (h *Handler) setInstallationID(username string, instID int) error {
	inst := &models.Installation{
		InstallationID: instID,
		Username: username,
	}
	err := h.DB.Save(inst)

	return err
}
<commit_msg>Log more data<commit_after>package handlers

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/google/go-github/github"
	"github.com/k8s-community/cicd"
	githubWrap "github.com/k8s-community/github-integration/github"
	userManClient "github.com/k8s-community/user-manager/client"
	"github.com/takama/router"
	githubhook "gopkg.in/rjz/githubhook.v0"
	"github.com/AlekSi/pointer"
	"github.com/k8s-community/github-integration/models"
)

// WebHookHandler is common handler for web hooks (installation, repositories installation, push)
func (h *Handler) WebHookHandler(c *router.Control) {
	secret := []byte(h.Env["GITHUBINT_TOKEN"])

	hook, err := githubhook.Parse(secret, c.Request)
	if err != nil {
		h.Errlog.Printf("cannot parse hook (ID %s): %s", hook.Id, err)
		return
	}

	switch hook.Event {
	case "integration_installation":
		// Triggered when an integration has been installed or uninstalled by user.
		h.Infolog.Printf("initialization web hook (ID %s)", hook.Id)
		err = h.saveInstallation(hook)

	case "integration_installation_repositories":
		// Triggered when a repository is added or removed from an installation.
		h.Infolog.Printf("initialization web hook for user repositories (ID %s)", hook.Id)
		err = h.initialUserManagement(hook)

	case "push":
		// Any Git push to a Repository, including editing tags or branches.
		// Commits via API actions that update references are also counted. This is the default event.
		h.Infolog.Printf("push hook (ID %s)", hook.Id)
		err = h.runCiCdProcess(c, hook)
		if err != nil {
			h.Infolog.Printf("cannot run ci/cd process for hook (ID %s): %s", hook.Id, err)
			c.Code(http.StatusBadRequest).Body(nil)
			return
		}

	default:
		h.Infolog.Printf("not processed hook (ID %s), event = %s", hook.Id, hook.Event)
		c.Code(http.StatusNotFound).Body(nil)
		return
	}

	if err != nil {
		h.Errlog.Printf("cannot process hook (ID %s): %s", hook.Id, err)
		c.Code(http.StatusInternalServerError).Body(nil)
		return
	}

	h.Infolog.Printf("finished to process hook (ID %s)", hook.Id)
	c.Code(http.StatusOK).Body(nil)
}

// initialUserManagement is used for user activation in k8s system
func (h *Handler) initialUserManagement(hook *githubhook.Hook) error {
	evt := github.IntegrationInstallationRepositoriesEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	userManagerURL := h.Env["USERMAN_BASE_URL"]

	client, err := userManClient.NewClient(nil, userManagerURL)
	if err != nil {
		return err
	}

	h.Infolog.Print("Try to activate (sync) user in k8s system: ", *evt.Sender.Login)

	user := userManClient.NewUser(*evt.Sender.Login)

	code, err := client.User.Sync(user)
	if err != nil {
		return err
	}

	h.Infolog.Printf("Service user-man, method sync, returned code: %d", code)

	return nil
}

// runCiCdProcess is used for start CI/CD process for some repository from push hook
func (h *Handler) runCiCdProcess(c *router.Control, hook *githubhook.Hook) error {
	evt := github.PushEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	if !strings.HasPrefix(*evt.Ref, "refs/heads/" + h.Env["GITHUBINT_BRANCH"]) {
		return fmt.Errorf("incorrect branch %s for ci/cd process", *evt.Ref)
	}

	ciCdURL := h.Env["CICD_BASE_URL"]

	client := cicd.NewClient(ciCdURL)

	// set Pending sttatus to Github
	build := &githubWrap.BuildCallback{
		Username:   *evt.Repo.Owner.Name,
		Repository: *evt.Repo.Name,
		CommitHash: *evt.HeadCommit.ID,
		State:      "pending",
		BuildURL:   pointer.ToString("https://k8s.community"), // TODO fix it
		Context: pointer.ToString("k8s-community/cicd"), // move to constant!
		Description: pointer.ToString("Waiting for release..."),
	}
	err = h.updateCommitStatus(c, build)
	if err != nil {
		h.Errlog.Printf("cannot update commit status, build: %+v, err: %s", build, err)
	}

	// run CICD process
	req := &cicd.BuildRequest{
		Username:   *evt.Repo.Owner.Name,
		Repository: *evt.Repo.Name,
		CommitHash: *evt.HeadCommit.ID,
	}

	_, err = client.Build(req)
	if err != nil {
		return fmt.Errorf("cannot run ci/cd process for hook (ID %s): %s", hook.Id, err)
	}

	return nil
}

// saveInstallation saves installation in memory
func (h *Handler) saveInstallation(hook *githubhook.Hook) error {
	evt := github.IntegrationInstallationEvent{}

	err := hook.Extract(&evt)
	if err != nil {
		return err
	}

	h.Infolog.Printf("save installation for user %s (installation ID = %d)", *evt.Sender.Login, *evt.Installation.ID)

	// save installation for commit status update
	err = h.setInstallationID(*evt.Sender.Login, *evt.Installation.ID)
	if err != nil {
		h.Errlog.Printf("Couldn't save installation: %+v", err)
	}

	return nil
}

// installationID gets installation from DB
func (h *Handler) installationID(username string) (*int, error) {
	st, err := h.DB.FindOneFrom(models.InstallationTable, "username", username)
	if err != nil {
		return nil, err
	}
	inst := st.(*models.Installation)

	return pointer.ToInt(inst.InstallationID), nil
}

func (h *Handler) setInstallationID(username string, instID int) error {
	inst := &models.Installation{
		InstallationID: instID,
		Username: username,
	}
	err := h.DB.Save(inst)

	return err
}
<|endoftext|>


<commit_before>package main
import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"mig"
	"mig/modules/filechecker"
	"mig/pgp"
	"os"
	"time"
)

func main() {

	var Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Mozilla InvestiGator Action Generator\n" +
			"usage: %s -k=<key id> (-i <input file)\n\n" +
			"Command line to generate and sign MIG Actions.\n" +
			"The resulting actions are display on stdout.\n\n" +
			"Options:\n",
			os.Args[0])
		flag.PrintDefaults()
	}

	// command line options
	var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)")
	var file = flag.String("i", "/path/to/file", "Load action from file")
	flag.Parse()

	// We need a key, if none is set on the command line, fail
	if *key == "key identifier" {
		Usage()
		os.Exit(-1)
	}

	var ea mig.ExtendedAction
	var err error
	if *file != "/path/to/file" {
		// get action from local json file
		ea, err = mig.ActionFromFile(*file)
	} else {
		//interactive mode
		ea, err = getActionFromTerminal()
	}
	if err != nil {
		panic(err)
	}
	a := ea.Action

	// compute the signature
	str, err := a.String()
	if err != nil {
		panic(err)
	}
	a.PGPSignature, err = pgp.Sign(str, *key)
	if err != nil {
		panic(err)
	}

	a.PGPSignatureDate = time.Now().UTC()

	jsonAction, err := json.MarshalIndent(a, "", "\t")
	if err != nil {
		panic(err)
	}

	// Verify the GPG signature
	str2, err := a.String()
	if err != nil {
		panic(err)
	}
	valid, _, err := pgp.Verify(str2, a.PGPSignature)
	if err != nil {
		panic(err)
	}
	if !valid {
		panic("Invalid PGP Signature")
	}

	fmt.Printf("%s\n", jsonAction)
}

func getActionFromTerminal() (ea mig.ExtendedAction, err error) {
	err = nil
	fmt.Print("Action name> ")
	_, err = fmt.Scanln(&ea.Action.Name)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Target> ")
	_, err = fmt.Scanln(&ea.Action.Target)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Check> ")
	_, err = fmt.Scanln(&ea.Action.Check)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Expiration> ")
	var expiration string
	_, err = fmt.Scanln(&expiration)
	if err != nil {
		panic(err)
	}
	ea.Action.ScheduledDate = time.Now().UTC()
	period, err := time.ParseDuration(expiration)
	if err != nil {
		log.Fatal(err)
	}
	ea.Action.ExpirationDate = time.Now().UTC().Add(period)

	var checkArgs string
	switch ea.Action.Check {
	default:
		fmt.Print("Unknown check type, supply JSON arguments> ")
		_, err := fmt.Scanln(&checkArgs)
		if err != nil {
			panic(err)
		}
		err = json.Unmarshal([]byte(checkArgs), ea.Action.Arguments)
		if err != nil {
			panic(err)
		}
	case "filechecker":
		fmt.Println("Filechecker module parameters")
		var name string
		var fcargs filechecker.FileCheck
		fmt.Print("Check Name> ")
		_, err := fmt.Scanln(&name)
		if err != nil {
			panic(err)
		}
		fmt.Print("Filechecker Type> ")
		_, err = fmt.Scanln(&fcargs.Type)
		if err != nil {
			panic(err)
		}
		fmt.Print("File Path> ")
		_, err = fmt.Scanln(&fcargs.Path)
		if err != nil {
			panic(err)
		}
		fmt.Print("Check Value> ")
		_, err = fmt.Scanln(&fcargs.Value)
		if err != nil {
			panic(err)
		}
		fc := make(map[string]filechecker.FileCheck)
		fc[name] = fcargs
		ea.Action.Arguments = fc
	}
	return
}

<commit_msg>Mig-action-generator: use Validate() instead of doing it manually<commit_after>package main
import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"mig"
	"mig/modules/filechecker"
	"mig/pgp/sign"
	"os"
	"time"
)

func main() {

	var Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Mozilla InvestiGator Action Generator\n" +
			"usage: %s -k=<key id> (-i <input file)\n\n" +
			"Command line to generate and sign MIG Actions.\n" +
			"The resulting actions are display on stdout.\n\n" +
			"Options:\n",
			os.Args[0])
		flag.PrintDefaults()
	}

	// command line options
	var key = flag.String("k", "key identifier", "Key identifier used to sign the action (ex: B75C2346)")
	var file = flag.String("i", "/path/to/file", "Load action from file")
	flag.Parse()

	// We need a key, if none is set on the command line, fail
	if *key == "key identifier" {
		Usage()
		os.Exit(-1)
	}

	var ea mig.ExtendedAction
	var err error
	if *file != "/path/to/file" {
		// get action from local json file
		ea, err = mig.ActionFromFile(*file)
	} else {
		//interactive mode
		ea, err = getActionFromTerminal()
	}
	if err != nil {
		panic(err)
	}
	a := ea.Action

	// compute the signature
	str, err := a.String()
	if err != nil {
		panic(err)
	}
	a.PGPSignature, err = sign.Sign(str, *key)
	if err != nil {
		panic(err)
	}

	a.PGPSignatureDate = time.Now().UTC()

	jsonAction, err := json.MarshalIndent(a, "", "\t")
	if err != nil {
		panic(err)
	}

	// syntax checking
	err = a.Validate()
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", jsonAction)
}

func getActionFromTerminal() (ea mig.ExtendedAction, err error) {
	err = nil
	fmt.Print("Action name> ")
	_, err = fmt.Scanln(&ea.Action.Name)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Target> ")
	_, err = fmt.Scanln(&ea.Action.Target)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Check> ")
	_, err = fmt.Scanln(&ea.Action.Check)
	if err != nil {
		panic(err)
	}
	fmt.Print("Action Expiration> ")
	var expiration string
	_, err = fmt.Scanln(&expiration)
	if err != nil {
		panic(err)
	}
	ea.Action.ScheduledDate = time.Now().UTC()
	period, err := time.ParseDuration(expiration)
	if err != nil {
		log.Fatal(err)
	}
	ea.Action.ExpirationDate = time.Now().UTC().Add(period)

	var checkArgs string
	switch ea.Action.Check {
	default:
		fmt.Print("Unknown check type, supply JSON arguments> ")
		_, err := fmt.Scanln(&checkArgs)
		if err != nil {
			panic(err)
		}
		err = json.Unmarshal([]byte(checkArgs), ea.Action.Arguments)
		if err != nil {
			panic(err)
		}
	case "filechecker":
		fmt.Println("Filechecker module parameters")
		var name string
		var fcargs filechecker.FileCheck
		fmt.Print("Check Name> ")
		_, err := fmt.Scanln(&name)
		if err != nil {
			panic(err)
		}
		fmt.Print("Filechecker Type> ")
		_, err = fmt.Scanln(&fcargs.Type)
		if err != nil {
			panic(err)
		}
		fmt.Print("File Path> ")
		_, err = fmt.Scanln(&fcargs.Path)
		if err != nil {
			panic(err)
		}
		fmt.Print("Check Value> ")
		_, err = fmt.Scanln(&fcargs.Value)
		if err != nil {
			panic(err)
		}
		fc := make(map[string]filechecker.FileCheck)
		fc[name] = fcargs
		ea.Action.Arguments = fc
	}
	return
}

<|endoftext|>


<commit_before>package mpawsec2cpucredit

import (
	"errors"
	"flag"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

var graphdef = map[string]mp.Graphs{
	"ec2.cpucredit": {
		Label: "EC2 CPU Credit",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "usage", Label: "Usage", Diff: false},
			{Name: "balance", Label: "Balance", Diff: false},
		},
	},
}

// CPUCreditPlugin is a mackerel plugin
type CPUCreditPlugin struct {
	Region          string
	AccessKeyID     string
	SecretAccessKey string
	InstanceID      string
}

func getLastPointAverage(cw *cloudwatch.CloudWatch, dimension *cloudwatch.Dimension, metricName string) (float64, error) {
	namespace := "AWS/EC2"
	now := time.Now()
	prev := now.Add(time.Duration(600) * time.Second * -1) // 10 min (to fetch at least 1 data-point)

	input := &cloudwatch.GetMetricStatisticsInput{
		Dimensions: []*cloudwatch.Dimension{dimension},
		EndTime:    aws.Time(now),
		StartTime:  aws.Time(prev),
		MetricName: aws.String(metricName),
		Period:     aws.Int64(60),
		Statistics: []*string{aws.String("Average")},
		Namespace:  aws.String(namespace),
	}

	response, err := cw.GetMetricStatistics(input)
	if err != nil {
		return 0, err
	}

	datapoints := response.Datapoints
	if len(datapoints) == 0 {
		return 0, errors.New("fetched no datapoints")
	}

	latest := new(time.Time)
	var latestVal float64
	for _, dp := range datapoints {
		if dp.Timestamp.Before(*latest) {
			continue
		}

		latest = dp.Timestamp
		latestVal = *dp.Average
	}

	return latestVal, nil
}

// FetchMetrics fetch the metrics
func (p CPUCreditPlugin) FetchMetrics() (map[string]float64, error) {
	sess, err := session.NewSession()
	if err != nil {
		return nil, err
	}

	config := aws.NewConfig()
	if p.AccessKeyID != "" && p.SecretAccessKey != "" {
		config = config.WithCredentials(credentials.NewStaticCredentials(p.AccessKeyID, p.SecretAccessKey, ""))
	}
	if p.Region != "" {
		config = config.WithRegion(p.Region)
	}

	cw := cloudwatch.New(sess, config)

	dimension := &cloudwatch.Dimension{
		Name:  aws.String("InstanceId"),
		Value: aws.String(p.InstanceID),
	}

	stat := make(map[string]float64)

	stat["usage"], err = getLastPointAverage(cw, dimension, "CPUCreditUsage")
	if err != nil {
		return nil, err
	}

	stat["balance"], err = getLastPointAverage(cw, dimension, "CPUCreditBalance")
	if err != nil {
		return nil, err
	}

	return stat, nil
}

// GraphDefinition for plugin
func (p CPUCreditPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

// Do the plugin
func Do() {
	optRegion := flag.String("region", "", "AWS Region")
	optInstanceID := flag.String("instance-id", "", "Instance ID")
	optAccessKeyID := flag.String("access-key-id", "", "AWS Access Key ID")
	optSecretAccessKey := flag.String("secret-access-key", "", "AWS Secret Access Key")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	var cpucredit CPUCreditPlugin

	if *optRegion == "" || *optInstanceID == "" {
		ec2metadata := ec2metadata.New(session.New())
		if ec2metadata.Available() {
			cpucredit.Region, _ = ec2metadata.Region()
			cpucredit.InstanceID, _ = ec2metadata.GetMetadata("instance-id")
		}
	} else {
		cpucredit.Region = *optRegion
		cpucredit.InstanceID = *optInstanceID
	}

	cpucredit.AccessKeyID = *optAccessKeyID
	cpucredit.SecretAccessKey = *optSecretAccessKey

	helper := mp.NewMackerelPlugin(cpucredit)
	helper.Tempfile = *optTempfile

	helper.Run()
}
<commit_msg>[aws-ec2-cpucredit] Add T2 unlimited CPU credit metrics<commit_after>package mpawsec2cpucredit

import (
	"errors"
	"flag"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

var graphdef = map[string]mp.Graphs{
	"ec2.cpucredit": {
		Label: "EC2 CPU Credit",
		Unit:  "float",
		Metrics: []mp.Metrics{
			{Name: "usage", Label: "Usage", Diff: false},
			{Name: "balance", Label: "Balance", Diff: false},
			{Name: "surplus_balance", Label: "Surplus Usage", Diff: false},
			{Name: "surplus_charged", Label: "Surplus Charged", Diff: false},
		},
	},
}

// CPUCreditPlugin is a mackerel plugin
type CPUCreditPlugin struct {
	Region          string
	AccessKeyID     string
	SecretAccessKey string
	InstanceID      string
}

func getLastPointAverage(cw *cloudwatch.CloudWatch, dimension *cloudwatch.Dimension, metricName string) (float64, error) {
	namespace := "AWS/EC2"
	now := time.Now()
	prev := now.Add(time.Duration(600) * time.Second * -1) // 10 min (to fetch at least 1 data-point)

	input := &cloudwatch.GetMetricStatisticsInput{
		Dimensions: []*cloudwatch.Dimension{dimension},
		EndTime:    aws.Time(now),
		StartTime:  aws.Time(prev),
		MetricName: aws.String(metricName),
		Period:     aws.Int64(60),
		Statistics: []*string{aws.String("Average")},
		Namespace:  aws.String(namespace),
	}

	response, err := cw.GetMetricStatistics(input)
	if err != nil {
		return 0, err
	}

	datapoints := response.Datapoints
	if len(datapoints) == 0 {
		return 0, errors.New("fetched no datapoints")
	}

	latest := new(time.Time)
	var latestVal float64
	for _, dp := range datapoints {
		if dp.Timestamp.Before(*latest) {
			continue
		}

		latest = dp.Timestamp
		latestVal = *dp.Average
	}

	return latestVal, nil
}

// FetchMetrics fetch the metrics
func (p CPUCreditPlugin) FetchMetrics() (map[string]float64, error) {
	sess, err := session.NewSession()
	if err != nil {
		return nil, err
	}

	config := aws.NewConfig()
	if p.AccessKeyID != "" && p.SecretAccessKey != "" {
		config = config.WithCredentials(credentials.NewStaticCredentials(p.AccessKeyID, p.SecretAccessKey, ""))
	}
	if p.Region != "" {
		config = config.WithRegion(p.Region)
	}

	cw := cloudwatch.New(sess, config)

	dimension := &cloudwatch.Dimension{
		Name:  aws.String("InstanceId"),
		Value: aws.String(p.InstanceID),
	}

	stat := make(map[string]float64)

	stat["usage"], err = getLastPointAverage(cw, dimension, "CPUCreditUsage")
	if err != nil {
		return nil, err
	}

	stat["balance"], err = getLastPointAverage(cw, dimension, "CPUCreditBalance")
	if err != nil {
		return nil, err
	}

	stat["surplus_balance"], err = getLastPointAverage(cw, dimension, "CPUSurplusCreditBalance")
	if err != nil {
		return nil, err
	}

	stat["surplus_charged"], err = getLastPointAverage(cw, dimension, "CPUSurplusCreditsCharged")
	if err != nil {
		return nil, err
	}

	return stat, nil
}

// GraphDefinition for plugin
func (p CPUCreditPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

// Do the plugin
func Do() {
	optRegion := flag.String("region", "", "AWS Region")
	optInstanceID := flag.String("instance-id", "", "Instance ID")
	optAccessKeyID := flag.String("access-key-id", "", "AWS Access Key ID")
	optSecretAccessKey := flag.String("secret-access-key", "", "AWS Secret Access Key")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()

	var cpucredit CPUCreditPlugin

	if *optRegion == "" || *optInstanceID == "" {
		ec2metadata := ec2metadata.New(session.New())
		if ec2metadata.Available() {
			cpucredit.Region, _ = ec2metadata.Region()
			cpucredit.InstanceID, _ = ec2metadata.GetMetadata("instance-id")
		}
	} else {
		cpucredit.Region = *optRegion
		cpucredit.InstanceID = *optInstanceID
	}

	cpucredit.AccessKeyID = *optAccessKeyID
	cpucredit.SecretAccessKey = *optSecretAccessKey

	helper := mp.NewMackerelPlugin(cpucredit)
	helper.Tempfile = *optTempfile

	helper.Run()
}
<|endoftext|>


<commit_before>package protocol

import (
	log "github.com/sirupsen/logrus"

	"github.com/bytom/errors"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
	"github.com/bytom/protocol/state"
	"github.com/bytom/protocol/validation"
)

var (
	// ErrBadBlock is returned when a block is invalid.
	ErrBadBlock = errors.New("invalid block")
	// ErrBadStateRoot is returned when the computed assets merkle root
	// disagrees with the one declared in a block header.
	ErrBadStateRoot = errors.New("invalid state merkle root")
)

// BlockExist check is a block in chain or orphan
func (c *Chain) BlockExist(hash *bc.Hash) bool {
	return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
}

// GetBlockByHash return a block by given hash
func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
	return c.store.GetBlock(hash)
}

// GetBlockByHeight return a block by given height
func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
	node := c.index.NodeByHeight(height)
	if node == nil {
		return nil, errors.New("can't find block in given hight")
	}
	return c.store.GetBlock(&node.Hash)
}

func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
	var attachNodes []*state.BlockNode
	var detachNodes []*state.BlockNode

	attachNode := node
	for c.index.NodeByHeight(attachNode.Height) != attachNode {
		attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
		attachNode = attachNode.Parent
	}

	detachNode := c.bestNode
	for detachNode != attachNode {
		detachNodes = append(detachNodes, detachNode)
		detachNode = detachNode.Parent
	}
	return attachNodes, detachNodes
}

func (c *Chain) connectBlock(block *types.Block) (err error) {
	bcBlock := types.MapBlock(block)
	if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
		return err
	}

	utxoView := state.NewUtxoViewpoint()
	if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
		return err
	}
	if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
		return err
	}

	node := c.index.GetNode(&bcBlock.ID)
	if err := c.setState(node, utxoView); err != nil {
		return err
	}

	for _, tx := range block.Transactions {
		c.txPool.RemoveTransaction(&tx.Tx.ID)
	}
	return nil
}

func (c *Chain) reorganizeChain(node *state.BlockNode) error {
	attachNodes, detachNodes := c.calcReorganizeNodes(node)
	utxoView := state.NewUtxoViewpoint()

	for _, detachNode := range detachNodes {
		b, err := c.store.GetBlock(&detachNode.Hash)
		if err != nil {
			return err
		}

		detachBlock := types.MapBlock(b)
		if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
			return err
		}
		txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
		if err != nil {
			return err
		}
		if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
			return err
		}

		log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
	}

	for _, attachNode := range attachNodes {
		b, err := c.store.GetBlock(&attachNode.Hash)
		if err != nil {
			return err
		}

		attachBlock := types.MapBlock(b)
		if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
			return err
		}
		txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
		if err != nil {
			return err
		}
		if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
			return err
		}

		log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
	}

	return c.setState(node, utxoView)
}

// SaveBlock will validate and save block into storage
func (c *Chain) saveBlock(block *types.Block) error {
	bcBlock := types.MapBlock(block)
	parent := c.index.GetNode(&block.PreviousBlockHash)

	if err := validation.ValidateBlock(bcBlock, parent); err != nil {
		return errors.Sub(ErrBadBlock, err)
	}
	if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
		return err
	}

	c.orphanManage.Delete(&bcBlock.ID)
	node, err := state.NewBlockNode(&block.BlockHeader, parent)
	if err != nil {
		return err
	}

	c.index.AddNode(node)
	return nil
}

func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
	blockHash := block.Hash()
	prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
	if !ok {
		return block
	}

	bestBlock := block
	for _, prevOrphan := range prevOrphans {
		orphanBlock, ok := c.orphanManage.Get(prevOrphan)
		if !ok {
			log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
			continue
		}
		if err := c.saveBlock(orphanBlock); err != nil {
			log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
			continue
		}

		if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
			bestBlock = subBestBlock
		}
	}
	return bestBlock
}

type processBlockResponse struct {
	isOrphan bool
	err      error
}

type processBlockMsg struct {
	block *types.Block
	reply chan processBlockResponse
}

// ProcessBlock is the entry for chain update
func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
	reply := make(chan processBlockResponse, 1)
	c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
	response := <-reply
	return response.isOrphan, response.err
}

func (c *Chain) blockProcesser() {
	for msg := range c.processBlockCh {
		isOrphan, err := c.processBlock(msg.block)
		msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
	}
}

// ProcessBlock is the entry for handle block insert
func (c *Chain) processBlock(block *types.Block) (bool, error) {
	blockHash := block.Hash()
	if c.BlockExist(&blockHash) {
		log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
		return c.orphanManage.BlockExist(&blockHash), nil
	}

	if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
		c.orphanManage.Add(block)
		return true, nil
	}

	if err := c.saveBlock(block); err != nil {
		return false, err
	}

	bestBlock := c.saveSubBlock(block)
	bestBlockHash := bestBlock.Hash()
	bestNode := c.index.GetNode(&bestBlockHash)

	if bestNode.Parent == c.bestNode {
		log.Debug("append block to the end of mainchain")
		return false, c.connectBlock(bestBlock)
	}

	if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 {
		log.Debug("start to reorganize chain")
		return false, c.reorganizeChain(bestNode)
	}
	return false, nil
}
<commit_msg>fix word spell<commit_after>package protocol

import (
	log "github.com/sirupsen/logrus"

	"github.com/bytom/errors"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
	"github.com/bytom/protocol/state"
	"github.com/bytom/protocol/validation"
)

var (
	// ErrBadBlock is returned when a block is invalid.
	ErrBadBlock = errors.New("invalid block")
	// ErrBadStateRoot is returned when the computed assets merkle root
	// disagrees with the one declared in a block header.
	ErrBadStateRoot = errors.New("invalid state merkle root")
)

// BlockExist check is a block in chain or orphan
func (c *Chain) BlockExist(hash *bc.Hash) bool {
	return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash)
}

// GetBlockByHash return a block by given hash
func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) {
	return c.store.GetBlock(hash)
}

// GetBlockByHeight return a block by given height
func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
	node := c.index.NodeByHeight(height)
	if node == nil {
		return nil, errors.New("can't find block in given height")
	}
	return c.store.GetBlock(&node.Hash)
}

func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
	var attachNodes []*state.BlockNode
	var detachNodes []*state.BlockNode

	attachNode := node
	for c.index.NodeByHeight(attachNode.Height) != attachNode {
		attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...)
		attachNode = attachNode.Parent
	}

	detachNode := c.bestNode
	for detachNode != attachNode {
		detachNodes = append(detachNodes, detachNode)
		detachNode = detachNode.Parent
	}
	return attachNodes, detachNodes
}

func (c *Chain) connectBlock(block *types.Block) (err error) {
	bcBlock := types.MapBlock(block)
	if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil {
		return err
	}

	utxoView := state.NewUtxoViewpoint()
	if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
		return err
	}
	if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
		return err
	}

	node := c.index.GetNode(&bcBlock.ID)
	if err := c.setState(node, utxoView); err != nil {
		return err
	}

	for _, tx := range block.Transactions {
		c.txPool.RemoveTransaction(&tx.Tx.ID)
	}
	return nil
}

func (c *Chain) reorganizeChain(node *state.BlockNode) error {
	attachNodes, detachNodes := c.calcReorganizeNodes(node)
	utxoView := state.NewUtxoViewpoint()

	for _, detachNode := range detachNodes {
		b, err := c.store.GetBlock(&detachNode.Hash)
		if err != nil {
			return err
		}

		detachBlock := types.MapBlock(b)
		if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil {
			return err
		}
		txStatus, err := c.GetTransactionStatus(&detachBlock.ID)
		if err != nil {
			return err
		}
		if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil {
			return err
		}

		log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
	}

	for _, attachNode := range attachNodes {
		b, err := c.store.GetBlock(&attachNode.Hash)
		if err != nil {
			return err
		}

		attachBlock := types.MapBlock(b)
		if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil {
			return err
		}
		txStatus, err := c.GetTransactionStatus(&attachBlock.ID)
		if err != nil {
			return err
		}
		if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil {
			return err
		}

		log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
	}

	return c.setState(node, utxoView)
}

// SaveBlock will validate and save block into storage
func (c *Chain) saveBlock(block *types.Block) error {
	bcBlock := types.MapBlock(block)
	parent := c.index.GetNode(&block.PreviousBlockHash)

	if err := validation.ValidateBlock(bcBlock, parent); err != nil {
		return errors.Sub(ErrBadBlock, err)
	}
	if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
		return err
	}

	c.orphanManage.Delete(&bcBlock.ID)
	node, err := state.NewBlockNode(&block.BlockHeader, parent)
	if err != nil {
		return err
	}

	c.index.AddNode(node)
	return nil
}

func (c *Chain) saveSubBlock(block *types.Block) *types.Block {
	blockHash := block.Hash()
	prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash)
	if !ok {
		return block
	}

	bestBlock := block
	for _, prevOrphan := range prevOrphans {
		orphanBlock, ok := c.orphanManage.Get(prevOrphan)
		if !ok {
			log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
			continue
		}
		if err := c.saveBlock(orphanBlock); err != nil {
			log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
			continue
		}

		if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height {
			bestBlock = subBestBlock
		}
	}
	return bestBlock
}

type processBlockResponse struct {
	isOrphan bool
	err      error
}

type processBlockMsg struct {
	block *types.Block
	reply chan processBlockResponse
}

// ProcessBlock is the entry for chain update
func (c *Chain) ProcessBlock(block *types.Block) (bool, error) {
	reply := make(chan processBlockResponse, 1)
	c.processBlockCh <- &processBlockMsg{block: block, reply: reply}
	response := <-reply
	return response.isOrphan, response.err
}

func (c *Chain) blockProcesser() {
	for msg := range c.processBlockCh {
		isOrphan, err := c.processBlock(msg.block)
		msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
	}
}

// ProcessBlock is the entry for handle block insert
func (c *Chain) processBlock(block *types.Block) (bool, error) {
	blockHash := block.Hash()
	if c.BlockExist(&blockHash) {
		log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
		return c.orphanManage.BlockExist(&blockHash), nil
	}

	if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil {
		c.orphanManage.Add(block)
		return true, nil
	}

	if err := c.saveBlock(block); err != nil {
		return false, err
	}

	bestBlock := c.saveSubBlock(block)
	bestBlockHash := bestBlock.Hash()
	bestNode := c.index.GetNode(&bestBlockHash)

	if bestNode.Parent == c.bestNode {
		log.Debug("append block to the end of mainchain")
		return false, c.connectBlock(bestBlock)
	}

	if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 {
		log.Debug("start to reorganize chain")
		return false, c.reorganizeChain(bestNode)
	}
	return false, nil
}
<|endoftext|>


<commit_before>/*
	Pulls data from multiple sources and funnels into metrics.
*/

package main

import (
	"context"
	"flag"
	"fmt"
	"path/filepath"
	"regexp"
	"time"

	"cloud.google.com/go/bigtable"
	"cloud.google.com/go/datastore"
	"cloud.google.com/go/storage"
	"go.skia.org/infra/datahopper/go/bot_metrics"
	"go.skia.org/infra/datahopper/go/supported_branches"
	"go.skia.org/infra/datahopper/go/swarming_metrics"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/common"
	"go.skia.org/infra/go/gcs"
	"go.skia.org/infra/go/git"
	"go.skia.org/infra/go/git/repograph"
	"go.skia.org/infra/go/gitauth"
	"go.skia.org/infra/go/gitstore"
	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/metrics2"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/go/swarming"
	"go.skia.org/infra/go/taskname"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/perf/go/perfclient"
	"go.skia.org/infra/task_scheduler/go/db/firestore"
	"go.skia.org/infra/task_scheduler/go/db/pubsub"
	"go.skia.org/infra/task_scheduler/go/task_cfg_cache"
	"google.golang.org/api/option"
)

// flags
var (
	// TODO(borenet): Combine btInstance, firestoreInstance, and
	// pubsubTopicSet.
	btInstance        = flag.String("bigtable_instance", "", "BigTable instance to use.")
	btProject         = flag.String("bigtable_project", "", "GCE project to use for BigTable.")
	firestoreInstance = flag.String("firestore_instance", "", "Firestore instance to use, eg. \"production\"")
	gitstoreTable     = flag.String("gitstore_bt_table", "git-repos", "BigTable table used for GitStore.")
	local             = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
	perfBucket        = flag.String("perf_bucket", "skia-perf", "The GCS bucket that should be used for writing into perf")
	perfPrefix        = flag.String("perf_duration_prefix", "task-duration", "The folder name in the bucket that task duration metric should be written.")
	port              = flag.String("port", ":8000", "HTTP service port for the health check server (e.g., ':8000')")
	promPort          = flag.String("prom_port", ":20000", "Metrics service address (e.g., ':10110')")
	pubsubProject     = flag.String("pubsub_project", "", "GCE project to use for PubSub.")
	pubsubTopicSet    = flag.String("pubsub_topic_set", "", fmt.Sprintf("Pubsub topic set; one of: %v", pubsub.VALID_TOPIC_SETS))
	repoUrls          = common.NewMultiStringFlag("repo", nil, "Repositories to query for status.")
	swarmingServer    = flag.String("swarming_server", "", "Host name of the Swarming server.")
	swarmingPools     = common.NewMultiStringFlag("swarming_pool", nil, "Swarming pools to use.")
	workdir           = flag.String("workdir", ".", "Working directory used by data processors.")
)

var (
	// Regexp matching non-alphanumeric characters.
	re = regexp.MustCompile("[^A-Za-z0-9]+")

	BUILDSLAVE_OFFLINE_BLACKLIST = []string{
		"build3-a3",
		"build4-a3",
		"vm255-m3",
	}
)

func main() {
	common.InitWithMust(
		"datahopper",
		common.PrometheusOpt(promPort),
		common.MetricsLoggingOpt(),
	)
	ctx := context.Background()

	// Absolutify the workdir.
	w, err := filepath.Abs(*workdir)
	if err != nil {
		sklog.Fatal(w)
	}
	sklog.Infof("Workdir is %s", w)

	// OAuth2.0 TokenSource.
	ts, err := auth.NewDefaultTokenSource(*local, auth.SCOPE_USERINFO_EMAIL, pubsub.AUTH_SCOPE, bigtable.Scope, datastore.ScopeDatastore, swarming.AUTH_SCOPE, auth.SCOPE_READ_WRITE)
	if err != nil {
		sklog.Fatal(err)
	}

	// Authenticated HTTP client.
	httpClient := httputils.DefaultClientConfig().WithTokenSource(ts).With2xxOnly().Client()

	// Various API clients.
	gsClient, err := storage.NewClient(ctx, option.WithHTTPClient(httpClient))
	if err != nil {
		sklog.Fatal(err)
	}
	storageClient := gcs.NewGCSClient(gsClient, *perfBucket)
	pc := perfclient.New(*perfPrefix, storageClient)

	tnp := taskname.DefaultTaskNameParser()

	// Shared repo objects.
	if *repoUrls == nil {
		sklog.Fatal("At least one --repo is required.")
	}
	btConf := &gitstore.BTConfig{
		ProjectID:  *btProject,
		InstanceID: *btInstance,
		TableID:    *gitstoreTable,
	}
	repos, err := repograph.NewBTGitStoreMap(ctx, *repoUrls, btConf)
	if err != nil {
		sklog.Fatal(err)
	}
	lvRepos := metrics2.NewLiveness("datahopper_repo_update")
	go util.RepeatCtx(time.Minute, ctx, func() {
		if err := repos.Update(ctx); err != nil {
			sklog.Errorf("Failed to update repos: %s", err)
		} else {
			lvRepos.Reset()
		}
	})

	// TaskCfgCache.
	tcc, err := task_cfg_cache.NewTaskCfgCache(ctx, repos, *btProject, *btInstance, ts)
	if err != nil {
		sklog.Fatalf("Failed to create TaskCfgCache: %s", err)
	}
	go util.RepeatCtx(30*time.Minute, ctx, func() {
		if err := tcc.Cleanup(ctx, OVERDUE_JOB_METRICS_PERIOD); err != nil {
			sklog.Errorf("Failed to cleanup TaskCfgCache: %s", err)
		}
	})

	// Data generation goroutines.

	// Swarming bots.
	swarmClient, err := swarming.NewApiClient(httpClient, *swarmingServer)
	if err != nil {
		sklog.Fatal(err)
	}
	swarming_metrics.StartSwarmingBotMetrics(ctx, *swarmingServer, *swarmingPools, swarmClient, metrics2.GetDefaultClient())

	// Swarming tasks.
	if err := swarming_metrics.StartSwarmingTaskMetrics(ctx, *btProject, *btInstance, swarmClient, *swarmingPools, pc, tnp, ts); err != nil {
		sklog.Fatal(err)
	}

	// Number of commits in the repo.
	go func() {
		for range time.Tick(5 * time.Minute) {
			for repoUrl, repo := range repos {
				normUrl, err := git.NormalizeURL(repoUrl)
				if err != nil {
					sklog.Fatal(err)
				}
				tags := map[string]string{"repo": normUrl}
				metrics2.GetInt64Metric("repo_commits", tags).Update(int64(repo.Len()))
			}
		}
	}()

	// Tasks metrics.
	label := "datahopper"
	mod, err := pubsub.NewModifiedData(*pubsubProject, *pubsubTopicSet, label, ts)
	if err != nil {
		sklog.Fatal(err)
	}
	d, err := firestore.NewDB(ctx, firestore.FIRESTORE_PROJECT, *firestoreInstance, ts, mod)
	if err != nil {
		sklog.Fatalf("Failed to create Firestore DB client: %s", err)
	}
	if err := StartTaskMetrics(ctx, d, *firestoreInstance); err != nil {
		sklog.Fatal(err)
	}

	// Jobs metrics.
	if err := StartJobMetrics(ctx, d, *firestoreInstance, repos, tcc); err != nil {
		sklog.Fatal(err)
	}

	// Generate "time to X% bot coverage" metrics.
	if err := bot_metrics.Start(ctx, d, repos, tcc, *btProject, *btInstance, *workdir, ts); err != nil {
		sklog.Fatal(err)
	}

	if err := StartFirestoreBackupMetrics(ctx, ts); err != nil {
		sklog.Fatal(err)
	}

	// Collect metrics for supported branches.
	gitcookiesPath := "/tmp/.gitcookies"
	if _, err := gitauth.New(ts, gitcookiesPath, true, ""); err != nil {
		sklog.Fatal(err)
	}
	supported_branches.Start(ctx, *repoUrls, gitcookiesPath, httpClient, swarmClient, *swarmingPools)

	// Wait while the above goroutines generate data.
	httputils.RunHealthCheckServer(*port)
}
<commit_msg>[datahopper] Fix missing gerrit scope<commit_after>/*
	Pulls data from multiple sources and funnels into metrics.
*/

package main

import (
	"context"
	"flag"
	"fmt"
	"path/filepath"
	"regexp"
	"time"

	"cloud.google.com/go/bigtable"
	"cloud.google.com/go/datastore"
	"cloud.google.com/go/storage"
	"go.skia.org/infra/datahopper/go/bot_metrics"
	"go.skia.org/infra/datahopper/go/supported_branches"
	"go.skia.org/infra/datahopper/go/swarming_metrics"
	"go.skia.org/infra/go/auth"
	"go.skia.org/infra/go/common"
	"go.skia.org/infra/go/gcs"
	"go.skia.org/infra/go/git"
	"go.skia.org/infra/go/git/repograph"
	"go.skia.org/infra/go/gitauth"
	"go.skia.org/infra/go/gitstore"
	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/metrics2"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/go/swarming"
	"go.skia.org/infra/go/taskname"
	"go.skia.org/infra/go/util"
	"go.skia.org/infra/perf/go/perfclient"
	"go.skia.org/infra/task_scheduler/go/db/firestore"
	"go.skia.org/infra/task_scheduler/go/db/pubsub"
	"go.skia.org/infra/task_scheduler/go/task_cfg_cache"
	"google.golang.org/api/option"
)

// flags
var (
	// TODO(borenet): Combine btInstance, firestoreInstance, and
	// pubsubTopicSet.
	btInstance        = flag.String("bigtable_instance", "", "BigTable instance to use.")
	btProject         = flag.String("bigtable_project", "", "GCE project to use for BigTable.")
	firestoreInstance = flag.String("firestore_instance", "", "Firestore instance to use, eg. \"production\"")
	gitstoreTable     = flag.String("gitstore_bt_table", "git-repos", "BigTable table used for GitStore.")
	local             = flag.Bool("local", false, "Running locally if true. As opposed to in production.")
	perfBucket        = flag.String("perf_bucket", "skia-perf", "The GCS bucket that should be used for writing into perf")
	perfPrefix        = flag.String("perf_duration_prefix", "task-duration", "The folder name in the bucket that task duration metric should be written.")
	port              = flag.String("port", ":8000", "HTTP service port for the health check server (e.g., ':8000')")
	promPort          = flag.String("prom_port", ":20000", "Metrics service address (e.g., ':10110')")
	pubsubProject     = flag.String("pubsub_project", "", "GCE project to use for PubSub.")
	pubsubTopicSet    = flag.String("pubsub_topic_set", "", fmt.Sprintf("Pubsub topic set; one of: %v", pubsub.VALID_TOPIC_SETS))
	repoUrls          = common.NewMultiStringFlag("repo", nil, "Repositories to query for status.")
	swarmingServer    = flag.String("swarming_server", "", "Host name of the Swarming server.")
	swarmingPools     = common.NewMultiStringFlag("swarming_pool", nil, "Swarming pools to use.")
	workdir           = flag.String("workdir", ".", "Working directory used by data processors.")
)

var (
	// Regexp matching non-alphanumeric characters.
	re = regexp.MustCompile("[^A-Za-z0-9]+")

	BUILDSLAVE_OFFLINE_BLACKLIST = []string{
		"build3-a3",
		"build4-a3",
		"vm255-m3",
	}
)

func main() {
	common.InitWithMust(
		"datahopper",
		common.PrometheusOpt(promPort),
		common.MetricsLoggingOpt(),
	)
	ctx := context.Background()

	// Absolutify the workdir.
	w, err := filepath.Abs(*workdir)
	if err != nil {
		sklog.Fatal(w)
	}
	sklog.Infof("Workdir is %s", w)

	// OAuth2.0 TokenSource.
	ts, err := auth.NewDefaultTokenSource(*local, auth.SCOPE_USERINFO_EMAIL, pubsub.AUTH_SCOPE, bigtable.Scope, datastore.ScopeDatastore, swarming.AUTH_SCOPE, auth.SCOPE_READ_WRITE, auth.SCOPE_GERRIT)
	if err != nil {
		sklog.Fatal(err)
	}

	// Authenticated HTTP client.
	httpClient := httputils.DefaultClientConfig().WithTokenSource(ts).With2xxOnly().Client()

	// Various API clients.
	gsClient, err := storage.NewClient(ctx, option.WithHTTPClient(httpClient))
	if err != nil {
		sklog.Fatal(err)
	}
	storageClient := gcs.NewGCSClient(gsClient, *perfBucket)
	pc := perfclient.New(*perfPrefix, storageClient)

	tnp := taskname.DefaultTaskNameParser()

	// Shared repo objects.
	if *repoUrls == nil {
		sklog.Fatal("At least one --repo is required.")
	}
	btConf := &gitstore.BTConfig{
		ProjectID:  *btProject,
		InstanceID: *btInstance,
		TableID:    *gitstoreTable,
	}
	repos, err := repograph.NewBTGitStoreMap(ctx, *repoUrls, btConf)
	if err != nil {
		sklog.Fatal(err)
	}
	lvRepos := metrics2.NewLiveness("datahopper_repo_update")
	go util.RepeatCtx(time.Minute, ctx, func() {
		if err := repos.Update(ctx); err != nil {
			sklog.Errorf("Failed to update repos: %s", err)
		} else {
			lvRepos.Reset()
		}
	})

	// TaskCfgCache.
	tcc, err := task_cfg_cache.NewTaskCfgCache(ctx, repos, *btProject, *btInstance, ts)
	if err != nil {
		sklog.Fatalf("Failed to create TaskCfgCache: %s", err)
	}
	go util.RepeatCtx(30*time.Minute, ctx, func() {
		if err := tcc.Cleanup(ctx, OVERDUE_JOB_METRICS_PERIOD); err != nil {
			sklog.Errorf("Failed to cleanup TaskCfgCache: %s", err)
		}
	})

	// Data generation goroutines.

	// Swarming bots.
	swarmClient, err := swarming.NewApiClient(httpClient, *swarmingServer)
	if err != nil {
		sklog.Fatal(err)
	}
	swarming_metrics.StartSwarmingBotMetrics(ctx, *swarmingServer, *swarmingPools, swarmClient, metrics2.GetDefaultClient())

	// Swarming tasks.
	if err := swarming_metrics.StartSwarmingTaskMetrics(ctx, *btProject, *btInstance, swarmClient, *swarmingPools, pc, tnp, ts); err != nil {
		sklog.Fatal(err)
	}

	// Number of commits in the repo.
	go func() {
		for range time.Tick(5 * time.Minute) {
			for repoUrl, repo := range repos {
				normUrl, err := git.NormalizeURL(repoUrl)
				if err != nil {
					sklog.Fatal(err)
				}
				tags := map[string]string{"repo": normUrl}
				metrics2.GetInt64Metric("repo_commits", tags).Update(int64(repo.Len()))
			}
		}
	}()

	// Tasks metrics.
	label := "datahopper"
	mod, err := pubsub.NewModifiedData(*pubsubProject, *pubsubTopicSet, label, ts)
	if err != nil {
		sklog.Fatal(err)
	}
	d, err := firestore.NewDB(ctx, firestore.FIRESTORE_PROJECT, *firestoreInstance, ts, mod)
	if err != nil {
		sklog.Fatalf("Failed to create Firestore DB client: %s", err)
	}
	if err := StartTaskMetrics(ctx, d, *firestoreInstance); err != nil {
		sklog.Fatal(err)
	}

	// Jobs metrics.
	if err := StartJobMetrics(ctx, d, *firestoreInstance, repos, tcc); err != nil {
		sklog.Fatal(err)
	}

	// Generate "time to X% bot coverage" metrics.
	if err := bot_metrics.Start(ctx, d, repos, tcc, *btProject, *btInstance, *workdir, ts); err != nil {
		sklog.Fatal(err)
	}

	if err := StartFirestoreBackupMetrics(ctx, ts); err != nil {
		sklog.Fatal(err)
	}

	// Collect metrics for supported branches.
	gitcookiesPath := "/tmp/.gitcookies"
	if _, err := gitauth.New(ts, gitcookiesPath, true, ""); err != nil {
		sklog.Fatal(err)
	}
	supported_branches.Start(ctx, *repoUrls, gitcookiesPath, httpClient, swarmClient, *swarmingPools)

	// Wait while the above goroutines generate data.
	httputils.RunHealthCheckServer(*port)
}
<|endoftext|>


<commit_before>package actionreconcilers

import (
	"log"

	"github.com/byuoitav/av-api/base"
)

//DefaultReconciler is the Default Reconciler
//Sorts by device, then by priority
type DefaultReconciler struct{}

//Reconcile fulfills the requirement to be a Reconciler.
func (d *DefaultReconciler) Reconcile(actions []base.ActionStructure) ([]base.ActionStructure, error) {

	log.Printf("Removing incompatible actions...")

	actionMap := make(map[int][]base.ActionStructure)
	for _, action := range actions {
		actionMap[action.Device.ID] = append(actionMap[action.Device.ID], action) //this should work every time, right?
	}

	output := []base.ActionStructure{
		base.ActionStructure{
			Action:              "Start",
			GeneratingEvaluator: "DefaultReconciler",
			Overridden:          true,
		},
	}

	for device, actionList := range actionMap {

		actionList, err := StandardReconcile(device, actionList)
		if err != nil {
			return []base.ActionStructure{}, err
		}

		actionList, err = SortActionsByPriority(actionList)
		if err != nil {
			return []base.ActionStructure{}, err
		}

		output = append(output, actionList...)

	}

	return output, nil
}

func SortActionsByPriority(actions []base.ActionStructure) ([]base.ActionStructure, error) {

	var output []base.ActionStructure

	return output, nil
}
<commit_msg>You're mocking me, aren't you?<commit_after>package actionreconcilers

import (
	"log"
	"sort"

	"github.com/byuoitav/av-api/base"
)

//DefaultReconciler is the Default Reconciler
//Sorts by device, then by priority
type DefaultReconciler struct{}

//Reconcile fulfills the requirement to be a Reconciler.
func (d *DefaultReconciler) Reconcile(actions []base.ActionStructure) ([]base.ActionStructure, error) {

	log.Printf("Removing incompatible actions...")

	actionMap := make(map[int][]base.ActionStructure)
	for _, action := range actions {
		actionMap[action.Device.ID] = append(actionMap[action.Device.ID], action) //this should work every time, right?
	}

	output := []base.ActionStructure{
		base.ActionStructure{
			Action:              "Start",
			GeneratingEvaluator: "DefaultReconciler",
			Overridden:          true,
		},
	}

	for device, actionList := range actionMap {

		actionList, err := StandardReconcile(device, actionList)
		if err != nil {
			return []base.ActionStructure{}, err
		}

		actionList, err = SortActionsByPriority(actionList)
		if err != nil {
			return []base.ActionStructure{}, err
		}

		output[0].Children = append(output[0].Children, &actionList[0])
		output = append(output, actionList...)

	}

	return output, nil
}

func SortActionsByPriority(actions []base.ActionStructure) (output []base.ActionStructure, err error) {

	actionMap := make(map[int][]base.ActionStructure)

	for _, action := range actions {

		for _, command := range action.Device.Commands {

			if command.Name == action.Action {

				actionMap[command.Priority] = append(actionMap[command.Priority], action)
			}
		}
	}

	var keys []int
	for key := range actionMap {
		keys = append(keys, key)
	}

	sort.Ints(keys)
	output = append(output, actionMap[keys[0]]...) //parents of everything
	marker := len(output) - 1
	delete(actionMap, keys[0])

	for len(actionMap) != 0 {
		for index, key := range keys {

			if index == 0 {
				continue
			}

			output = append(output, actionMap[key]...)
			marker = len(output) - 1
			for _, action := range actionMap[key] {

				output[marker].Children = append(output[marker].Children, &action)
			}

			delete(actionMap, key)
		}

	}
	return output, nil
}
<|endoftext|>


<commit_before>package core

// DevMode puts application in to dev mode
var DevMode = false

// ShowDebugMessages allows for log.Debug to print to console.
var ShowDebugMessages = false

// ProtectedMode forces Tile38 to default in protected mode.
var ProtectedMode = "no"

// AppendOnly allows for disabling the appendonly file.
var AppendOnly = true

// AppendFileName allows for custom appendonly file path
var AppendFileName = ""

// QueueFileName allows for custom queue.db file path
var QueueFileName = ""

// NumThreads is the number of network threads to use.
var NumThreads int
<commit_msg>remove deprecated threads flag<commit_after>package core

// DevMode puts application in to dev mode
var DevMode = false

// ShowDebugMessages allows for log.Debug to print to console.
var ShowDebugMessages = false

// ProtectedMode forces Tile38 to default in protected mode.
var ProtectedMode = "no"

// AppendOnly allows for disabling the appendonly file.
var AppendOnly = true

// AppendFileName allows for custom appendonly file path
var AppendFileName = ""

// QueueFileName allows for custom queue.db file path
var QueueFileName = ""
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"log"
	"strings"

	"github.com/mitchellh/mapstructure"
	"github.com/rackspace/gophercloud"
)

type Openstack struct {
	AuthURL  string
	Provider string
	Client   gophercloud.CloudServersProvider

	Creds struct {
		Username   string `mapstructure:"username"`
		Password   string `mapstructure:"password"`
		ApiKey     string `mapstructure:"apiKey"`
		TenantName string `mapstructure:"tenant_name"`
		TenantId   string `mapstructure:"tenant_id"`
	}

	Builder struct {
		// Populated by Kloud
		ID           string `mapstructure:"instanceId"`
		InstanceName string `mapstructure:"instanceName"`

		// Used in production
		SourceImage string `mapstructure:"imageId"`
		Flavor      string `mapstructure:"flavorId"`
		RawRegion   string `mapstructure:"region"`

		// Not Used
		RawSSHTimeout     string   `mapstructure:"ssh_timeout"`
		SSHUsername       string   `mapstructure:"ssh_username"`
		SSHPort           int      `mapstructure:"ssh_port"`
		OpenstackProvider string   `mapstructure:"openstack_provider"`
		UseFloatingIp     bool     `mapstructure:"use_floating_ip"`
		FloatingIpPool    string   `mapstructure:"floating_ip_pool"`
		FloatingIp        string   `mapstructure:"floating_ip"`
		SecurityGroups    []string `mapstructure:"security_groups"`
		Type              string   `mapstructure:"type" packer:"type"`
	}
}

func New(authURL, providerName string, credential, builder map[string]interface{}) (*Openstack, error) {
	// OpenStack's auto-generated openrc.sh files do not append the suffix
	// /tokens to the authentication URL. This ensures it is present when
	// specifying the URL.
	if strings.Contains(authURL, "://") && !strings.HasSuffix(authURL, "/tokens") {
		authURL += "/tokens"
	}

	o := &Openstack{
		AuthURL:  authURL,
		Provider: providerName,
	}

	// Credentials
	if err := mapstructure.Decode(credential, &o.Creds); err != nil {
		return nil, err
	}

	// Builder data
	if err := mapstructure.Decode(builder, &o.Builder); err != nil {
		return nil, err
	}

	if o.Creds.Username == "" {
		return nil, errors.New("Username is not set")
	}

	if o.Creds.Password == "" && o.Creds.ApiKey == "" {
		return nil, errors.New("Password/ApiKey is not set")
	}

	authoptions := gophercloud.AuthOptions{
		AllowReauth: true,
		ApiKey:      o.Creds.ApiKey,
		TenantId:    o.Creds.TenantId,
		TenantName:  o.Creds.TenantName,
		Username:    o.Creds.Username,
		Password:    o.Creds.Password,
	}

	access, err := gophercloud.Authenticate(authURL, authoptions)
	if err != nil {
		return nil, err
	}

	//fetches the api requisites from gophercloud for the appropriate
	//openstack variant
	api, err := gophercloud.PopulateApi(providerName)
	if err != nil {
		return nil, err
	}

	// if not given the default is used which is returned for that account.
	if o.Builder.RawRegion != "" {
		api.Region = o.Builder.RawRegion
	}

	csp, err := gophercloud.ServersApi(access, api)
	if err != nil {
		log.Printf("Region: %s", o.Builder.RawRegion)
		return nil, err
	}
	o.Client = csp

	return o, nil
}

// Id returns the servers unique Id
func (o *Openstack) Id() string {
	return o.Builder.ID
}

// Server returns a server instance from the server ID
func (o *Openstack) Server() (*gophercloud.Server, error) {
	if o.Id() == "" {
		return nil, errors.New("Server id is empty")
	}

	return o.Client.ServerById(o.Id())
}
<commit_msg>kloud/rackspace: make server method smarter by parsing the error response<commit_after>package api

import (
	"encoding/json"
	"errors"
	"log"
	"strings"

	"github.com/mitchellh/mapstructure"
	"github.com/racker/perigee"
	"github.com/rackspace/gophercloud"
)

var ErrServerNotFound = errors.New("server not found")

type Openstack struct {
	AuthURL  string
	Provider string
	Client   gophercloud.CloudServersProvider

	Creds struct {
		Username   string `mapstructure:"username"`
		Password   string `mapstructure:"password"`
		ApiKey     string `mapstructure:"apiKey"`
		TenantName string `mapstructure:"tenant_name"`
		TenantId   string `mapstructure:"tenant_id"`
	}

	Builder struct {
		// Populated by Kloud
		ID           string `mapstructure:"instanceId"`
		InstanceName string `mapstructure:"instanceName"`

		// Used in production
		SourceImage string `mapstructure:"imageId"`
		Flavor      string `mapstructure:"flavorId"`
		RawRegion   string `mapstructure:"region"`

		// Not Used
		RawSSHTimeout     string   `mapstructure:"ssh_timeout"`
		SSHUsername       string   `mapstructure:"ssh_username"`
		SSHPort           int      `mapstructure:"ssh_port"`
		OpenstackProvider string   `mapstructure:"openstack_provider"`
		UseFloatingIp     bool     `mapstructure:"use_floating_ip"`
		FloatingIpPool    string   `mapstructure:"floating_ip_pool"`
		FloatingIp        string   `mapstructure:"floating_ip"`
		SecurityGroups    []string `mapstructure:"security_groups"`
		Type              string   `mapstructure:"type" packer:"type"`
	}
}

func New(authURL, providerName string, credential, builder map[string]interface{}) (*Openstack, error) {
	// OpenStack's auto-generated openrc.sh files do not append the suffix
	// /tokens to the authentication URL. This ensures it is present when
	// specifying the URL.
	if strings.Contains(authURL, "://") && !strings.HasSuffix(authURL, "/tokens") {
		authURL += "/tokens"
	}

	o := &Openstack{
		AuthURL:  authURL,
		Provider: providerName,
	}

	// Credentials
	if err := mapstructure.Decode(credential, &o.Creds); err != nil {
		return nil, err
	}

	// Builder data
	if err := mapstructure.Decode(builder, &o.Builder); err != nil {
		return nil, err
	}

	if o.Creds.Username == "" {
		return nil, errors.New("Username is not set")
	}

	if o.Creds.Password == "" && o.Creds.ApiKey == "" {
		return nil, errors.New("Password/ApiKey is not set")
	}

	authoptions := gophercloud.AuthOptions{
		AllowReauth: true,
		ApiKey:      o.Creds.ApiKey,
		TenantId:    o.Creds.TenantId,
		TenantName:  o.Creds.TenantName,
		Username:    o.Creds.Username,
		Password:    o.Creds.Password,
	}

	access, err := gophercloud.Authenticate(authURL, authoptions)
	if err != nil {
		return nil, err
	}

	//fetches the api requisites from gophercloud for the appropriate
	//openstack variant
	api, err := gophercloud.PopulateApi(providerName)
	if err != nil {
		return nil, err
	}

	// if not given the default is used which is returned for that account.
	if o.Builder.RawRegion != "" {
		api.Region = o.Builder.RawRegion
	}

	csp, err := gophercloud.ServersApi(access, api)
	if err != nil {
		log.Printf("Region: %s", o.Builder.RawRegion)
		return nil, err
	}
	o.Client = csp

	return o, nil
}

// Id returns the servers unique Id
func (o *Openstack) Id() string {
	return o.Builder.ID
}

type ItemNotFound struct {
	ItemNotFound struct {
		Message string `json:"message"`
		Code    int    `json:"code"`
	} `json:"itemNotFound"`
}

// Server returns a server instance from the server ID
func (o *Openstack) Server() (*gophercloud.Server, error) {
	if o.Id() == "" {
		return nil, errors.New("Server id is empty")
	}

	s, err := o.Client.ServerById(o.Id())
	if err == nil {
		return s, nil
	}

	unexpErr, ok := err.(*perigee.UnexpectedResponseCodeError)
	if !ok {
		return nil, err
	}

	notFound := ItemNotFound{}
	if jsonErr := json.Unmarshal(unexpErr.Body, &notFound); jsonErr != nil {
		return nil, err // send our initial error, we couldn't make it
	}

	if strings.Contains(notFound.ItemNotFound.Message, "Instance could not be found") {
		return nil, ErrServerNotFound
	}

	return nil, err
}
<|endoftext|>