<commit_before>package chord

import (
	"math/big"
	"testing"
)

func TestNextClosest(t *testing.T) {
	// Make the vnodes on the ring (mod 64)
	v1 := &Vnode{Id: []byte{1}}
	v2 := &Vnode{Id: []byte{10}}
	//v3 := &Vnode{Id: []byte{20}}
	v4 := &Vnode{Id: []byte{32}}
	//v5 := &Vnode{Id: []byte{40}}
	//v6 := &Vnode{Id: []byte{48}}
	v7 := &Vnode{Id: []byte{62}}

	// Make a vnode
	vn := &localVnode{}
	vn.Id = []byte{54}
	vn.successors = []*Vnode{v7}
	vn.finger = []*Vnode{nil, nil, nil, v1, v2, v4}
	vn.ring = &Ring{}
	vn.ring.config = &Config{HashBits: 6}

	// Make an iterator
	k := []byte{32}
	cp := &ClosestPreceedingVnodeIterator{}
	cp.init(vn, k)

	// Iterate until we are done
	s1, err := cp.Next()
	if s1 != v2 || err != nil {
		t.Fatalf("Expect v2. %v", s1)
	}

	s2, err := cp.Next()
	if s2 != v1 || err != nil {
		t.Fatalf("Expect v1. %v", s2)
	}

	s3, err := cp.Next()
	if s3 != v7 || err != nil {
		t.Fatalf("Expect v7. %v", s3)
	}

	s4, err := cp.Next()
	if s4 != nil || err != nil {
		t.Fatalf("Expect nil. %v", s4)
	}
}

func TestClosest(t *testing.T) {
	a := &Vnode{Id: []byte{128}}
	b := &Vnode{Id: []byte{32}}
	k := []byte{45}
	c := closest_preceeding_vnode(a, b, k, 8)
	if c != b {
		t.Fatalf("expect b to be closer!")
	}
}

func TestDistance(t *testing.T) {
	a := []byte{63}
	b := []byte{3}
	d := distance(a, b, 6) // Ring size of 64
	if d.Cmp(big.NewInt(4)) != 0 {
		t.Fatalf("expect distance 4! %v", d)
	}

	a = []byte{0}
	b = []byte{65}
	d = distance(a, b, 7) // Ring size of 128
	if d.Cmp(big.NewInt(65)) != 0 {
		t.Fatalf("expect distance 65! %v", d)
	}

	a = []byte{1}
	b = []byte{255}
	d = distance(a, b, 8) // Ring size of 256
	if d.Cmp(big.NewInt(254)) != 0 {
		t.Fatalf("expect distance 254! %v", d)
	}
}
<commit_msg>Increasing test coverage<commit_after>package chord

import (
	"math/big"
	"testing"
)

func TestNextClosest(t *testing.T) {
	// Make the vnodes on the ring (mod 64)
	v1 := &Vnode{Id: []byte{1}}
	v2 := &Vnode{Id: []byte{10}}
	//v3 := &Vnode{Id: []byte{20}}
	v4 := &Vnode{Id: []byte{32}}
	//v5 := &Vnode{Id: []byte{40}}
	v6 := &Vnode{Id: []byte{59}}
	v7 := &Vnode{Id: []byte{62}}

	// Make a vnode
	vn := &localVnode{}
	vn.Id = []byte{54}
	vn.successors = []*Vnode{v6, v7, nil}
	vn.finger = []*Vnode{v6, v6, v7, v1, v2, v4, nil}
	vn.ring = &Ring{}
	vn.ring.config = &Config{HashBits: 6}

	// Make an iterator
	k := []byte{32}
	cp := &ClosestPreceedingVnodeIterator{}
	cp.init(vn, k)

	// Iterate until we are done
	s1, err := cp.Next()
	if s1 != v2 || err != nil {
		t.Fatalf("Expect v2. %v", s1)
	}

	s2, err := cp.Next()
	if s2 != v1 || err != nil {
		t.Fatalf("Expect v1. %v", s2)
	}

	s3, err := cp.Next()
	if s3 != v7 || err != nil {
		t.Fatalf("Expect v7. %v", s3)
	}

	s4, err := cp.Next()
	if s4 != v6 || err != nil {
		t.Fatalf("Expect v6. %v", s4)
	}

	s5, err := cp.Next()
	if s5 != nil || err != nil {
		t.Fatalf("Expect nil. %v", s5)
	}
}

func TestNextClosestNoSucc(t *testing.T) {
	// Make the vnodes on the ring (mod 64)
	v1 := &Vnode{Id: []byte{1}}
	v2 := &Vnode{Id: []byte{10}}
	//v3 := &Vnode{Id: []byte{20}}
	v4 := &Vnode{Id: []byte{32}}
	//v5 := &Vnode{Id: []byte{40}}
	v6 := &Vnode{Id: []byte{59}}
	v7 := &Vnode{Id: []byte{62}}

	// Make a vnode
	vn := &localVnode{}
	vn.Id = []byte{54}
	vn.successors = []*Vnode{nil}
	vn.finger = []*Vnode{v6, v6, v7, v1, v2, v4, nil}
	vn.ring = &Ring{}
	vn.ring.config = &Config{HashBits: 6}

	// Make an iterator
	k := []byte{32}
	cp := &ClosestPreceedingVnodeIterator{}
	cp.init(vn, k)

	// Iterate until we are done
	s1, err := cp.Next()
	if s1 != v2 || err != nil {
		t.Fatalf("Expect v2. %v", s1)
	}

	s2, err := cp.Next()
	if s2 != v1 || err != nil {
		t.Fatalf("Expect v1. %v", s2)
	}

	s3, err := cp.Next()
	if s3 != v7 || err != nil {
		t.Fatalf("Expect v7. %v", s3)
	}

	s4, err := cp.Next()
	if s4 != v6 || err != nil {
		t.Fatalf("Expect v6. %v", s4)
	}

	s5, err := cp.Next()
	if s5 != nil || err != nil {
		t.Fatalf("Expect nil. %v", s5)
	}
}

func TestNextClosestNoFinger(t *testing.T) {
	// Make the vnodes on the ring (mod 64)
	//v1 := &Vnode{Id: []byte{1}}
	//v2 := &Vnode{Id: []byte{10}}
	//v3 := &Vnode{Id: []byte{20}}
	//v4 := &Vnode{Id: []byte{32}}
	//v5 := &Vnode{Id: []byte{40}}
	v6 := &Vnode{Id: []byte{59}}
	v7 := &Vnode{Id: []byte{62}}

	// Make a vnode
	vn := &localVnode{}
	vn.Id = []byte{54}
	vn.successors = []*Vnode{v6, v7, v7, nil}
	vn.finger = []*Vnode{nil, nil, nil}
	vn.ring = &Ring{}
	vn.ring.config = &Config{HashBits: 6}

	// Make an iterator
	k := []byte{32}
	cp := &ClosestPreceedingVnodeIterator{}
	cp.init(vn, k)

	// Iterate until we are done
	s3, err := cp.Next()
	if s3 != v7 || err != nil {
		t.Fatalf("Expect v7. %v", s3)
	}

	s4, err := cp.Next()
	if s4 != v6 || err != nil {
		t.Fatalf("Expect v6. %v", s4)
	}

	s5, err := cp.Next()
	if s5 != nil || err != nil {
		t.Fatalf("Expect nil. %v", s5)
	}
}

func TestClosest(t *testing.T) {
	a := &Vnode{Id: []byte{128}}
	b := &Vnode{Id: []byte{32}}
	k := []byte{45}
	c := closest_preceeding_vnode(a, b, k, 8)
	if c != b {
		t.Fatalf("expect b to be closer!")
	}
	c = closest_preceeding_vnode(b, a, k, 8)
	if c != b {
		t.Fatalf("expect b to be closer!")
	}
}

func TestDistance(t *testing.T) {
	a := []byte{63}
	b := []byte{3}
	d := distance(a, b, 6) // Ring size of 64
	if d.Cmp(big.NewInt(4)) != 0 {
		t.Fatalf("expect distance 4! %v", d)
	}

	a = []byte{0}
	b = []byte{65}
	d = distance(a, b, 7) // Ring size of 128
	if d.Cmp(big.NewInt(65)) != 0 {
		t.Fatalf("expect distance 65! %v", d)
	}

	a = []byte{1}
	b = []byte{255}
	d = distance(a, b, 8) // Ring size of 256
	if d.Cmp(big.NewInt(254)) != 0 {
		t.Fatalf("expect distance 254! %v", d)
	}
}
<|endoftext|>


<commit_before>package evedata

import (
	"encoding/gob"

	"log"
	"net/http"
	"time"

	"github.com/antihax/evedata/appContext"
	"github.com/antihax/evedata/config"
	"github.com/antihax/evedata/discord"
	"github.com/antihax/evedata/esi"
	"github.com/antihax/evedata/eveConsumer"
	"github.com/antihax/evedata/eveapi"
	"github.com/antihax/evedata/models"

	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/context"
	"github.com/gregjones/httpcache"
	httpredis "github.com/gregjones/httpcache/redis"
	"golang.org/x/oauth2"
	gsr "gopkg.in/boj/redistore.v1"
)

var ctx appContext.AppContext

func GetContext() *appContext.AppContext {
	return &ctx
}

// Load the server
func GoServer() {
	var err error

	// Make a new app context.

	// Read configuation.
	if ctx.Conf, err = config.ReadConfig(); err != nil {
		log.Fatalf("Error reading configuration: %v", err)
	}

	// Build the redis pool
	ctx.Cache = &redis.Pool{
		MaxIdle:     10,
		IdleTimeout: 60 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", ctx.Conf.Redis.Address)
			if err != nil {
				return nil, err
			}
			if ctx.Conf.Redis.Password != "" {
				if _, err := c.Do("AUTH", ctx.Conf.Redis.Password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
	}

	// Create a Redis http client for the CCP APIs.
	transportCache := httpcache.NewTransport(httpredis.NewWithClient(ctx.Cache.Get()))

	// Attach a basic transport with our chained custom transport.
	transportCache.Transport = &transport{&http.Transport{Proxy: http.ProxyFromEnvironment, MaxIdleConnsPerHost: 5}, &ctx, 0}

	// Build a HTTP Client pool this client will be shared with APIs for:
	//   - ESI
	//   - ZKillboard
	//   - EVE SSO
	//   - EVE CREST and XML
	ctx.HTTPClient = &http.Client{Transport: transportCache}
	if ctx.HTTPClient == nil {
		panic("http client is null")
	}

	/*	r := ctx.Cache.Get()
		r.Do("FLUSHALL")
		r.Close()*/

	// Build Connection Pool
	if ctx.Db, err = models.SetupDatabase(ctx.Conf.Database.Driver, ctx.Conf.Database.Spec); err != nil {
		log.Fatalf("Cannot build database pool: %v", err)
	}

	// Setup the SSO authenticator, this is the main login.
	ssoScopes := []string{
		eveapi.ScopeCharacterLocationRead,
		eveapi.ScopeCharacterNavigationWrite,
		eveapi.ScopeRemoteClientUI,
	}

	ctx.SSOAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.SSO.ClientID,
		ctx.Conf.CREST.SSO.SecretKey,
		ctx.Conf.CREST.SSO.RedirectURL,
		ssoScopes)

	// Setup the Token authenticator, this handles sub characters.
	tokenScopes := []string{
		eveapi.ScopeCharacterContractsRead,
		eveapi.ScopeCharacterMarketOrdersRead,
		eveapi.ScopeCharacterResearchRead,
		eveapi.ScopeCharacterWalletRead,
		"esi-assets.read_assets.v1",
		"esi-bookmarks.read_character_bookmarks.v1",
		"esi-calendar.read_calendar_events.v1",
		"esi-calendar.respond_calendar_events.v1",
		"esi-characters.read_contacts.v1",
		"esi-characters.write_contacts.v1",
		"esi-clones.read_clones.v1",
		"esi-corporations.read_corporation_membership.v1",
		"esi-fleets.read_fleet.v1",
		"esi-fleets.write_fleet.v1",
		"esi-killmails.read_killmails.v1",
		"esi-location.read_location.v1",
		"esi-location.read_ship_type.v1",
		"esi-planets.manage_planets.v1",
		"esi-search.search_structures.v1",
		"esi-skills.read_skillqueue.v1",
		"esi-skills.read_skills.v1",
		"esi-ui.open_window.v1",
		"esi-ui.write_waypoint.v1",
		"esi-universe.read_structures.v1",
		"esi-wallet.read_character_wallet.v1",
	}

	ctx.TokenAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.Token.ClientID,
		ctx.Conf.CREST.Token.SecretKey,
		ctx.Conf.CREST.Token.RedirectURL,
		tokenScopes)

	// Setup the EVE ESI Client
	ctx.ESI = esi.NewAPIClient(ctx.HTTPClient, ctx.Conf.UserAgent)

	// Setup the bootstrap authenticator. Needed to update the site main token.
	ctx.ESIBootstrapAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.ESIAccessToken.ClientID,
		ctx.Conf.CREST.ESIAccessToken.SecretKey,
		ctx.Conf.CREST.ESIAccessToken.RedirectURL,
		[]string{"esi-universe.read_structures.v1",
			"esi-search.search_structures.v1"})

	// Get the token from config and build a TokenSource (refreshes the token if needed.)
	token := &eveapi.CRESTToken{
		AccessToken:  ctx.Conf.CREST.ESIAccessToken.AccessToken,
		TokenType:    ctx.Conf.CREST.ESIAccessToken.TokenType,
		RefreshToken: ctx.Conf.CREST.ESIAccessToken.RefreshToken,
		Expiry:       ctx.Conf.CREST.ESIAccessToken.Expiry,
	}

	ctx.ESIPublicToken, err = ctx.ESIBootstrapAuthenticator.TokenSource(token)
	if err != nil {
		log.Fatalf("Error starting bootstrap ESI client: %v", err)
	}

	// Create a memcached session store.
	ctx.Store, err = gsr.NewRediStoreWithPool(ctx.Cache, []byte(ctx.Conf.Store.Key))
	if err != nil {
		log.Fatalf("Cannot build database pool: %v", err)
	}

	ctx.Store.Options.Domain = ctx.Conf.Store.Domain

	// Register structs for storage
	gob.Register(oauth2.Token{})
	gob.Register(eveapi.CRESTToken{})
	gob.Register(eveapi.VerifyResponse{})

	// Anonymous EVE API & Crest Client
	ctx.EVE = eveapi.NewEVEAPIClient(ctx.HTTPClient)

	// Set our logging flags
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	if ctx.Conf.Discord.Enabled {
		go discord.GoDiscordBot(&ctx)
	}

	if ctx.Conf.EVEConsumer.Enabled {
		log.Println("Starting EVE Consumer")
		eC := eveConsumer.NewEVEConsumer(&ctx)
		eC.RunConsumer()
		defer eC.StopConsumer()
	}
	// Allocate the routes
	rtr := NewRouter(&ctx)

	log.Printf("EveData Listening port 3000...\n")
	http.ListenAndServe(":3000", context.ClearHandler(rtr))
	log.Printf("EveData Quitting..\n")
}
<commit_msg>Apparently using too many scioes<commit_after>package evedata

import (
	"encoding/gob"

	"log"
	"net/http"
	"time"

	"github.com/antihax/evedata/appContext"
	"github.com/antihax/evedata/config"
	"github.com/antihax/evedata/discord"
	"github.com/antihax/evedata/esi"
	"github.com/antihax/evedata/eveConsumer"
	"github.com/antihax/evedata/eveapi"
	"github.com/antihax/evedata/models"

	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/context"
	"github.com/gregjones/httpcache"
	httpredis "github.com/gregjones/httpcache/redis"
	"golang.org/x/oauth2"
	gsr "gopkg.in/boj/redistore.v1"
)

var ctx appContext.AppContext

func GetContext() *appContext.AppContext {
	return &ctx
}

// Load the server
func GoServer() {
	var err error

	// Make a new app context.

	// Read configuation.
	if ctx.Conf, err = config.ReadConfig(); err != nil {
		log.Fatalf("Error reading configuration: %v", err)
	}

	// Build the redis pool
	ctx.Cache = &redis.Pool{
		MaxIdle:     10,
		IdleTimeout: 60 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", ctx.Conf.Redis.Address)
			if err != nil {
				return nil, err
			}
			if ctx.Conf.Redis.Password != "" {
				if _, err := c.Do("AUTH", ctx.Conf.Redis.Password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
	}

	// Create a Redis http client for the CCP APIs.
	transportCache := httpcache.NewTransport(httpredis.NewWithClient(ctx.Cache.Get()))

	// Attach a basic transport with our chained custom transport.
	transportCache.Transport = &transport{&http.Transport{Proxy: http.ProxyFromEnvironment, MaxIdleConnsPerHost: 5}, &ctx, 0}

	// Build a HTTP Client pool this client will be shared with APIs for:
	//   - ESI
	//   - ZKillboard
	//   - EVE SSO
	//   - EVE CREST and XML
	ctx.HTTPClient = &http.Client{Transport: transportCache}
	if ctx.HTTPClient == nil {
		panic("http client is null")
	}

	/*	r := ctx.Cache.Get()
		r.Do("FLUSHALL")
		r.Close()*/

	// Build Connection Pool
	if ctx.Db, err = models.SetupDatabase(ctx.Conf.Database.Driver, ctx.Conf.Database.Spec); err != nil {
		log.Fatalf("Cannot build database pool: %v", err)
	}

	// Setup the SSO authenticator, this is the main login.
	ssoScopes := []string{}

	ctx.SSOAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.SSO.ClientID,
		ctx.Conf.CREST.SSO.SecretKey,
		ctx.Conf.CREST.SSO.RedirectURL,
		ssoScopes)

	// Setup the Token authenticator, this handles sub characters.
	tokenScopes := []string{
		eveapi.ScopeCharacterContractsRead,
		eveapi.ScopeCharacterMarketOrdersRead,
		eveapi.ScopeCharacterResearchRead,
		eveapi.ScopeCharacterWalletRead,
		"esi-assets.read_assets.v1",
		"esi-characters.read_contacts.v1",
		"esi-characters.write_contacts.v1",
		"esi-corporations.read_corporation_membership.v1",
		"esi-location.read_location.v1",
		"esi-location.read_ship_type.v1",
		"esi-planets.manage_planets.v1",
		"esi-search.search_structures.v1",
		"esi-skills.read_skills.v1",
		"esi-ui.open_window.v1",
		"esi-ui.write_waypoint.v1",
		"esi-universe.read_structures.v1",
		"esi-wallet.read_character_wallet.v1",
	}

	ctx.TokenAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.Token.ClientID,
		ctx.Conf.CREST.Token.SecretKey,
		ctx.Conf.CREST.Token.RedirectURL,
		tokenScopes)

	// Setup the EVE ESI Client
	ctx.ESI = esi.NewAPIClient(ctx.HTTPClient, ctx.Conf.UserAgent)

	// Setup the bootstrap authenticator. Needed to update the site main token.
	ctx.ESIBootstrapAuthenticator = eveapi.NewSSOAuthenticator(
		ctx.HTTPClient,
		ctx.Conf.CREST.ESIAccessToken.ClientID,
		ctx.Conf.CREST.ESIAccessToken.SecretKey,
		ctx.Conf.CREST.ESIAccessToken.RedirectURL,
		[]string{"esi-universe.read_structures.v1",
			"esi-search.search_structures.v1"})

	// Get the token from config and build a TokenSource (refreshes the token if needed.)
	token := &eveapi.CRESTToken{
		AccessToken:  ctx.Conf.CREST.ESIAccessToken.AccessToken,
		TokenType:    ctx.Conf.CREST.ESIAccessToken.TokenType,
		RefreshToken: ctx.Conf.CREST.ESIAccessToken.RefreshToken,
		Expiry:       ctx.Conf.CREST.ESIAccessToken.Expiry,
	}

	ctx.ESIPublicToken, err = ctx.ESIBootstrapAuthenticator.TokenSource(token)
	if err != nil {
		log.Fatalf("Error starting bootstrap ESI client: %v", err)
	}

	// Create a memcached session store.
	ctx.Store, err = gsr.NewRediStoreWithPool(ctx.Cache, []byte(ctx.Conf.Store.Key))
	if err != nil {
		log.Fatalf("Cannot build database pool: %v", err)
	}

	ctx.Store.Options.Domain = ctx.Conf.Store.Domain

	// Register structs for storage
	gob.Register(oauth2.Token{})
	gob.Register(eveapi.CRESTToken{})
	gob.Register(eveapi.VerifyResponse{})

	// Anonymous EVE API & Crest Client
	ctx.EVE = eveapi.NewEVEAPIClient(ctx.HTTPClient)

	// Set our logging flags
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	if ctx.Conf.Discord.Enabled {
		go discord.GoDiscordBot(&ctx)
	}

	if ctx.Conf.EVEConsumer.Enabled {
		log.Println("Starting EVE Consumer")
		eC := eveConsumer.NewEVEConsumer(&ctx)
		eC.RunConsumer()
		defer eC.StopConsumer()
	}
	// Allocate the routes
	rtr := NewRouter(&ctx)

	log.Printf("EveData Listening port 3000...\n")
	http.ListenAndServe(":3000", context.ClearHandler(rtr))
	log.Printf("EveData Quitting..\n")
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/garyburd/redigo/redis"
    "encoding/json"
)

type User struct {
    Name string `json:"name"`
    Password string `json:"password"`
    Method  string `json:"method"`
}

type Storage struct {
    conn redis.Conn
}

func NewStorage(server string) (*Storage, error){
    conn, err := redis.Dial("tcp", server)
    if err != nil {
        return nil, err
    }
    return &Storage{conn}, nil
}

func (s *Storage) Get(key string) (user User, err error) {
    var data []byte
    data, err = redis.Bytes(s.conn.Do("GET", key))
    if err != nil {
        return
    }
    err = json.Unmarshal(data, &user)
    return
}

func (s *Storage) Set(key string, user User) (err error) {
    data, err := json.Marshal(user)
    if err != nil {
        return err
    }
    _, err = s.conn.Do("SET", key, data)
    return
}
<commit_msg>format<commit_after>package main

import (
    "encoding/json"
    "github.com/garyburd/redigo/redis"
)

type User struct {
    Name     string `json:"name"`
    Password string `json:"password"`
    Method   string `json:"method"`
}

type Storage struct {
    conn redis.Conn
}

func NewStorage(server string) (*Storage, error) {
    conn, err := redis.Dial("tcp", server)
    if err != nil {
        return nil, err
    }
    return &Storage{conn}, nil
}

func (s *Storage) Get(key string) (user User, err error) {
    var data []byte
    data, err = redis.Bytes(s.conn.Do("GET", key))
    if err != nil {
        return
    }
    err = json.Unmarshal(data, &user)
    return
}

func (s *Storage) Set(key string, user User) (err error) {
    data, err := json.Marshal(user)
    if err != nil {
        return err
    }
    _, err = s.conn.Do("SET", key, data)
    return
}
<|endoftext|>


<commit_before>package sendcloud

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

const (
	API_ENDPOINT = "https://sendcloud.sohu.com/webapi/"
)

type Sendcloud struct {
	user string
	pswd string
}

func New(user, pswd string) *Sendcloud {
	return &Sendcloud{user: user, pswd: pswd}
}

func (sc *Sendcloud) do(target string, data url.Values) (body []byte, err error) {
	url := fmt.Sprintf("%s%s.json", API_ENDPOINT, target)
	data.Add("api_user", sc.user)
	data.Add("api_key", sc.pswd)
	rsp, err := http.PostForm(url, data)
	if err != nil {
		return
	}
	defer rsp.Body.Close()
	body, err = ioutil.ReadAll(rsp.Body)
	if err != nil {
		return
	}
	if rsp.StatusCode != 200 {
		err = fmt.Errorf("SendCloud error: %d %s", rsp.StatusCode, body)
	}
	return
}

type Mail interface {
	From() string
	To() []string
	Cc() []string
	Bcc() []string
	ReplyTo() string
	Subject() string
	Html() string
}

func (sc *Sendcloud) Send(m Mail) (id string, err error) {
	d := url.Values{}
	d.Add("resp_email_id", "true")
	d.Add("from", m.From())
	if to := m.To(); len(to) > 0 {
		d.Add("to", strings.Join(to, ";"))
	}
	if cc := m.Cc(); len(cc) > 0 {
		d.Add("cc", strings.Join(cc, ";"))
	}
	if bcc := m.Bcc(); len(bcc) > 0 {
		d.Add("bcc", strings.Join(bcc, ";"))
	}
	if replyto := m.ReplyTo(); replyto != "" {
		d.Add("replyto", replyto)
	}
	d.Add("subject", m.Subject())
	d.Add("html", m.Html())

	body, err := sc.do("mail.send", d)
	if err != nil {
		return
	}

	var reply struct {
		Msg  string   `json:"message"`
		Errs []string `json:"errors"`
		Ids  []string `json:"email_id_list"`
	}
	json.Unmarshal(body, &reply)
	if reply.Msg != "success" {
		if len(reply.Errs) > 0 {
			err = fmt.Errorf("SendCloud error: %s", reply.Errs[0])
		}
		err = fmt.Errorf("SendCloud error: unknown")
		return
	}
	if len(reply.Ids) > 0 {
		id = reply.Ids[0]
	}
	return
}
<commit_msg>Bug fix: error reporting from SendCloud response<commit_after>package sendcloud

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

const (
	API_ENDPOINT = "https://sendcloud.sohu.com/webapi/"
)

type Sendcloud struct {
	user string
	pswd string
}

func New(user, pswd string) *Sendcloud {
	return &Sendcloud{user: user, pswd: pswd}
}

func (sc *Sendcloud) do(target string, data url.Values) (body []byte, err error) {
	url := fmt.Sprintf("%s%s.json", API_ENDPOINT, target)
	data.Add("api_user", sc.user)
	data.Add("api_key", sc.pswd)
	rsp, err := http.PostForm(url, data)
	if err != nil {
		return
	}
	defer rsp.Body.Close()
	body, err = ioutil.ReadAll(rsp.Body)
	if err != nil {
		return
	}
	if rsp.StatusCode != 200 {
		err = fmt.Errorf("SendCloud error: %d %s", rsp.StatusCode, body)
	}
	return
}

type Mail interface {
	From() string
	To() []string
	Cc() []string
	Bcc() []string
	ReplyTo() string
	Subject() string
	Html() string
}

func (sc *Sendcloud) Send(m Mail) (id string, err error) {
	d := url.Values{}
	d.Add("resp_email_id", "true")
	d.Add("from", m.From())
	if to := m.To(); len(to) > 0 {
		d.Add("to", strings.Join(to, ";"))
	}
	if cc := m.Cc(); len(cc) > 0 {
		d.Add("cc", strings.Join(cc, ";"))
	}
	if bcc := m.Bcc(); len(bcc) > 0 {
		d.Add("bcc", strings.Join(bcc, ";"))
	}
	if replyto := m.ReplyTo(); replyto != "" {
		d.Add("replyto", replyto)
	}
	d.Add("subject", m.Subject())
	d.Add("html", m.Html())

	body, err := sc.do("mail.send", d)
	if err != nil {
		return
	}

	var reply struct {
		Msg  string   `json:"message"`
		Errs []string `json:"errors"`
		Ids  []string `json:"email_id_list"`
	}
	json.Unmarshal(body, &reply)
	if reply.Msg != "success" {
		if len(reply.Errs) > 0 {
			err = fmt.Errorf("SendCloud error: %s", reply.Errs[0])
		} else {
			err = fmt.Errorf("SendCloud error: unknown")
		}
		return
	}
	if len(reply.Ids) > 0 {
		id = reply.Ids[0]
	}
	return
}
<|endoftext|>


<commit_before>package xval

import (
	"bytes"
	"crypto/des"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
)

const FlagNone = 0
const (
	FlagAuthExFailure           = 1 << iota
	FlagAuthExNoTable           = 1 << iota
	FlagAuthExReserved          = 1 << iota
	FlagInvalidDVDGeometry      = 1 << iota
	FlagInvalidDVDDMI           = 1 << iota
	FlagDVDKeyvaultPairMismatch = 1 << iota
	FlagCRLDataInvalid          = 1 << iota
	FlagCRLCertificateRevoked   = 1 << iota
	FlagUnauthorizedInstall     = 1 << iota
	FlagKeyvaultPolicyViolation = 1 << iota
	FlagConsoleBanned           = 1 << iota
	FlagODDViolation            = 1 << iota
)

func getFlagDescriptions() map[int32]string {
	return map[int32]string{
		FlagAuthExFailure:           "AuthEx challenge failure (AP 2.5 related)",
		FlagAuthExNoTable:           "AuthEx table missing (AP 2.5 related",
		FlagAuthExReserved:          "AuthEx reserved flag (AP 2.5 related)",
		FlagInvalidDVDGeometry:      "Invalid DVD geometry",
		FlagInvalidDVDDMI:           "Invalid DVD DMI",
		FlagDVDKeyvaultPairMismatch: "Invalid CRL data",
		FlagCRLDataInvalid:          "CRL certificate revoked",
		FlagCRLCertificateRevoked:   "CRL certificate revoked",
		FlagUnauthorizedInstall:     "Unauthorized install",
		FlagKeyvaultPolicyViolation: "Keyvault policy violation",
		FlagConsoleBanned:           "Console is banned",
		FlagODDViolation:            "ODD violation",
	}
}

func DecryptXVal(serial, xval string) ([]byte, []byte, error) {
	if strings.Contains(xval, "-") {
		xval = strings.Replace(xval, "-", "", -1)
	}
	if len(xval) != 16 {
		return nil, nil, errors.New("Invalid X value. Without dashes, length is not 16")
	}
	if len(serial) != 0xC {
		return nil, nil, errors.New(fmt.Sprintf("Invalid console serial number. Length is not %d", 0xC))
	}

	mac := hmac.New(sha1.New, []byte(serial))
	mac.Write([]byte("XBOX360SSB"))
	desKey := mac.Sum(nil)[0:8]

	if len(desKey) != 8 {
		return nil, nil, errors.New(fmt.Sprintf("Error decrypting (invalid DES key length of %d). Key: %v", len(desKey), desKey))
	}

	xvalAsHex, _ := hex.DecodeString(xval)

	cipher, err := des.NewCipher(desKey)
	if err != nil {
		return nil, nil, err
	}
	cipher.Decrypt(xvalAsHex, xvalAsHex)
	return desKey, xvalAsHex, nil
}

func TextResult(dec []byte) []string {
	var result []string

	buf := new(bytes.Buffer)
	buf.Write(dec[0:4])

	var lowBits, highBits int32
	binary.Read(buf, binary.BigEndian, &highBits)
	buf.Reset()
	buf.Write(dec[4:8])
	binary.Read(buf, binary.BigEndian, &lowBits)

	if lowBits == 0 && highBits == 0 {
		return []string{"Secdata is clean"}
	} else if lowBits == -1 && highBits == -1 {
		return []string{"Secdata is invalid"}
	} else if lowBits != 0 && highBits != 0 {
		return []string{"Secdata decryption error"}
	} else {
		for flag, message := range getFlagDescriptions() {
			if lowBits&flag != 0 {
				result = append(result, message)
			}
		}
		if lowBits&-0x7FFF != 0 {
			result = append(result, "Unknown violation(s)")
		}
	}
	return result
}
<commit_msg>Add godoc<commit_after>// Package xval provides a method for decrypting Xbox 360 X-value data.
package xval

import (
	"bytes"
	"crypto/des"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
)

const FlagNone = 0
const (
	FlagAuthExFailure           = 1 << iota
	FlagAuthExNoTable           = 1 << iota
	FlagAuthExReserved          = 1 << iota
	FlagInvalidDVDGeometry      = 1 << iota
	FlagInvalidDVDDMI           = 1 << iota
	FlagDVDKeyvaultPairMismatch = 1 << iota
	FlagCRLDataInvalid          = 1 << iota
	FlagCRLCertificateRevoked   = 1 << iota
	FlagUnauthorizedInstall     = 1 << iota
	FlagKeyvaultPolicyViolation = 1 << iota
	FlagConsoleBanned           = 1 << iota
	FlagODDViolation            = 1 << iota
)

func getFlagDescriptions() map[int32]string {
	return map[int32]string{
		FlagAuthExFailure:           "AuthEx challenge failure (AP 2.5 related)",
		FlagAuthExNoTable:           "AuthEx table missing (AP 2.5 related",
		FlagAuthExReserved:          "AuthEx reserved flag (AP 2.5 related)",
		FlagInvalidDVDGeometry:      "Invalid DVD geometry",
		FlagInvalidDVDDMI:           "Invalid DVD DMI",
		FlagDVDKeyvaultPairMismatch: "Invalid CRL data",
		FlagCRLDataInvalid:          "CRL certificate revoked",
		FlagCRLCertificateRevoked:   "CRL certificate revoked",
		FlagUnauthorizedInstall:     "Unauthorized install",
		FlagKeyvaultPolicyViolation: "Keyvault policy violation",
		FlagConsoleBanned:           "Console is banned",
		FlagODDViolation:            "ODD violation",
	}
}

// Decrypt returns the decryption key, decrypted xval data, and an error
// which shows whether or not the decryption was successful.
func DecryptXVal(serial, xval string) ([]byte, []byte, error) {
	if strings.Contains(xval, "-") {
		xval = strings.Replace(xval, "-", "", -1)
	}
	if len(xval) != 16 {
		return nil, nil, errors.New("Invalid X value. Without dashes, length is not 16")
	}
	if len(serial) != 0xC {
		return nil, nil, errors.New(fmt.Sprintf("Invalid console serial number. Length is not %d", 0xC))
	}

	mac := hmac.New(sha1.New, []byte(serial))
	mac.Write([]byte("XBOX360SSB"))
	desKey := mac.Sum(nil)[0:8]

	if len(desKey) != 8 {
		return nil, nil, errors.New(fmt.Sprintf("Error decrypting (invalid DES key length of %d). Key: %v", len(desKey), desKey))
	}

	xvalAsHex, _ := hex.DecodeString(xval)

	cipher, err := des.NewCipher(desKey)
	if err != nil {
		return nil, nil, err
	}
	cipher.Decrypt(xvalAsHex, xvalAsHex)
	return desKey, xvalAsHex, nil
}

// TextResult returns an array of descriptive messages for each
// flag in the dec
func TextResult(dec []byte) []string {
	var result []string

	buf := new(bytes.Buffer)
	buf.Write(dec[0:4])

	var lowBits, highBits int32
	binary.Read(buf, binary.BigEndian, &highBits)
	buf.Reset()
	buf.Write(dec[4:8])
	binary.Read(buf, binary.BigEndian, &lowBits)

	if lowBits == 0 && highBits == 0 {
		return []string{"Secdata is clean"}
	} else if lowBits == -1 && highBits == -1 {
		return []string{"Secdata is invalid"}
	} else if lowBits != 0 && highBits != 0 {
		return []string{"Secdata decryption error"}
	} else {
		for flag, message := range getFlagDescriptions() {
			if lowBits&flag != 0 {
				result = append(result, message)
			}
		}
		if lowBits&-0x7FFF != 0 {
			result = append(result, "Unknown violation(s)")
		}
	}
	return result
}
<|endoftext|>


<commit_before>package poker

import (
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	MsgIQ       = "iq"
	MsgPresence = "presence"
	MsgMessage  = "message"

	ActGet    = "get"
	ActSet    = "set"
	ActResult = "result"

	ActPreflop  = "preflop"
	ActFlop     = "flop"
	ActTurn     = "turn"
	ActRiver    = "river"
	ActShowdown = "showdown"
	ActPot      = "pot"

	ActActive = "active"
	ActJoin   = "join"
	ActLeave  = "gone"
	ActBet    = "bet"
	ActButton = "button"
	ActState  = "state"

	ActAction = "action"
	ActReady  = "ready"
	ActCall   = "call"
	ActCheck  = "check"
	ActRaise  = "raise"
	ActFold   = "fold"
	ActAllin  = "allin"
)

var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin:     func(r *http.Request) bool { return true },
	}
)

type Message struct {
	Id       string    `json:"id,omitempty"`
	Type     string    `json:"type"`
	From     string    `json:"from,omitempty"`
	To       string    `json:"to,omitempty"`
	Action   string    `json:"action"`
	Class    string    `json:"class,omitempty"`
	Occupant *Occupant `json:"occupant,omitempty"`
	Room     *Room     `json:"room,omitempty"`
	Rooms    []*Room   `json:"rooms,omitempty"`
}

type Version struct {
	//Id  string `json:"id"`
	Ver string `json:"version"`
}

type Auth struct {
	Mechanism string `json:"mechanism"`
	Text      string `json:"text"`
}

type AuthResp struct {
	Id    string `json:"id"`
	Name  string `json:"name"`
	Level int    `json:"level"`
	Chips int    `json:"chips"`
}

type Error struct {
	Code int    `json:"code,omitempty"`
	Err  string `json:"error,omitempty"`
}

func NewError(code int, err string) *Error {
	return &Error{
		Code: code,
		Err:  err,
	}
}

func PokerHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer ws.Close()

	ws.SetReadLimit(maxMessageSize)
	ws.SetPongHandler(
		func(string) error {
			ws.SetReadDeadline(time.Now().Add(pongWait))
			return nil
		})
	conn := NewConn(ws, 128)
	defer conn.Close()

	ver := &Version{}
	if err := conn.ReadJSONTimeout(ver, readWait); err != nil {
		return
	}
	if err := conn.WriteJSON(ver); err != nil {
		return
	}

	auth := &Auth{}
	if err := conn.ReadJSONTimeout(auth, readWait); err != nil {
		return
	}

	o := NewOccupant(strconv.FormatInt(time.Now().Unix(), 10), conn)
	o.Name = auth.Text
	o.Chips = 10000

	if err := conn.WriteJSON(o); err != nil {
		return
	}

	for {
		message, _ := o.GetMessage(0)
		if message == nil {
			break
		}

		switch message.Type {
		case MsgIQ:
			go handleIQ(o, message)
		case MsgPresence:
			go handlePresence(o, message)
		case MsgMessage:
		}
	}

	o.Leave()
	log.Println(o.Name, "disconnected.")
}

func handlePresence(o *Occupant, message *Message) {
	switch message.Action {
	case ActJoin:
		if room := o.Join(message.To); room == nil {
			o.SendError(1, "room not found")
			return
		}
	case ActLeave:
		o.Leave()
	case ActBet:
		select {
		case o.Actions <- message:
		default:
		}
	}
}

func handleIQ(o *Occupant, message *Message) {
	switch message.Action {
	case ActSet:
		switch message.Class {
		case "room":
			room := GetRoom(message.To)
			if room == nil {
				room = NewRoom("", 9, 5, 10)
			}
			if message.Room != nil {
				if message.Room.SB > 0 {
					room.SB = message.Room.SB
				}
				if message.Room.BB > 0 {
					room.BB = message.Room.BB
				}
				if message.Room.Timeout > 0 {
					room.Timeout = message.Room.Timeout
				}

				if message.Room.Max > 0 && message.Room.Max <= MaxN {
					room.Max = message.Room.Max
					room.Occupants = room.Occupants[:room.Max]
					room.Chips = room.Chips[:room.Max]
				}

				SetRoom(room)
			}
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				From:   room.Id,
				Action: ActResult,
				Class:  message.Class,
				Room:   room,
			})
		}

	case ActGet:
		switch message.Class {
		case "room":
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				From:   message.To,
				Action: ActResult,
				Class:  message.Class,
				Room:   GetRoom(message.To),
			})
		case "roomlist":
			rooms := []*Room{}
			for _, room := range Rooms() {
				rooms = append(rooms, &Room{
					Id:  room.Id,
					SB:  room.SB,
					BB:  room.BB,
					N:   room.N,
					Max: room.Max,
				})
			}
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				Action: ActResult,
				Class:  message.Class,
				Rooms:  rooms,
			})
		}
	}
}
<commit_msg>fix create room<commit_after>package poker

import (
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

const (
	MsgIQ       = "iq"
	MsgPresence = "presence"
	MsgMessage  = "message"

	ActGet    = "get"
	ActSet    = "set"
	ActResult = "result"

	ActPreflop  = "preflop"
	ActFlop     = "flop"
	ActTurn     = "turn"
	ActRiver    = "river"
	ActShowdown = "showdown"
	ActPot      = "pot"

	ActActive = "active"
	ActJoin   = "join"
	ActLeave  = "gone"
	ActBet    = "bet"
	ActButton = "button"
	ActState  = "state"

	ActAction = "action"
	ActReady  = "ready"
	ActCall   = "call"
	ActCheck  = "check"
	ActRaise  = "raise"
	ActFold   = "fold"
	ActAllin  = "allin"
)

var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin:     func(r *http.Request) bool { return true },
	}
)

type Message struct {
	Id       string    `json:"id,omitempty"`
	Type     string    `json:"type"`
	From     string    `json:"from,omitempty"`
	To       string    `json:"to,omitempty"`
	Action   string    `json:"action"`
	Class    string    `json:"class,omitempty"`
	Occupant *Occupant `json:"occupant,omitempty"`
	Room     *Room     `json:"room,omitempty"`
	Rooms    []*Room   `json:"rooms,omitempty"`
}

type Version struct {
	//Id  string `json:"id"`
	Ver string `json:"version"`
}

type Auth struct {
	Mechanism string `json:"mechanism"`
	Text      string `json:"text"`
}

type AuthResp struct {
	Id    string `json:"id"`
	Name  string `json:"name"`
	Level int    `json:"level"`
	Chips int    `json:"chips"`
}

type Error struct {
	Code int    `json:"code,omitempty"`
	Err  string `json:"error,omitempty"`
}

func NewError(code int, err string) *Error {
	return &Error{
		Code: code,
		Err:  err,
	}
}

func PokerHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer ws.Close()

	ws.SetReadLimit(maxMessageSize)
	ws.SetPongHandler(
		func(string) error {
			ws.SetReadDeadline(time.Now().Add(pongWait))
			return nil
		})
	conn := NewConn(ws, 128)
	defer conn.Close()

	ver := &Version{}
	if err := conn.ReadJSONTimeout(ver, readWait); err != nil {
		return
	}
	if err := conn.WriteJSON(ver); err != nil {
		return
	}

	auth := &Auth{}
	if err := conn.ReadJSONTimeout(auth, readWait); err != nil {
		return
	}

	o := NewOccupant(strconv.FormatInt(time.Now().Unix(), 10), conn)
	o.Name = auth.Text
	o.Chips = 10000

	if err := conn.WriteJSON(o); err != nil {
		return
	}

	for {
		message, _ := o.GetMessage(0)
		if message == nil {
			break
		}

		switch message.Type {
		case MsgIQ:
			go handleIQ(o, message)
		case MsgPresence:
			go handlePresence(o, message)
		case MsgMessage:
		}
	}

	o.Leave()
	log.Println(o.Name, "disconnected.")
}

func handlePresence(o *Occupant, message *Message) {
	switch message.Action {
	case ActJoin:
		if room := o.Join(message.To); room == nil {
			o.SendError(1, "room not found")
			return
		}
	case ActLeave:
		o.Leave()
	case ActBet:
		select {
		case o.Actions <- message:
		default:
		}
	}
}

func handleIQ(o *Occupant, message *Message) {
	switch message.Action {
	case ActSet:
		switch message.Class {
		case "room":
			room := NewRoom("", 9, 5, 10)

			if message.Room != nil {
				if message.Room.SB > 0 {
					room.SB = message.Room.SB
				}
				if message.Room.BB > 0 {
					room.BB = message.Room.BB
				}
				if message.Room.Timeout > 0 {
					room.Timeout = message.Room.Timeout
				}

				if message.Room.Max > 0 && message.Room.Max <= MaxN {
					room.Max = message.Room.Max
					room.Occupants = room.Occupants[:room.Max]
					room.Chips = room.Chips[:room.Max]
				}

				SetRoom(room)
			}
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				From:   room.Id,
				Action: ActResult,
				Class:  message.Class,
				Room:   room,
			})
		}

	case ActGet:
		switch message.Class {
		case "room":
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				From:   message.To,
				Action: ActResult,
				Class:  message.Class,
				Room:   GetRoom(message.To),
			})
		case "roomlist":
			rooms := []*Room{}
			for _, room := range Rooms() {
				rooms = append(rooms, &Room{
					Id:  room.Id,
					SB:  room.SB,
					BB:  room.BB,
					N:   room.N,
					Max: room.Max,
				})
			}
			o.SendMessage(&Message{
				Type:   message.Type,
				Id:     message.Id,
				Action: ActResult,
				Class:  message.Class,
				Rooms:  rooms,
			})
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"net/http"
	"os"
	"strings"
)

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Served %s to %s", r.URL, r.RemoteAddr)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	l, err := net.Listen("tcp4", ":0")
	if err != nil {
		panic(err)
	}
	addr := strings.Split(l.Addr().String(), ":")

	log.Printf("Serving %s at http://localhost:%s/. Ctrl+C to exit", cwd, addr[len(addr)-1])
	log.Fatal(http.Serve(l, Log(http.FileServer(http.Dir(cwd)))))
}
<commit_msg>log.Fatal instead of panic<commit_after>package main

import (
	"log"
	"net"
	"net/http"
	"os"
	"strings"
)

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Served %s to %s", r.URL, r.RemoteAddr)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	l, err := net.Listen("tcp4", ":0")
	if err != nil {
		log.Fatal(err)
	}
	addr := strings.Split(l.Addr().String(), ":")

	log.Printf("Serving %s at http://localhost:%s/. Ctrl+C to exit", cwd, addr[len(addr)-1])
	log.Fatal(http.Serve(l, Log(http.FileServer(http.Dir(cwd)))))
}
<|endoftext|>


<commit_before>package request

import (
	"bytes"
	"io/ioutil"
	"net/http"
)

func NewFromHTTPRequest(r *http.Request) (*Request, error) {

	headers := Headers{}

	for key, values := range r.Header {
		for _, value := range values {
			headers = append(headers, [2]string{key, value})
		}
	}

	// GetBody
	bodyIO, err := r.GetBody()
	if err != nil {
		return nil, err
	}
	defer bodyIO.Close()

	bodyContent, err := ioutil.ReadAll(bodyIO)

	if err != nil {
		return nil, err
	}

	return New(r.Method, r.URL.String(), headers, string(bodyContent), 0), nil

}

func (r *Request) HTTPRequest() (*http.Request, error) {
	bodyIO := bytes.NewBuffer([]byte(r.body))
	httpRequest, err := http.NewRequest(r.method, r.url, bodyIO)

	if err != nil {
		return httpRequest, err
	}

	for _, keyValuePair := range r.headers {
		key := keyValuePair[0]
		value := keyValuePair[1]

		httpRequest.Header.Add(key, value)
	}

	return httpRequest, nil
}
<commit_msg>remove dependency on GetBody set<commit_after>package request

import (
	"bytes"
	"io/ioutil"
	"net/http"
)

func NewFromHTTPRequest(r *http.Request) (*Request, error) {

	headers := Headers{}

	for key, values := range r.Header {
		for _, value := range values {
			headers = append(headers, [2]string{key, value})
		}
	}

	// GetBody
	body, err := ioutil.ReadAll(r.Body)

	if err != nil {
		return nil, err
	}

	r.Body.Close()
	r.Body = ioutil.NopCloser(bytes.NewBuffer(body))

	return New(r.Method, r.URL.String(), headers, string(body), 0), nil

}

func (r *Request) HTTPRequest() (*http.Request, error) {
	bodyIO := bytes.NewBuffer([]byte(r.body))
	httpRequest, err := http.NewRequest(r.method, r.url, bodyIO)

	if err != nil {
		return httpRequest, err
	}

	for _, keyValuePair := range r.headers {
		key := keyValuePair[0]
		value := keyValuePair[1]

		httpRequest.Header.Add(key, value)
	}

	return httpRequest, nil
}
<|endoftext|>


<commit_before><commit_msg>Fix build errors<commit_after><|endoftext|>


<commit_before>package usecase

import (
	"context"
	"time"

	"github.com/oinume/lekcije/backend/domain/repository"
	"github.com/oinume/lekcije/backend/model2"
)

type Lesson struct {
	lessonRepo repository.Lesson
}

func NewLesson(lessonRepo repository.Lesson) *Lesson {
	return &Lesson{
		lessonRepo: lessonRepo,
	}
}

func (u *Lesson) FindLessons(
	ctx context.Context,
	teacherID uint, fromDate, toDate time.Time,
) ([]*model2.Lesson, error) {
	return u.lessonRepo.FindAllByTeacherIDsDatetimeBetween(ctx, teacherID, fromDate, toDate)
}

func (u *Lesson) GetNewAvailableLessons(ctx context.Context, oldLessons, newLessons []*model2.Lesson) []*model2.Lesson {
	return u.lessonRepo.GetNewAvailableLessons(ctx, oldLessons, newLessons)
}
<commit_msg>Define UpdateLessons<commit_after>package usecase

import (
	"context"
	"strings"
	"time"

	"github.com/oinume/lekcije/backend/domain/repository"
	"github.com/oinume/lekcije/backend/errors"
	"github.com/oinume/lekcije/backend/model2"
)

type Lesson struct {
	lessonRepo repository.Lesson
}

func NewLesson(lessonRepo repository.Lesson) *Lesson {
	return &Lesson{
		lessonRepo: lessonRepo,
	}
}

func (u *Lesson) FindLessons(
	ctx context.Context,
	teacherID uint, fromDate, toDate time.Time,
) ([]*model2.Lesson, error) {
	return u.lessonRepo.FindAllByTeacherIDsDatetimeBetween(ctx, teacherID, fromDate, toDate)
}

func (u *Lesson) GetNewAvailableLessons(ctx context.Context, oldLessons, newLessons []*model2.Lesson) []*model2.Lesson {
	return u.lessonRepo.GetNewAvailableLessons(ctx, oldLessons, newLessons)
}

func (u *Lesson) UpdateLessons(ctx context.Context, lessons []*model2.Lesson) (int64, error) {
	if len(lessons) == 0 {
		return 0, nil
	}

	existingLessons, err := u.lessonRepo.FindAllByTeacherIDAndDatetimeAsMap(ctx, lessons[0].TeacherID, lessons)
	if err != nil {
		return 0, err
	}

	rowsAffected := 0
	now := time.Now().UTC()
	for _, lesson := range lessons {
		lesson.Status = strings.ToLower(lesson.Status)
		if l, ok := existingLessons[lesson.Datetime.Format(lessonTimeFormat)]; ok {
			if lesson.Status == l.Status {
				continue
			}
			// UPDATE
			values := &Lesson{Status: lesson.Status, UpdatedAt: now}
			if err := s.db.Model(lesson).Where("id = ?", l.ID).Updates(values).Error; err != nil {
				return 0, errors.NewInternalError(
					errors.WithError(err),
				)
			}
			rowsAffected++

			log := &LessonStatusLog{
				LessonID:  l.ID,
				Status:    lesson.Status,
				CreatedAt: now,
			}
			if err := NewLessonStatusLogService(s.db).Create(log); err != nil {
				return 0, err
			}
		} else {
			// INSERT
			dt := lesson.Datetime
			lesson.Datetime = time.Date(dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second(), 0, time.UTC)
			where := Lesson{TeacherID: lesson.TeacherID, Datetime: lesson.Datetime}
			if err := s.db.Where(where).FirstOrCreate(lesson).Error; err != nil {
				return 0, errors.NewInternalError(
					errors.WithError(err),
					errors.WithMessage("FirstOrCreate failed"),
					errors.WithResource(errors.NewResourceWithEntries(
						s.TableName(),
						[]errors.ResourceEntry{
							{Key: "teacherID", Value: lesson.TeacherID},
							{Key: "datetime", Value: lesson.Datetime},
						},
					)),
				)
			}
			rowsAffected++

			log := &LessonStatusLog{
				LessonID:  lesson.ID,
				Status:    lesson.Status,
				CreatedAt: now,
			}
			if err := NewLessonStatusLogService(s.db).Create(log); err != nil {
				return 0, err
			}
		}
	}

	return int64(rowsAffected), nil
}
<|endoftext|>


<commit_before>// Copyright 2014, Truveris Inc. All Rights Reserved.

package main

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

	"github.com/tamentis/go-mplayer"
)

var (
	RunningProcess *os.Process

	// This is the noise box, we keep as much as possible in local memory,
	// that makes 'shutup' remotely useful. Without buffer we would have to
	// wait through orders before even reaching the 'shutup' command.
	NoiseInbox = make(chan Noise, 1000)
)

type Noise struct {
	Path     string
	Duration time.Duration
	Sentence string
}

func playTune(tune Noise) {
	cmd := player(tune)
	if cmd == nil {
		return
	}

	err := cmd.Start()
	if err != nil {
		log.Printf("error on mplayer Start(): %s", err.Error())
	}

	RunningProcess = cmd.Process

	err = cmd.Wait()
	if err != nil {
		log.Printf("error on mplayer Wait(): %s", err.Error())
	}

	RunningProcess = nil
}

func playNoise(noiseInbox chan Noise) {
	for noise := range noiseInbox {
		if noise.Sentence != "" {
			say(noise.Sentence)
		} else {
			playTune(noise)
		}
	}
}

// Empty the noise inbox ...
func ShutUp() {
	log.Printf("shutup: deleting %d items from the noise queue",
		len(NoiseInbox))

	if len(NoiseInbox) > 0 {
		for _ = range NoiseInbox {
			if len(NoiseInbox) == 0 {
				break
			}
		}
	}

	mplayer.SendCommand("stop")

	// ... then kill whatever is currently running.
	if RunningProcess != nil {
		if err := RunningProcess.Kill(); err != nil {
			log.Printf("error trying to kill "+
				"current process: %s",
				err.Error())
		}
	}
}

func Say(data string) {
	noise := Noise{}
	noise.Sentence = data
	NoiseInbox <- noise
}

func Play(data string) {
	if data == "" {
		return
	}

	tokens := strings.Split(data, " ")
	tune := Noise{}
	tune.Path = tokens[0]
	if len(tokens) > 1 {
		duration, err := time.ParseDuration(tokens[1])
		if err != nil {
			Send("play error invalid duration: " + err.Error())
			return
		}
		tune.Duration = duration
	}
	NoiseInbox <- tune
}
<commit_msg>Don't crash if the duration is fucked, just assume no duration.<commit_after>// Copyright 2014, Truveris Inc. All Rights Reserved.

package main

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

	"github.com/tamentis/go-mplayer"
)

var (
	RunningProcess *os.Process

	// This is the noise box, we keep as much as possible in local memory,
	// that makes 'shutup' remotely useful. Without buffer we would have to
	// wait through orders before even reaching the 'shutup' command.
	NoiseInbox = make(chan Noise, 1000)
)

type Noise struct {
	Path     string
	Duration time.Duration
	Sentence string
}

func playTune(tune Noise) {
	cmd := player(tune)
	if cmd == nil {
		return
	}

	err := cmd.Start()
	if err != nil {
		log.Printf("error on mplayer Start(): %s", err.Error())
	}

	RunningProcess = cmd.Process

	err = cmd.Wait()
	if err != nil {
		log.Printf("error on mplayer Wait(): %s", err.Error())
	}

	RunningProcess = nil
}

func playNoise(noiseInbox chan Noise) {
	for noise := range noiseInbox {
		if noise.Sentence != "" {
			say(noise.Sentence)
		} else {
			playTune(noise)
		}
	}
}

// Empty the noise inbox ...
func ShutUp() {
	log.Printf("shutup: deleting %d items from the noise queue",
		len(NoiseInbox))

	if len(NoiseInbox) > 0 {
		for _ = range NoiseInbox {
			if len(NoiseInbox) == 0 {
				break
			}
		}
	}

	mplayer.SendCommand("stop")

	// ... then kill whatever is currently running.
	if RunningProcess != nil {
		if err := RunningProcess.Kill(); err != nil {
			log.Printf("error trying to kill "+
				"current process: %s",
				err.Error())
		}
	}
}

func Say(data string) {
	noise := Noise{}
	noise.Sentence = data
	NoiseInbox <- noise
}

func Play(data string) {
	if data == "" {
		return
	}

	tokens := strings.Split(data, " ")
	tune := Noise{}
	tune.Path = tokens[0]
	if len(tokens) > 1 {
		duration, err := time.ParseDuration(tokens[1])
		if err != nil {
			Send("play warning invalid duration: " + err.Error())
		} else {
			tune.Duration = duration
		}
	}
	NoiseInbox <- tune
}
<|endoftext|>


<commit_before>package commandline

import (
	"fmt"
	"strings"
)

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type CommandT struct {
	args []token
}

func parse(src []byte) *CommandT {
	s := scan(src)
	var args []token
	for t := range s.tokens {
		args = append(args, t)
	}
	return &CommandT{args: args}
}

type scanner struct {
	src   []byte
	size  int
	start int
	off   int

	tokens chan token
}

func (s *scanner) next() (byte, bool) {
	if s.off >= s.size {
		return 0, true
	}

	ret := s.src[s.off]

	s.off++
	return ret, false
}

func (s *scanner) error(msg string) *scanError {
	return &scanError{
		msg: msg,
		off: s.off,
	}
}

type scanError struct {
	msg string
	off int
}

func (s *scanError) Error() string {
	return fmt.Sprintf("byte offset %d: %s", s.off, s.msg)
}

func isWhitespace(b byte) bool {
	return b == ' '
}

func isIdent(b byte) bool {
	return 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z'
}

type stateFn func(*scanner) stateFn

func scan(src []byte) *scanner {
	s := &scanner{
		src:    src,
		size:   len(src),
		tokens: make(chan token),
	}
	go s.run()
	return s
}

func (s *scanner) run() {
	for state := scanToken; state != nil; {
		state = state(s)
	}
	close(s.tokens)
}

func scanToken(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		switch {
		case isWhitespace(b):
			s.start = s.off
		case isIdent(b):
			return scanIdent
		case b == '"':
			return scanString
		default:
			s.emit(tokenErr)
			return nil
		}
	}
	s.emit(tokenEOF)
	return nil
}

func scanIdent(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		if !isIdent(b) {
			s.off--
			break
		}
	}
	if s.start < s.off {
		s.emit(tokenIdent)
		return scanToken
	}
	s.emit(tokenEOF)
	return nil
}

func scanString(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		if b == '"' {
			s.emit(tokenString) // including quotes
			return scanToken
		}
	}
	if s.start < s.off {
		s.emit(tokenErr)
		return nil
	}
	s.emit(tokenEOF)
	return nil
}

func (s *scanner) emit(tt tokenType) {
	s.tokens <- token{
		tt:    tt,
		value: s.src[s.start:s.off],
	}
	s.start = s.off
}

type tokenType int

type token struct {
	tt    tokenType
	value []byte
}

const (
	tokenErr tokenType = iota
	tokenEOF
	tokenIdent
	tokenString
)
<commit_msg>Add parseIdent<commit_after>package commandline

import (
	"fmt"
	"strings"
)

func Parse(s string) *Command {
	ss := strings.Split(s, " ")
	if ss[0] == "" {
		return nil
	}
	return &Command{
		Name: ss[0],
		Args: ss[1:],
	}
}

type Command struct {
	Name string
	Args []string
}

type CommandT struct {
	args []token
}

func parse(src []byte) *CommandT {
	s := scan(src)
	_ = parseIdent(s.tokens)
	var args []token
	for t := range s.tokens {
		args = append(args, t)
	}
	return &CommandT{args: args}
}

func parseIdent(ch chan token) token {
	t := <-ch
	if t.tt != tokenIdent {
		panic("not identifier")
	}
	return t
}

type scanner struct {
	src   []byte
	size  int
	start int
	off   int

	tokens chan token
}

func (s *scanner) next() (byte, bool) {
	if s.off >= s.size {
		return 0, true
	}

	ret := s.src[s.off]

	s.off++
	return ret, false
}

func (s *scanner) error(msg string) *scanError {
	return &scanError{
		msg: msg,
		off: s.off,
	}
}

type scanError struct {
	msg string
	off int
}

func (s *scanError) Error() string {
	return fmt.Sprintf("byte offset %d: %s", s.off, s.msg)
}

func isWhitespace(b byte) bool {
	return b == ' '
}

func isIdent(b byte) bool {
	return 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z'
}

type stateFn func(*scanner) stateFn

func scan(src []byte) *scanner {
	s := &scanner{
		src:    src,
		size:   len(src),
		tokens: make(chan token),
	}
	go s.run()
	return s
}

func (s *scanner) run() {
	for state := scanToken; state != nil; {
		state = state(s)
	}
	close(s.tokens)
}

func scanToken(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		switch {
		case isWhitespace(b):
			s.start = s.off
		case isIdent(b):
			return scanIdent
		case b == '"':
			return scanString
		default:
			s.emit(tokenErr)
			return nil
		}
	}
	s.emit(tokenEOF)
	return nil
}

func scanIdent(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		if !isIdent(b) {
			s.off--
			break
		}
	}
	if s.start < s.off {
		s.emit(tokenIdent)
		return scanToken
	}
	s.emit(tokenEOF)
	return nil
}

func scanString(s *scanner) stateFn {
	for {
		b, eof := s.next()
		if eof {
			break
		}
		if b == '"' {
			s.emit(tokenString) // including quotes
			return scanToken
		}
	}
	if s.start < s.off {
		s.emit(tokenErr)
		return nil
	}
	s.emit(tokenEOF)
	return nil
}

func (s *scanner) emit(tt tokenType) {
	s.tokens <- token{
		tt:    tt,
		value: s.src[s.start:s.off],
	}
	s.start = s.off
}

type tokenType int

type token struct {
	tt    tokenType
	value []byte
}

const (
	tokenErr tokenType = iota
	tokenEOF
	tokenIdent
	tokenString
)
<|endoftext|>


<commit_before>package constants

const (
	BOSHURL        = "https://s3.amazonaws.com/bbl-precompiled-bosh-releases/release-bosh-257.15-on-ubuntu-trusty-stemcell-3263.7.tgz"
	BOSHSHA1       = ""
	BOSHAWSCPIURL  = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-aws-cpi-release?v=60"
	BOSHAWSCPISHA1 = "8e40a9ff892204007889037f094a1b0d23777058"
	StemcellURL    = "https://d26ekeud912fhb.cloudfront.net/bosh-stemcell/aws/light-bosh-stemcell-3263.7-aws-xen-hvm-ubuntu-trusty-go_agent.tgz"
	StemcellSHA1   = "6f09d8ed6514a22eaafefa97dcd916f1fc357631"
)
<commit_msg>Update bosh release sha1<commit_after>package constants

// THIS FILE IS GENERATED AUTOMATICALLY, NO TOUCHING!!!!!

const (
	BOSHURL        = "https://s3.amazonaws.com/bbl-precompiled-bosh-releases/release-bosh-257.15-on-ubuntu-trusty-stemcell-3263.7.tgz"
	BOSHSHA1       = "e72406ddbfc4ebb7e389544c0c48802780a54f1c"
	BOSHAWSCPIURL  = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-aws-cpi-release?v=60"
	BOSHAWSCPISHA1 = "8e40a9ff892204007889037f094a1b0d23777058"
	StemcellURL    = "https://d26ekeud912fhb.cloudfront.net/bosh-stemcell/aws/light-bosh-stemcell-3263.7-aws-xen-hvm-ubuntu-trusty-go_agent.tgz"
	StemcellSHA1   = "6f09d8ed6514a22eaafefa97dcd916f1fc357631"
)
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package zip_test

import (
	"bytes"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"sort"

	gc "launchpad.net/gocheck"

	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/utils/zip"
)

type ZipSuite struct {
	BaseSuite
}

var _ = gc.Suite(&ZipSuite{})

func (s *ZipSuite) TestFind(c *gc.C) {
	reader := s.makeZip(c,
		file{"some-file", "", 0644},
		file{"another-file", "", 0644},
		symlink{"some-symlink", "some-file"},
		dir{"some-dir", 0755},
		dir{"some-dir/another-dir", 0755},
		file{"some-dir/another-file", "", 0644},
	)

	for i, test := range []struct {
		pattern string
		expect  []string
	}{{
		"", nil,
	}, {
		"no-matches", nil,
	}, {
		"some-file", []string{
			"some-file"},
	}, {
		"another-file", []string{
			"another-file",
			"some-dir/another-file"},
	}, {
		"some-*", []string{
			"some-file",
			"some-symlink",
			"some-dir"},
	}, {
		"another-*", []string{
			"another-file",
			"some-dir/another-dir",
			"some-dir/another-file"},
	}, {
		"*", []string{
			"some-file",
			"another-file",
			"some-symlink",
			"some-dir",
			"some-dir/another-dir",
			"some-dir/another-file"},
	}} {
		c.Logf("test %d: %q", i, test.pattern)
		actual, err := zip.Find(reader, test.pattern)
		c.Assert(err, gc.IsNil)
		sort.Strings(test.expect)
		sort.Strings(actual)
		c.Check(actual, jc.DeepEquals, test.expect)
	}

	c.Logf("test $spanish-inquisition: FindAll")
	expect, err := zip.Find(reader, "*")
	c.Assert(err, gc.IsNil)
	actual, err := zip.FindAll(reader)
	c.Assert(err, gc.IsNil)
	sort.Strings(expect)
	sort.Strings(actual)
	c.Check(actual, jc.DeepEquals, expect)
}

func (s *ZipSuite) TestFindError(c *gc.C) {
	reader := s.makeZip(c, file{"some-file", "", 0644})
	_, err := zip.Find(reader, "[]")
	c.Assert(err, gc.ErrorMatches, "syntax error in pattern")
}

func (s *ZipSuite) TestExtractAll(c *gc.C) {
	creators := []creator{
		file{"some-file", "content 1", 0644},
		file{"another-file", "content 2", 0640},
		symlink{"some-symlink", "some-file"},
		dir{"some-dir", 0750},
		file{"some-dir/another-file", "content 3", 0644},
		dir{"some-dir/another-dir", 0755},
		symlink{"some-dir/another-dir/another-symlink", "../../another-file"},
	}
	reader := s.makeZip(c, creators...)
	targetPath := c.MkDir()
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)
	for i, creator := range creators {
		c.Logf("test %d: %#v", i, creator)
		creator.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteFiles(c *gc.C) {
	name := "some-file"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		file{name, "original", 0}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteSymlinks(c *gc.C) {
	name := "some-symlink"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		original := file{"original", "content", 0644}
		original.create(c, targetPath)
		symlink{name, "original"}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
		original.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteDirs(c *gc.C) {
	name := "some-dir"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		dir{name, 0}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllMergeDirs(c *gc.C) {
	targetPath := c.MkDir()
	dir{"dir", 0755}.create(c, targetPath)
	originals := []creator{
		dir{"dir/original-dir", 0751},
		file{"dir/original-file", "content 1", 0600},
		symlink{"dir/original-symlink", "original-file"},
	}
	for _, creator := range originals {
		creator.create(c, targetPath)
	}
	merges := []creator{
		dir{"dir", 0751},
		dir{"dir/merge-dir", 0750},
		file{"dir/merge-file", "content 2", 0640},
		symlink{"dir/merge-symlink", "merge-file"},
	}
	reader := s.makeZip(c, merges...)
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)

	for i, test := range append(originals, merges...) {
		c.Logf("test %d: %#v", i, test)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllSymlinkErrors(c *gc.C) {
	for i, test := range []struct {
		content []creator
		error   string
	}{{
		content: []creator{
			symlink{"symlink", "/blah"},
		},
		error: `cannot extract "symlink": symlink "/blah" is absolute`,
	}, {
		content: []creator{
			symlink{"symlink", "../blah"},
		},
		error: `cannot extract "symlink": symlink "../blah" leads out of scope`,
	}, {
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "../../blah"},
		},
		error: `cannot extract "dir/symlink": symlink "../../blah" leads out of scope`,
	}} {
		c.Logf("test %d: %s", i, test.error)
		targetPath := c.MkDir()
		reader := s.makeZip(c, test.content...)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.ErrorMatches, test.error)
	}
}

func (s *ZipSuite) TestExtractDir(c *gc.C) {
	reader := s.makeZip(c,
		file{"bad-file", "xxx", 0644},
		dir{"bad-dir", 0755},
		symlink{"bad-symlink", "bad-file"},
		dir{"some-dir", 0751},
		file{"some-dir-bad-lol", "xxx", 0644},
		file{"some-dir/some-file", "content 1", 0644},
		file{"some-dir/another-file", "content 2", 0600},
		dir{"some-dir/another-dir", 0750},
		symlink{"some-dir/another-dir/some-symlink", "../some-file"},
	)
	targetParent := c.MkDir()
	targetPath := filepath.Join(targetParent, "random-dir")
	err := zip.Extract(reader, targetPath, "some-dir")
	c.Assert(err, gc.IsNil)

	for i, test := range []creator{
		dir{"random-dir", 0751},
		file{"random-dir/some-file", "content 1", 0644},
		file{"random-dir/another-file", "content 2", 0600},
		dir{"random-dir/another-dir", 0750},
		symlink{"random-dir/another-dir/some-symlink", "../some-file"},
	} {
		c.Logf("test %d: %#v", i, test)
		test.check(c, targetParent)
	}

	fileInfos, err := ioutil.ReadDir(targetParent)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 1)

	fileInfos, err = ioutil.ReadDir(targetPath)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 3)
}

func (s *ZipSuite) TestExtractSingleFile(c *gc.C) {
	reader := s.makeZip(c,
		dir{"dir", 0755},
		dir{"dir/dir", 0755},
		file{"dir/dir/some-file", "content 1", 0644},
		file{"dir/dir/some-file-wtf", "content 2", 0644},
	)
	targetParent := c.MkDir()
	targetPath := filepath.Join(targetParent, "just-the-one-file")
	err := zip.Extract(reader, targetPath, "dir/dir/some-file")
	c.Assert(err, gc.IsNil)
	fileInfos, err := ioutil.ReadDir(targetParent)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 1)
	file{"just-the-one-file", "content 1", 0644}.check(c, targetParent)
}

func (s *ZipSuite) TestClosesFile(c *gc.C) {
	reader := s.makeZip(c, file{"f", "echo hullo!", 0755})
	targetPath := c.MkDir()
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)
	cmd := exec.Command("/bin/sh", "-c", filepath.Join(targetPath, "f"))
	var buffer bytes.Buffer
	cmd.Stdout = &buffer
	err = cmd.Run()
	c.Assert(err, gc.IsNil)
	c.Assert(buffer.String(), gc.Equals, "hullo!\n")
}

func (s *ZipSuite) TestExtractSymlinkErrors(c *gc.C) {
	for i, test := range []struct {
		content []creator
		source  string
		error   string
	}{{
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "/blah"},
		},
		source: "dir",
		error:  `cannot extract "dir/symlink": symlink "/blah" is absolute`,
	}, {
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "../blah"},
		},
		source: "dir",
		error:  `cannot extract "dir/symlink": symlink "../blah" leads out of scope`,
	}, {
		content: []creator{
			symlink{"symlink", "blah"},
		},
		source: "symlink",
		error:  `cannot extract "symlink": symlink "blah" leads out of scope`,
	}} {
		c.Logf("test %d: %s", i, test.error)
		targetPath := c.MkDir()
		reader := s.makeZip(c, test.content...)
		err := zip.Extract(reader, targetPath, test.source)
		c.Check(err, gc.ErrorMatches, test.error)
	}
}

func (s *ZipSuite) TestExtractSourceError(c *gc.C) {
	reader := s.makeZip(c, dir{"dir", 0755})
	err := zip.Extract(reader, c.MkDir(), "../lol")
	c.Assert(err, gc.ErrorMatches, `cannot extract files rooted at "../lol"`)
}
<commit_msg>address review<commit_after>// Copyright 2011-2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package zip_test

import (
	"bytes"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"sort"

	gc "launchpad.net/gocheck"

	jc "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/utils/zip"
)

type ZipSuite struct {
	BaseSuite
}

var _ = gc.Suite(&ZipSuite{})

func (s *ZipSuite) TestFind(c *gc.C) {
	reader := s.makeZip(c,
		file{"some-file", "", 0644},
		file{"another-file", "", 0644},
		symlink{"some-symlink", "some-file"},
		dir{"some-dir", 0755},
		dir{"some-dir/another-dir", 0755},
		file{"some-dir/another-file", "", 0644},
	)

	for i, test := range []struct {
		pattern string
		expect  []string
	}{{
		"", nil,
	}, {
		"no-matches", nil,
	}, {
		"some-file", []string{
			"some-file"},
	}, {
		"another-file", []string{
			"another-file",
			"some-dir/another-file"},
	}, {
		"some-*", []string{
			"some-file",
			"some-symlink",
			"some-dir"},
	}, {
		"another-*", []string{
			"another-file",
			"some-dir/another-dir",
			"some-dir/another-file"},
	}, {
		"*", []string{
			"some-file",
			"another-file",
			"some-symlink",
			"some-dir",
			"some-dir/another-dir",
			"some-dir/another-file"},
	}} {
		c.Logf("test %d: %q", i, test.pattern)
		actual, err := zip.Find(reader, test.pattern)
		c.Assert(err, gc.IsNil)
		sort.Strings(test.expect)
		sort.Strings(actual)
		c.Check(actual, jc.DeepEquals, test.expect)
	}

	c.Logf("test $spanish-inquisition: FindAll")
	expect, err := zip.Find(reader, "*")
	c.Assert(err, gc.IsNil)
	actual, err := zip.FindAll(reader)
	c.Assert(err, gc.IsNil)
	sort.Strings(expect)
	sort.Strings(actual)
	c.Check(actual, jc.DeepEquals, expect)
}

func (s *ZipSuite) TestFindError(c *gc.C) {
	reader := s.makeZip(c, file{"some-file", "", 0644})
	_, err := zip.Find(reader, "[]")
	c.Assert(err, gc.ErrorMatches, "syntax error in pattern")
}

func (s *ZipSuite) TestExtractAll(c *gc.C) {
	creators := []creator{
		file{"some-file", "content 1", 0644},
		file{"another-file", "content 2", 0640},
		symlink{"some-symlink", "some-file"},
		dir{"some-dir", 0750},
		file{"some-dir/another-file", "content 3", 0644},
		dir{"some-dir/another-dir", 0755},
		symlink{"some-dir/another-dir/another-symlink", "../../another-file"},
	}
	reader := s.makeZip(c, creators...)
	targetPath := c.MkDir()
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)
	for i, creator := range creators {
		c.Logf("test %d: %#v", i, creator)
		creator.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteFiles(c *gc.C) {
	name := "some-file"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		file{name, "original", 0}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteSymlinks(c *gc.C) {
	name := "some-symlink"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		original := file{"original", "content", 0644}
		original.create(c, targetPath)
		symlink{name, "original"}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
		original.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllOverwriteDirs(c *gc.C) {
	name := "some-dir"
	for i, test := range []creator{
		file{name, "content", 0644},
		dir{name, 0751},
		symlink{name, "wherever"},
	} {
		c.Logf("test %d: %#v", i, test)
		targetPath := c.MkDir()
		dir{name, 0}.create(c, targetPath)
		reader := s.makeZip(c, test)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.IsNil)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllMergeDirs(c *gc.C) {
	targetPath := c.MkDir()
	dir{"dir", 0755}.create(c, targetPath)
	originals := []creator{
		dir{"dir/original-dir", 0751},
		file{"dir/original-file", "content 1", 0600},
		symlink{"dir/original-symlink", "original-file"},
	}
	for _, creator := range originals {
		creator.create(c, targetPath)
	}
	merges := []creator{
		dir{"dir", 0751},
		dir{"dir/merge-dir", 0750},
		file{"dir/merge-file", "content 2", 0640},
		symlink{"dir/merge-symlink", "merge-file"},
	}
	reader := s.makeZip(c, merges...)
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)

	for i, test := range append(originals, merges...) {
		c.Logf("test %d: %#v", i, test)
		test.check(c, targetPath)
	}
}

func (s *ZipSuite) TestExtractAllSymlinkErrors(c *gc.C) {
	for i, test := range []struct {
		content []creator
		error   string
	}{{
		content: []creator{
			symlink{"symlink", "/blah"},
		},
		error: `cannot extract "symlink": symlink "/blah" is absolute`,
	}, {
		content: []creator{
			symlink{"symlink", "../blah"},
		},
		error: `cannot extract "symlink": symlink "../blah" leads out of scope`,
	}, {
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "../../blah"},
		},
		error: `cannot extract "dir/symlink": symlink "../../blah" leads out of scope`,
	}} {
		c.Logf("test %d: %s", i, test.error)
		targetPath := c.MkDir()
		reader := s.makeZip(c, test.content...)
		err := zip.ExtractAll(reader, targetPath)
		c.Check(err, gc.ErrorMatches, test.error)
	}
}

func (s *ZipSuite) TestExtractDir(c *gc.C) {
	reader := s.makeZip(c,
		file{"bad-file", "xxx", 0644},
		dir{"bad-dir", 0755},
		symlink{"bad-symlink", "bad-file"},
		dir{"some-dir", 0751},
		file{"some-dir-bad-lol", "xxx", 0644},
		file{"some-dir/some-file", "content 1", 0644},
		file{"some-dir/another-file", "content 2", 0600},
		dir{"some-dir/another-dir", 0750},
		symlink{"some-dir/another-dir/some-symlink", "../some-file"},
	)
	targetParent := c.MkDir()
	targetPath := filepath.Join(targetParent, "random-dir")
	err := zip.Extract(reader, targetPath, "some-dir")
	c.Assert(err, gc.IsNil)

	for i, test := range []creator{
		dir{"random-dir", 0751},
		file{"random-dir/some-file", "content 1", 0644},
		file{"random-dir/another-file", "content 2", 0600},
		dir{"random-dir/another-dir", 0750},
		symlink{"random-dir/another-dir/some-symlink", "../some-file"},
	} {
		c.Logf("test %d: %#v", i, test)
		test.check(c, targetParent)
	}

	fileInfos, err := ioutil.ReadDir(targetParent)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 1)

	fileInfos, err = ioutil.ReadDir(targetPath)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 3)
}

func (s *ZipSuite) TestExtractSingleFile(c *gc.C) {
	reader := s.makeZip(c,
		dir{"dir", 0755},
		dir{"dir/dir", 0755},
		file{"dir/dir/some-file", "content 1", 0644},
		file{"dir/dir/some-file-wtf", "content 2", 0644},
	)
	targetParent := c.MkDir()
	targetPath := filepath.Join(targetParent, "just-the-one-file")
	err := zip.Extract(reader, targetPath, "dir/dir/some-file")
	c.Assert(err, gc.IsNil)
	fileInfos, err := ioutil.ReadDir(targetParent)
	c.Check(err, gc.IsNil)
	c.Check(fileInfos, gc.HasLen, 1)
	file{"just-the-one-file", "content 1", 0644}.check(c, targetParent)
}

func (s *ZipSuite) TestClosesFile(c *gc.C) {
	reader := s.makeZip(c, file{"f", "echo hullo!", 0755})
	targetPath := c.MkDir()
	err := zip.ExtractAll(reader, targetPath)
	c.Assert(err, gc.IsNil)
	cmd := exec.Command("/bin/sh", "-c", filepath.Join(targetPath, "f"))
	var buffer bytes.Buffer
	cmd.Stdout = &buffer
	err = cmd.Run()
	c.Assert(err, gc.IsNil)
	c.Assert(buffer.String(), gc.Equals, "hullo!\n")
}

func (s *ZipSuite) TestExtractSymlinkErrors(c *gc.C) {
	for i, test := range []struct {
		content []creator
		source  string
		error   string
	}{{
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "/blah"},
		},
		source: "dir",
		error:  `cannot extract "dir/symlink": symlink "/blah" is absolute`,
	}, {
		content: []creator{
			dir{"dir", 0755},
			symlink{"dir/symlink", "../blah"},
		},
		source: "dir",
		error:  `cannot extract "dir/symlink": symlink "../blah" leads out of scope`,
	}, {
		content: []creator{
			symlink{"symlink", "blah"},
		},
		source: "symlink",
		error:  `cannot extract "symlink": symlink "blah" leads out of scope`,
	}} {
		c.Logf("test %d: %s", i, test.error)
		targetPath := c.MkDir()
		reader := s.makeZip(c, test.content...)
		err := zip.Extract(reader, targetPath, test.source)
		c.Check(err, gc.ErrorMatches, test.error)
	}
}

func (s *ZipSuite) TestExtractSourceError(c *gc.C) {
	reader := s.makeZip(c, dir{"dir", 0755})
	err := zip.Extract(reader, c.MkDir(), "../lol")
	c.Assert(err, gc.ErrorMatches, `cannot extract files rooted at "../lol"`)
}
<|endoftext|>


<commit_before>package workflow

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/go-gorp/gorp"
	"github.com/mitchellh/mapstructure"

	"github.com/ovh/cds/engine/api/event"
	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/exportentities"
	"github.com/ovh/cds/sdk/log"
)

var (
	audits = map[string]sdk.Audit{
		fmt.Sprintf("%T", sdk.EventWorkflowAdd{}):              addWorkflowAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowUpdate{}):           updateWorkflowAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowDelete{}):           deleteWorkflowAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionAdd{}):    addWorkflowPermissionAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionUpdate{}): updateWorkflowPermissionAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionDelete{}): deleteWorkflowPermissionAudit{},
	}
)

// ComputeAudit Compute audit on workflow
func ComputeAudit(ctx context.Context, DBFunc func() *gorp.DbMap) {
	chanEvent := make(chan sdk.Event)
	event.Subscribe(chanEvent)
	deleteTicker := time.NewTicker(15 * time.Minute)
	defer deleteTicker.Stop()

	db := DBFunc()
	for {
		select {
		case <-ctx.Done():
			if ctx.Err() != nil {
				log.Error(ctx, "ComputeWorkflowAudit> Exiting: %v", ctx.Err())
				return
			}
		case <-deleteTicker.C:
			if err := purgeAudits(ctx, DBFunc()); err != nil {
				log.Error(ctx, "ComputeWorkflowAudit> Purge error: %v", err)
			}
		case e := <-chanEvent:
			if !strings.HasPrefix(e.EventType, "sdk.EventWorkflow") {
				continue
			}

			if audit, ok := audits[e.EventType]; ok {
				if err := audit.Compute(ctx, db, e); err != nil {
					log.Warning(ctx, "ComputeAudit> Unable to compute audit on event %s: %v", e.EventType, err)
				}
			}
		}
	}
}

type addWorkflowAudit struct{}

func (a addWorkflowAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowAdd
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	buffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.Workflow, exportentities.FormatYAML, buffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.Workflow.ID,
		ProjectKey: e.ProjectKey,
		DataType:   "yaml",
		DataAfter:  buffer.String(),
	})
}

type updateWorkflowAudit struct{}

func (u updateWorkflowAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowUpdate
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	oldWorkflowBuffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.OldWorkflow, exportentities.FormatYAML, oldWorkflowBuffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	newWorkflowBuffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.NewWorkflow, exportentities.FormatYAML, newWorkflowBuffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.NewWorkflow.ID,
		ProjectKey: e.ProjectKey,
		DataType:   "yaml",
		DataAfter:  newWorkflowBuffer.String(),
		DataBefore: oldWorkflowBuffer.String(),
	})
}

type deleteWorkflowAudit struct{}

func (d deleteWorkflowAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowDelete
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	oldWorkflowBuffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.Workflow, exportentities.FormatYAML, oldWorkflowBuffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.Workflow.ID,
		ProjectKey: e.ProjectKey,
		DataType:   "yaml",
		DataBefore: oldWorkflowBuffer.String(),
	})
}

type addWorkflowPermissionAudit struct{}

func (a addWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionAdd
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	b, err := json.MarshalIndent(wEvent.Permission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.WorkflowID,
		ProjectKey: e.ProjectKey,
		DataType:   "json",
		DataAfter:  string(b),
	})
}

type updateWorkflowPermissionAudit struct{}

func (u updateWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionUpdate
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	oldPerm, err := json.MarshalIndent(wEvent.OldPermission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal old permission")
	}

	newPerm, err := json.MarshalIndent(wEvent.NewPermission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal new permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.WorkflowID,
		ProjectKey: e.ProjectKey,
		DataType:   "json",
		DataBefore: string(oldPerm),
		DataAfter:  string(newPerm),
	})
}

type deleteWorkflowPermissionAudit struct{}

func (a deleteWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionDelete
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	b, err := json.MarshalIndent(wEvent.Permission, "", " ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		ProjectKey: e.ProjectKey,
		WorkflowID: wEvent.WorkflowID,
		DataType:   "json",
		DataBefore: string(b),
	})
}

const keepAudits = 50

func purgeAudits(ctx context.Context, db gorp.SqlExecutor) error {
	var nbAuditsPerWorkflowID = []struct {
		WorkflowID int64 `db:"workflow_id"`
		NbAudits   int64 `db:"nb_audits"`
	}{}

	query := `select workflow_id, count(id) "nb_audits" from workflow_audit group by workflow_id having count(id)  > $1`
	if _, err := db.Select(&nbAuditsPerWorkflowID, query, keepAudits); err != nil {
		return sdk.WithStack(err)
	}

	for _, r := range nbAuditsPerWorkflowID {
		log.Debug("purgeAudits> deleting audits for workflow %d (%d audits)", r.WorkflowID, r.NbAudits)
		var ids []int64
		query = `select id from workflow_audit where workflow_id = $1 order by created desc offset $2`
		if _, err := db.Select(&ids, query, r.WorkflowID, keepAudits); err != nil {
			return sdk.WithStack(err)
		}
		for _, id := range ids {
			if err := deleteAudit(db, id); err != nil {
				log.Error(ctx, "purgeAudits> unable to delete audit %d: %v", id, err)
			}
		}
	}

	return nil
}

func deleteAudit(db gorp.SqlExecutor, id int64) error {
	_, err := db.Exec(`delete from workflow_audit where id = $1`, id)
	return sdk.WithStack(err)
}
<commit_msg>fix(api): workflow deletion audits do not work (#4966)<commit_after>package workflow

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/go-gorp/gorp"
	"github.com/mitchellh/mapstructure"

	"github.com/ovh/cds/engine/api/event"
	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/exportentities"
	"github.com/ovh/cds/sdk/log"
)

var (
	audits = map[string]sdk.Audit{
		fmt.Sprintf("%T", sdk.EventWorkflowAdd{}):              addWorkflowAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowUpdate{}):           updateWorkflowAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionAdd{}):    addWorkflowPermissionAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionUpdate{}): updateWorkflowPermissionAudit{},
		fmt.Sprintf("%T", sdk.EventWorkflowPermissionDelete{}): deleteWorkflowPermissionAudit{},
	}
)

// ComputeAudit Compute audit on workflow
func ComputeAudit(ctx context.Context, DBFunc func() *gorp.DbMap) {
	chanEvent := make(chan sdk.Event)
	event.Subscribe(chanEvent)
	deleteTicker := time.NewTicker(15 * time.Minute)
	defer deleteTicker.Stop()

	db := DBFunc()
	for {
		select {
		case <-ctx.Done():
			if ctx.Err() != nil {
				log.Error(ctx, "ComputeWorkflowAudit> Exiting: %v", ctx.Err())
				return
			}
		case <-deleteTicker.C:
			if err := purgeAudits(ctx, DBFunc()); err != nil {
				log.Error(ctx, "ComputeWorkflowAudit> Purge error: %v", err)
			}
		case e := <-chanEvent:
			if !strings.HasPrefix(e.EventType, "sdk.EventWorkflow") {
				continue
			}

			if audit, ok := audits[e.EventType]; ok {
				if err := audit.Compute(ctx, db, e); err != nil {
					log.Warning(ctx, "ComputeAudit> Unable to compute audit on event %s: %v", e.EventType, err)
				}
			}
		}
	}
}

type addWorkflowAudit struct{}

func (a addWorkflowAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowAdd
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	buffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.Workflow, exportentities.FormatYAML, buffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.Workflow.ID,
		ProjectKey: e.ProjectKey,
		DataType:   "yaml",
		DataAfter:  buffer.String(),
	})
}

type updateWorkflowAudit struct{}

func (u updateWorkflowAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowUpdate
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	oldWorkflowBuffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.OldWorkflow, exportentities.FormatYAML, oldWorkflowBuffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	newWorkflowBuffer := bytes.NewBufferString("")
	if _, err := exportWorkflow(ctx, wEvent.NewWorkflow, exportentities.FormatYAML, newWorkflowBuffer); err != nil {
		return sdk.WrapError(err, "Unable to export workflow")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.NewWorkflow.ID,
		ProjectKey: e.ProjectKey,
		DataType:   "yaml",
		DataAfter:  newWorkflowBuffer.String(),
		DataBefore: oldWorkflowBuffer.String(),
	})
}

type addWorkflowPermissionAudit struct{}

func (a addWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionAdd
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	b, err := json.MarshalIndent(wEvent.Permission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.WorkflowID,
		ProjectKey: e.ProjectKey,
		DataType:   "json",
		DataAfter:  string(b),
	})
}

type updateWorkflowPermissionAudit struct{}

func (u updateWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionUpdate
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	oldPerm, err := json.MarshalIndent(wEvent.OldPermission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal old permission")
	}

	newPerm, err := json.MarshalIndent(wEvent.NewPermission, "", "  ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal new permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		WorkflowID: wEvent.WorkflowID,
		ProjectKey: e.ProjectKey,
		DataType:   "json",
		DataBefore: string(oldPerm),
		DataAfter:  string(newPerm),
	})
}

type deleteWorkflowPermissionAudit struct{}

func (a deleteWorkflowPermissionAudit) Compute(ctx context.Context, db gorp.SqlExecutor, e sdk.Event) error {
	var wEvent sdk.EventWorkflowPermissionDelete
	if err := mapstructure.Decode(e.Payload, &wEvent); err != nil {
		return sdk.WrapError(err, "Unable to decode payload")
	}

	b, err := json.MarshalIndent(wEvent.Permission, "", " ")
	if err != nil {
		return sdk.WrapError(err, "Unable to marshal permission")
	}

	return InsertAudit(db, &sdk.AuditWorkflow{
		AuditCommon: sdk.AuditCommon{
			EventType:   strings.Replace(e.EventType, "sdk.Event", "", -1),
			Created:     e.Timestamp,
			TriggeredBy: e.Username,
		},
		ProjectKey: e.ProjectKey,
		WorkflowID: wEvent.WorkflowID,
		DataType:   "json",
		DataBefore: string(b),
	})
}

const keepAudits = 50

func purgeAudits(ctx context.Context, db gorp.SqlExecutor) error {
	var nbAuditsPerWorkflowID = []struct {
		WorkflowID int64 `db:"workflow_id"`
		NbAudits   int64 `db:"nb_audits"`
	}{}

	query := `select workflow_id, count(id) "nb_audits" from workflow_audit group by workflow_id having count(id)  > $1`
	if _, err := db.Select(&nbAuditsPerWorkflowID, query, keepAudits); err != nil {
		return sdk.WithStack(err)
	}

	for _, r := range nbAuditsPerWorkflowID {
		log.Debug("purgeAudits> deleting audits for workflow %d (%d audits)", r.WorkflowID, r.NbAudits)
		var ids []int64
		query = `select id from workflow_audit where workflow_id = $1 order by created desc offset $2`
		if _, err := db.Select(&ids, query, r.WorkflowID, keepAudits); err != nil {
			return sdk.WithStack(err)
		}
		for _, id := range ids {
			if err := deleteAudit(db, id); err != nil {
				log.Error(ctx, "purgeAudits> unable to delete audit %d: %v", id, err)
			}
		}
	}

	return nil
}

func deleteAudit(db gorp.SqlExecutor, id int64) error {
	_, err := db.Exec(`delete from workflow_audit where id = $1`, id)
	return sdk.WithStack(err)
}
<|endoftext|>


<commit_before>//go:build linux
// +build linux

package linux

import (
	"os/exec"
	"regexp"
	"strings"

	"github.com/vishvananda/netlink"

	"github.com/mackerelio/golib/logging"
	"github.com/mackerelio/mackerel-agent/spec"
	mkr "github.com/mackerelio/mackerel-client-go"
)

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

var interfaceLogger = logging.GetLogger("spec.interface")

// Generate XXX
func (g *InterfaceGenerator) Generate() ([]mkr.Interface, error) {
	var interfaces spec.Interfaces
	_, err := exec.LookPath("ip")
	// has ip command
	if err == nil {
		interfaces, err = g.generateByIPCommand()
		if err != nil {
			return nil, err
		}
	} else {
		interfaces, err = g.generateByIfconfigCommand()
		if err != nil {
			return nil, err
		}
	}
	var results []mkr.Interface
	for _, iface := range interfaces {
		if spec.IsLoopback(iface) {
			continue
		}
		if len(iface.IPv4Addresses) == 0 && len(iface.IPv6Addresses) == 0 {
			continue
		}
		results = append(results, iface)
	}
	return results, nil
}

func (g *InterfaceGenerator) generateByNetLink() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)

	links, err := netlink.LinkList()
	if err != nil {
		return nil, err
	}

	for _, link := range links {
		attr := link.Attrs()
		name := attr.Name

		interfaces.SetMacAddress(name, attr.HardwareAddr.String())

		addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			interfaces.AppendIPv4Address(name, addr.IP.String())
		}

		addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			interfaces.AppendIPv6Address(name, addr.IP.String())
		}
	}
	return interfaces, nil
}

var (
	// ex.) 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
	ipCmdNameReg = regexp.MustCompile(`^(\d+): ([0-9a-zA-Z@:\.\-_]*?)(@[0-9a-zA-Z]+|):\s`)
	// ex.) link/ether 12:34:56:78:9a:bc brd ff:ff:ff:ff:ff:ff
	ipCmdEncapReg = regexp.MustCompile(`link\/(\w+) ([\da-f\:]+) `)
	// ex.) inet 10.0.4.7/24 brd 10.0.5.255 scope global eth0
	ipCmdIPv4Reg = regexp.MustCompile(`inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\/(\d{1,2}))?`)
	//inet6 fe80::44b3:b3ff:fe1c:d17c/64 scope link
	ipCmdIPv6Reg = regexp.MustCompile(`inet6 ([a-f0-9\:]+)\/(\d+) scope (\w+)`)
)

func (g *InterfaceGenerator) generateByIPCommand() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)
	name := ""
	{
		// ip addr
		out, err := exec.Command("ip", "addr").Output()
		if err != nil {
			interfaceLogger.Errorf("Failed to run ip command (skip this spec): %s", err)
			return nil, err
		}
		for _, line := range strings.Split(string(out), "\n") {
			if matches := ipCmdNameReg.FindStringSubmatch(line); matches != nil {
				name = matches[2]
			}
			if matches := ipCmdEncapReg.FindStringSubmatch(line); matches != nil {
				interfaces.SetMacAddress(name, matches[2])
			}
			if matches := ipCmdIPv4Reg.FindStringSubmatch(line); matches != nil {
				interfaces.AppendIPv4Address(name, matches[1])
			}
			if matches := ipCmdIPv6Reg.FindStringSubmatch(line); matches != nil {
				interfaces.AppendIPv6Address(name, matches[1])
			}
		}
	}
	return interfaces, nil
}

var (
	// ex.) eth0      Link encap:Ethernet  HWaddr 12:34:56:78:9a:bc
	ifconfigNameReg = regexp.MustCompile(`^([0-9a-zA-Z@\.\:\-_]+)\s+`)
	// ex.) eth0      Link encap:Ethernet  HWaddr 12:34:56:78:9a:bc
	ifconfigEncapReg = regexp.MustCompile(`Link encap:(Local Loopback)|Link encap:(.+?)\s`)
	// ex.) eth0      Link encap:Ethernet  HWaddr 00:16:3e:4f:f3:41
	ifconfigMacAddrReg = regexp.MustCompile(`HWaddr (.+?)\s`)
	// ex.) inet addr:10.0.4.7  Bcast:10.0.5.255  Mask:255.255.255.0
	ifconfigV4AddrReg = regexp.MustCompile(`inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`)
	// ex.) inet6 addr: fe80::44b3:b3ff:fe1c:d17c/64 Scope:Link
	ifconfigV6AddrReg = regexp.MustCompile(`inet6 addr: ([a-f0-9\:]+)\/(\d+) Scope:(\w+)`)
)

func (g *InterfaceGenerator) generateByIfconfigCommand() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)
	name := ""

	// ifconfig -a
	out, err := exec.Command("ifconfig", "-a").Output()
	if err != nil {
		interfaceLogger.Errorf("Failed to run ifconfig command (skip this spec): %s", err)
		return nil, err
	}
	for _, line := range strings.Split(string(out), "\n") {
		if matches := ifconfigNameReg.FindStringSubmatch(line); matches != nil {
			name = matches[1]
		}
		if matches := ifconfigMacAddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.SetMacAddress(name, matches[1])
		}
		if matches := ifconfigV4AddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.AppendIPv4Address(name, matches[1])
		}
		if matches := ifconfigV6AddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.AppendIPv6Address(name, matches[1])
		}
	}
	return interfaces, nil
}
<commit_msg>use generateByNetLink<commit_after>//go:build linux
// +build linux

package linux

import (
	"os/exec"
	"regexp"
	"strings"

	"github.com/vishvananda/netlink"

	"github.com/mackerelio/golib/logging"
	"github.com/mackerelio/mackerel-agent/spec"
	mkr "github.com/mackerelio/mackerel-client-go"
)

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

var interfaceLogger = logging.GetLogger("spec.interface")

// Generate XXX
func (g *InterfaceGenerator) Generate() ([]mkr.Interface, error) {
	var interfaces spec.Interfaces
	interfaces, err := g.generateByNetLink()
	if err == nil {
		interfaceLogger.Infof("generateByNetLink")
	} else {
		_, err := exec.LookPath("ip")
		// has ip command
		if err == nil {
			interfaceLogger.Infof("generateByIPCommand")
			interfaces, err = g.generateByIPCommand()
			if err != nil {
				return nil, err
			}
		} else {
			interfaceLogger.Infof("generateByIfconfigCommand")
			interfaces, err = g.generateByIfconfigCommand()
			if err != nil {
				return nil, err
			}
		}
	}
	var results []mkr.Interface
	for _, iface := range interfaces {
		if spec.IsLoopback(iface) {
			continue
		}
		if len(iface.IPv4Addresses) == 0 && len(iface.IPv6Addresses) == 0 {
			continue
		}
		results = append(results, iface)
	}
	return results, nil
}

func (g *InterfaceGenerator) generateByNetLink() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)

	links, err := netlink.LinkList()
	if err != nil {
		return nil, err
	}

	for _, link := range links {
		attr := link.Attrs()
		name := attr.Name

		interfaces.SetMacAddress(name, attr.HardwareAddr.String())

		addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			interfaces.AppendIPv4Address(name, addr.IP.String())
		}

		addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			interfaces.AppendIPv6Address(name, addr.IP.String())
		}
	}
	return interfaces, nil
}

var (
	// ex.) 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
	ipCmdNameReg = regexp.MustCompile(`^(\d+): ([0-9a-zA-Z@:\.\-_]*?)(@[0-9a-zA-Z]+|):\s`)
	// ex.) link/ether 12:34:56:78:9a:bc brd ff:ff:ff:ff:ff:ff
	ipCmdEncapReg = regexp.MustCompile(`link\/(\w+) ([\da-f\:]+) `)
	// ex.) inet 10.0.4.7/24 brd 10.0.5.255 scope global eth0
	ipCmdIPv4Reg = regexp.MustCompile(`inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(\/(\d{1,2}))?`)
	//inet6 fe80::44b3:b3ff:fe1c:d17c/64 scope link
	ipCmdIPv6Reg = regexp.MustCompile(`inet6 ([a-f0-9\:]+)\/(\d+) scope (\w+)`)
)

func (g *InterfaceGenerator) generateByIPCommand() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)
	name := ""
	{
		// ip addr
		out, err := exec.Command("ip", "addr").Output()
		if err != nil {
			interfaceLogger.Errorf("Failed to run ip command (skip this spec): %s", err)
			return nil, err
		}
		for _, line := range strings.Split(string(out), "\n") {
			if matches := ipCmdNameReg.FindStringSubmatch(line); matches != nil {
				name = matches[2]
			}
			if matches := ipCmdEncapReg.FindStringSubmatch(line); matches != nil {
				interfaces.SetMacAddress(name, matches[2])
			}
			if matches := ipCmdIPv4Reg.FindStringSubmatch(line); matches != nil {
				interfaces.AppendIPv4Address(name, matches[1])
			}
			if matches := ipCmdIPv6Reg.FindStringSubmatch(line); matches != nil {
				interfaces.AppendIPv6Address(name, matches[1])
			}
		}
	}
	return interfaces, nil
}

var (
	// ex.) eth0      Link encap:Ethernet  HWaddr 12:34:56:78:9a:bc
	ifconfigNameReg = regexp.MustCompile(`^([0-9a-zA-Z@\.\:\-_]+)\s+`)
	// ex.) eth0      Link encap:Ethernet  HWaddr 12:34:56:78:9a:bc
	ifconfigEncapReg = regexp.MustCompile(`Link encap:(Local Loopback)|Link encap:(.+?)\s`)
	// ex.) eth0      Link encap:Ethernet  HWaddr 00:16:3e:4f:f3:41
	ifconfigMacAddrReg = regexp.MustCompile(`HWaddr (.+?)\s`)
	// ex.) inet addr:10.0.4.7  Bcast:10.0.5.255  Mask:255.255.255.0
	ifconfigV4AddrReg = regexp.MustCompile(`inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`)
	// ex.) inet6 addr: fe80::44b3:b3ff:fe1c:d17c/64 Scope:Link
	ifconfigV6AddrReg = regexp.MustCompile(`inet6 addr: ([a-f0-9\:]+)\/(\d+) Scope:(\w+)`)
)

func (g *InterfaceGenerator) generateByIfconfigCommand() (spec.Interfaces, error) {
	interfaces := make(spec.Interfaces)
	name := ""

	// ifconfig -a
	out, err := exec.Command("ifconfig", "-a").Output()
	if err != nil {
		interfaceLogger.Errorf("Failed to run ifconfig command (skip this spec): %s", err)
		return nil, err
	}
	for _, line := range strings.Split(string(out), "\n") {
		if matches := ifconfigNameReg.FindStringSubmatch(line); matches != nil {
			name = matches[1]
		}
		if matches := ifconfigMacAddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.SetMacAddress(name, matches[1])
		}
		if matches := ifconfigV4AddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.AppendIPv4Address(name, matches[1])
		}
		if matches := ifconfigV6AddrReg.FindStringSubmatch(line); matches != nil {
			interfaces.AppendIPv6Address(name, matches[1])
		}
	}
	return interfaces, nil
}
<|endoftext|>