<commit_before>package arn

import (
	"errors"

	"github.com/aerogo/nano"
)

// Company ...
type Company struct {
	ID          string      `json:"id"`
	Name        CompanyName `json:"name" editable:"true"`
	Image       string      `json:"image"`
	Description string      `json:"description" editable:"true" type:"textarea"`
	Mappings    []*Mapping  `json:"mappings" editable:"true"`
	Links       []*Link     `json:"links" editable:"true"`
	Location    Location    `json:"location" editable:"true"`
	Tags        []string    `json:"tags" editable:"true"`
	Likes       []string    `json:"likes"`
	IsDraft     bool        `json:"isDraft"`
	Created     string      `json:"created"`
	CreatedBy   string      `json:"createdBy"`
	Edited      string      `json:"edited"`
	EditedBy    string      `json:"editedBy"`
}

// Link returns a single company.
func (company *Company) Link() string {
	return "/company/" + company.ID
}

// Creator returns the user who created this company.
func (company *Company) Creator() *User {
	user, _ := GetUser(company.CreatedBy)
	return user
}

// Anime returns the anime connected with this company.
func (company *Company) Anime() (studioAnime []*Anime, producedAnime []*Anime, licensedAnime []*Anime) {
	for anime := range StreamAnime() {
		if Contains(anime.StudioIDs, company.ID) {
			studioAnime = append(studioAnime, anime)
		}

		if Contains(anime.ProducerIDs, company.ID) {
			producedAnime = append(producedAnime, anime)
		}

		if Contains(anime.LicensorIDs, company.ID) {
			licensedAnime = append(licensedAnime, anime)
		}
	}

	SortAnimeByQuality(studioAnime, "")
	SortAnimeByQuality(producedAnime, "")
	SortAnimeByQuality(licensedAnime, "")

	return studioAnime, producedAnime, licensedAnime
}

// Publish ...
func (company *Company) Publish() error {
	// No draft
	if !company.IsDraft {
		return errors.New("Not a draft")
	}

	// No title
	if company.Name.English == "" {
		return errors.New("No English company name")
	}

	draftIndex, err := GetDraftIndex(company.CreatedBy)

	if err != nil {
		return err
	}

	if draftIndex.CompanyID == "" {
		return errors.New("Company draft doesn't exist in the user draft index")
	}

	company.IsDraft = false
	draftIndex.CompanyID = ""
	draftIndex.Save()
	return nil
}

// Unpublish ...
func (company *Company) Unpublish() error {
	draftIndex, err := GetDraftIndex(company.CreatedBy)

	if err != nil {
		return err
	}

	if draftIndex.CompanyID != "" {
		return errors.New("You still have an unfinished draft")
	}

	company.IsDraft = true
	draftIndex.CompanyID = company.ID
	draftIndex.Save()
	return nil
}

// Like adds an user to the company's Likes array if they aren't already in it.
func (company *Company) Like(userID string) {
	for _, id := range company.Likes {
		if id == userID {
			return
		}
	}

	company.Likes = append(company.Likes, userID)
}

// Unlike removes the user from the company's Likes array if they are in it.
func (company *Company) Unlike(userID string) {
	for index, id := range company.Likes {
		if id == userID {
			company.Likes = append(company.Likes[:index], company.Likes[index+1:]...)
			return
		}
	}
}

// LikedBy checks to see if the user has liked the company.
func (company *Company) LikedBy(userID string) bool {
	for _, id := range company.Likes {
		if id == userID {
			return true
		}
	}

	return false
}

// GetCompany returns a single company.
func GetCompany(id string) (*Company, error) {
	obj, err := DB.Get("Company", id)

	if err != nil {
		return nil, err
	}

	return obj.(*Company), nil
}

// StreamCompanies returns a stream of all companies.
func StreamCompanies() chan *Company {
	channel := make(chan *Company, nano.ChannelBufferSize)

	go func() {
		for obj := range DB.All("Company") {
			channel <- obj.(*Company)
		}

		close(channel)
	}()

	return channel
}

// FilterCompanies filters all companies by a custom function.
func FilterCompanies(filter func(*Company) bool) []*Company {
	var filtered []*Company

	channel := DB.All("Company")

	for obj := range channel {
		realObject := obj.(*Company)

		if filter(realObject) {
			filtered = append(filtered, realObject)
		}
	}

	return filtered
}

// AllCompanies returns a slice of all companies.
func AllCompanies() []*Company {
	var all []*Company

	stream := StreamCompanies()

	for obj := range stream {
		all = append(all, obj)
	}

	return all
}
<commit_msg>New implementation for likes<commit_after>package arn

import (
	"errors"

	"github.com/aerogo/nano"
)

// Company ...
type Company struct {
	ID          string      `json:"id"`
	Name        CompanyName `json:"name" editable:"true"`
	Image       string      `json:"image"`
	Description string      `json:"description" editable:"true" type:"textarea"`
	Mappings    []*Mapping  `json:"mappings" editable:"true"`
	Links       []*Link     `json:"links" editable:"true"`
	Location    Location    `json:"location" editable:"true"`
	Tags        []string    `json:"tags" editable:"true"`
	IsDraft     bool        `json:"isDraft"`
	Created     string      `json:"created"`
	CreatedBy   string      `json:"createdBy"`
	Edited      string      `json:"edited"`
	EditedBy    string      `json:"editedBy"`
	LikeableImplementation
}

// Link returns a single company.
func (company *Company) Link() string {
	return "/company/" + company.ID
}

// Creator returns the user who created this company.
func (company *Company) Creator() *User {
	user, _ := GetUser(company.CreatedBy)
	return user
}

// Anime returns the anime connected with this company.
func (company *Company) Anime() (studioAnime []*Anime, producedAnime []*Anime, licensedAnime []*Anime) {
	for anime := range StreamAnime() {
		if Contains(anime.StudioIDs, company.ID) {
			studioAnime = append(studioAnime, anime)
		}

		if Contains(anime.ProducerIDs, company.ID) {
			producedAnime = append(producedAnime, anime)
		}

		if Contains(anime.LicensorIDs, company.ID) {
			licensedAnime = append(licensedAnime, anime)
		}
	}

	SortAnimeByQuality(studioAnime, "")
	SortAnimeByQuality(producedAnime, "")
	SortAnimeByQuality(licensedAnime, "")

	return studioAnime, producedAnime, licensedAnime
}

// Publish ...
func (company *Company) Publish() error {
	// No draft
	if !company.IsDraft {
		return errors.New("Not a draft")
	}

	// No title
	if company.Name.English == "" {
		return errors.New("No English company name")
	}

	draftIndex, err := GetDraftIndex(company.CreatedBy)

	if err != nil {
		return err
	}

	if draftIndex.CompanyID == "" {
		return errors.New("Company draft doesn't exist in the user draft index")
	}

	company.IsDraft = false
	draftIndex.CompanyID = ""
	draftIndex.Save()
	return nil
}

// Unpublish ...
func (company *Company) Unpublish() error {
	draftIndex, err := GetDraftIndex(company.CreatedBy)

	if err != nil {
		return err
	}

	if draftIndex.CompanyID != "" {
		return errors.New("You still have an unfinished draft")
	}

	company.IsDraft = true
	draftIndex.CompanyID = company.ID
	draftIndex.Save()
	return nil
}

// GetCompany returns a single company.
func GetCompany(id string) (*Company, error) {
	obj, err := DB.Get("Company", id)

	if err != nil {
		return nil, err
	}

	return obj.(*Company), nil
}

// StreamCompanies returns a stream of all companies.
func StreamCompanies() chan *Company {
	channel := make(chan *Company, nano.ChannelBufferSize)

	go func() {
		for obj := range DB.All("Company") {
			channel <- obj.(*Company)
		}

		close(channel)
	}()

	return channel
}

// FilterCompanies filters all companies by a custom function.
func FilterCompanies(filter func(*Company) bool) []*Company {
	var filtered []*Company

	channel := DB.All("Company")

	for obj := range channel {
		realObject := obj.(*Company)

		if filter(realObject) {
			filtered = append(filtered, realObject)
		}
	}

	return filtered
}

// AllCompanies returns a slice of all companies.
func AllCompanies() []*Company {
	var all []*Company

	stream := StreamCompanies()

	for obj := range stream {
		all = append(all, obj)
	}

	return all
}
<|endoftext|>


<commit_before>package recording

import (
	"context"
	"errors"
	"log"
	"os"
	"os/exec"
	"time"
)

var (
	ErrMismatchWrite = errors.New("recording: did not write the same number of bytes that were read")
)

// Recording ...
type Recording struct {
	ctx      context.Context
	url      string
	fname    string
	cancel   context.CancelFunc
	started  time.Time
	restarts int

	Debug bool
	Err   error
}

// New creates a new Recording of the given URL to the given filename for output.
func New(url, fname string) (*Recording, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 4*time.Hour)

	r := &Recording{
		ctx:     ctx,
		url:     url,
		fname:   fname,
		cancel:  cancel,
		started: time.Now(),
	}

	return r, nil
}

// Cancel stops the recording.
func (r *Recording) Cancel() {
	r.cancel()
}

// Done returns the done channel of the recording.
func (r *Recording) Done() <-chan struct{} {
	return r.ctx.Done()
}

// OutputFilename gets the output filename originally passed into New.
func (r *Recording) OutputFilename() string {
	return r.fname
}

// StartTime gets start time
func (r *Recording) StartTime() time.Time {
	return r.started
}

// Start blockingly starts the recording and returns the error if one is encountered while streaming.
// This should be stopped in another goroutine.
func (r *Recording) Start() error {
	sr, err := exec.LookPath("streamripper")
	if err != nil {
		return err
	}

	cmd := exec.Command(sr, r.url, "-a", r.fname)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	log.Printf("%s: %v", cmd.Path, cmd.Args)

	err = cmd.Start()
	if err != nil {
		return err
	}

	go func() {
		defer r.Cancel()
		err := cmd.Wait()
		if err != nil {
			log.Println(err)
		}
	}()

	defer r.cancel()

	for {
		time.Sleep(250 * time.Millisecond)

		select {
		case <-r.ctx.Done():
			return cmd.Process.Signal(os.Interrupt)
		default:
		}
	}
}
<commit_msg>recording: have streamripper not save every song<commit_after>package recording

import (
	"context"
	"errors"
	"log"
	"os"
	"os/exec"
	"time"
)

var (
	ErrMismatchWrite = errors.New("recording: did not write the same number of bytes that were read")
)

// Recording ...
type Recording struct {
	ctx      context.Context
	url      string
	fname    string
	cancel   context.CancelFunc
	started  time.Time
	restarts int

	Debug bool
	Err   error
}

// New creates a new Recording of the given URL to the given filename for output.
func New(url, fname string) (*Recording, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 4*time.Hour)

	r := &Recording{
		ctx:     ctx,
		url:     url,
		fname:   fname,
		cancel:  cancel,
		started: time.Now(),
	}

	return r, nil
}

// Cancel stops the recording.
func (r *Recording) Cancel() {
	r.cancel()
}

// Done returns the done channel of the recording.
func (r *Recording) Done() <-chan struct{} {
	return r.ctx.Done()
}

// OutputFilename gets the output filename originally passed into New.
func (r *Recording) OutputFilename() string {
	return r.fname
}

// StartTime gets start time
func (r *Recording) StartTime() time.Time {
	return r.started
}

// Start blockingly starts the recording and returns the error if one is encountered while streaming.
// This should be stopped in another goroutine.
func (r *Recording) Start() error {
	sr, err := exec.LookPath("streamripper")
	if err != nil {
		return err
	}

	cmd := exec.Command(sr, r.url, "-A", "-a", r.fname)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	log.Printf("%s: %v", cmd.Path, cmd.Args)

	err = cmd.Start()
	if err != nil {
		return err
	}

	go func() {
		defer r.Cancel()
		err := cmd.Wait()
		if err != nil {
			log.Println(err)
		}
	}()

	defer r.cancel()

	for {
		time.Sleep(250 * time.Millisecond)

		select {
		case <-r.ctx.Done():
			return cmd.Process.Signal(os.Interrupt)
		default:
		}
	}
}
<|endoftext|>


<commit_before>package hamt32

import (
	"fmt"
	"strings"
)

// sparseTableInitCap constant sets the default capacity of a new
// sparseTable.
const sparseTableInitCap int = 8

// OLD sparsTable layout size == 48
//type sparseTable struct {
//	hashPath HashVal // 4; 8 cuz of alignment
//	depth    uint    // 8
//	nodeMap  Bitmap  // 4; 8 cuz of alignment
//	nodes    []nodeI // 24
//}

// NEW sparseTable layout size == 40
type sparseTable struct {
	nodes    []nodeI // 24
	depth    uint    // 8
	nodeMap  Bitmap  // 4
	hashPath HashVal // 4
}

func (t *sparseTable) copy() tableI {
	var nt = new(sparseTable)
	nt.hashPath = t.hashPath
	nt.depth = t.depth
	nt.nodeMap = t.nodeMap

	nt.nodes = make([]nodeI, len(t.nodes), cap(t.nodes))
	copy(nt.nodes, t.nodes)
	//nt.nodes = append(nt.nodes, t.nodes...)

	return nt
}

func (t *sparseTable) deepCopy() tableI {
	var nt = new(sparseTable)
	nt.hashPath = t.hashPath
	nt.depth = t.depth
	nt.nodeMap = t.nodeMap
	nt.nodes = make([]nodeI, len(t.nodes), cap(t.nodes))
	for i := 0; i < len(t.nodes); i++ {
		if table, isTable := t.nodes[i].(tableI); isTable {
			nt.nodes[i] = table.deepCopy()
		} else {
			//leafs are functional, so no need to copy
			//nils can be copied just fine; duh!
			nt.nodes[i] = t.nodes[i]
		}
	}
	return nt
}

func createRootSparseTable(lf leafI) tableI {
	var idx = lf.Hash().Index(0)

	var ct = new(sparseTable)
	//ct.hashPath = 0
	//ct.depth = 0
	//ct.nodeMap = uint32(1 << idx)
	ct.nodeMap.Set(idx)
	ct.nodes = make([]nodeI, 1, sparseTableInitCap)
	ct.nodes[0] = lf

	return ct
}

func createSparseTable(depth uint, leaf1 leafI, leaf2 *flatLeaf) tableI {
	_ = AssertOn && assert(depth > 0, "createSparseTable(): depth < 1")

	_ = AssertOn && assertf(
		leaf1.Hash().HashPath(depth) == leaf2.Hash().HashPath(depth),
		"createSparseTable(): hp1,%s != hp2,%s",
		leaf1.Hash().HashPath(depth),
		leaf2.Hash().HashPath(depth))

	var retTable = new(sparseTable)
	retTable.hashPath = leaf1.Hash().HashPath(depth)
	retTable.depth = depth
	//retTable.nodeMap = 0
	retTable.nodes = make([]nodeI, 0, sparseTableInitCap)

	var idx1 = leaf1.Hash().Index(depth)
	var idx2 = leaf2.Hash().Index(depth)
	if idx1 != idx2 {
		retTable.insert(idx1, leaf1)
		retTable.insert(idx2, leaf2)
	} else { //idx1 == idx2
		var node nodeI
		if depth == MaxDepth {
			node = newCollisionLeaf(append(leaf1.keyVals(), leaf2.keyVals()...))
		} else {
			node = createSparseTable(depth+1, leaf1, leaf2)
		}
		retTable.insert(idx1, node)
	}

	return retTable
}

// downgradeToSparseTable() converts fixedTable structs that have less than
// or equal to downgradeThreshold tableEntry's. One important thing we know is
// that none of the entries will collide with another.
//
// The ents []tableEntry slice is guaranteed to be in order from lowest idx to
// highest. tableI.entries() also adhears to this contract.
func downgradeToSparseTable(
	hashPath HashVal,
	depth uint,
	ents []tableEntry,
) *sparseTable {
	var nt = new(sparseTable)
	nt.hashPath = hashPath
	//nt.nodeMap = 0
	nt.nodes = make([]nodeI, len(ents), len(ents)+1)

	for i := 0; i < len(ents); i++ {
		var ent = ents[i]
		nt.nodeMap.Set(ent.idx)
		nt.nodes[i] = ent.node
	}

	return nt
}

// Hash returns an incomplete Hash of this table. Any levels past it's current
// depth should be zero.
func (t *sparseTable) Hash() HashVal {
	return t.hashPath
}

// String return a string representation of this table including the hashPath,
// depth, and number of entries.
func (t *sparseTable) String() string {
	return fmt.Sprintf("sparseTable{hashPath:%s, depth=%d, nentries()=%d}",
		t.hashPath, t.depth, t.nentries())
}

// LongString returns a string representation of this table and all the tables
// contained herein recursively.
func (t *sparseTable) LongString(indent string, depth uint) string {
	var strs = make([]string, 3+len(t.nodes))

	strs[0] = indent +
		fmt.Sprintf("sparseTable{hashPath=%s, depth=%d, nentries()=%d,",
			t.hashPath.HashPathString(depth), t.depth, t.nentries())

	strs[1] = indent + "\tnodeMap=" + t.nodeMap.String() + ","

	for i, n := range t.nodes {
		var idx = n.Hash().Index(depth)
		if t, isTable := n.(tableI); isTable {
			strs[2+i] = indent +
				fmt.Sprintf("\tt.nodes[%d]:\n%s",
					idx, t.LongString(indent+"\t", depth+1))
		} else {
			strs[2+i] = indent + fmt.Sprintf("\tt.nodes[%d]: %s", idx, n)
		}
	}

	strs[len(strs)-1] = indent + "}"

	return strings.Join(strs, "\n")
}

func (t *sparseTable) nentries() uint {
	return uint(len(t.nodes))
	//return t.nodeMap.Count(IndexLimit)
}

func (t *sparseTable) entries() []tableEntry {
	var n = t.nentries()
	var ents = make([]tableEntry, n)

	for idx, j := uint(0), uint(0); idx < IndexLimit; idx++ {
		if t.nodeMap.IsSet(idx) {
			ents[j] = tableEntry{idx, t.nodes[j]}
			j++
		}
	}

	return ents
}

func (t *sparseTable) get(idx uint) nodeI {
	if !t.nodeMap.IsSet(idx) {
		return nil
	}

	var j = t.nodeMap.Count(idx)

	return t.nodes[j]
}

func (t *sparseTable) insert(idx uint, n nodeI) {
	_ = AssertOn && assert(!t.nodeMap.IsSet(idx),
		"t.insert(idx, n) where idx slot is NOT empty; this should be a replace")

	var j = t.nodeMap.Count(idx)
	if j == uint(len(t.nodes)) {
		t.nodes = append(t.nodes, n)
	} else {
		t.nodes = append(t.nodes[:j], append([]nodeI{n}, t.nodes[j:]...)...)
	}

	t.nodeMap.Set(idx)
}

func (t *sparseTable) replace(idx uint, n nodeI) {
	_ = AssertOn && assert(t.nodeMap.IsSet(idx),
		"t.replace(idx, n) where idx slot is empty; this should be an insert")

	var j = t.nodeMap.Count(idx)
	t.nodes[j] = n
}

func (t *sparseTable) remove(idx uint) {
	_ = AssertOn && assert(t.nodeMap.IsSet(idx),
		"t.remove(idx) where idx slot is already empty")

	var j = t.nodeMap.Count(idx)
	if int(j) == len(t.nodes)-1 {
		t.nodes = t.nodes[:j]
	} else {
		t.nodes = append(t.nodes[:j], t.nodes[j+1:]...)
	}

	t.nodeMap.Unset(idx)
}
<commit_msg>changed sparseTableInitCap constant; does not seem to affect performance<commit_after>package hamt32

import (
	"fmt"
	"strings"
)

// sparseTableInitCap constant sets the default capacity of a new
// sparseTable.
const sparseTableInitCap int = 2

// OLD sparsTable layout size == 48
//type sparseTable struct {
//	hashPath HashVal // 4; 8 cuz of alignment
//	depth    uint    // 8
//	nodeMap  Bitmap  // 4; 8 cuz of alignment
//	nodes    []nodeI // 24
//}

// NEW sparseTable layout size == 40
type sparseTable struct {
	nodes    []nodeI // 24
	depth    uint    // 8
	nodeMap  Bitmap  // 4
	hashPath HashVal // 4
}

func (t *sparseTable) copy() tableI {
	var nt = new(sparseTable)
	nt.hashPath = t.hashPath
	nt.depth = t.depth
	nt.nodeMap = t.nodeMap

	nt.nodes = make([]nodeI, len(t.nodes), cap(t.nodes))
	copy(nt.nodes, t.nodes)
	//nt.nodes = append(nt.nodes, t.nodes...)

	return nt
}

func (t *sparseTable) deepCopy() tableI {
	var nt = new(sparseTable)
	nt.hashPath = t.hashPath
	nt.depth = t.depth
	nt.nodeMap = t.nodeMap
	nt.nodes = make([]nodeI, len(t.nodes), cap(t.nodes))
	for i := 0; i < len(t.nodes); i++ {
		if table, isTable := t.nodes[i].(tableI); isTable {
			nt.nodes[i] = table.deepCopy()
		} else {
			//leafs are functional, so no need to copy
			//nils can be copied just fine; duh!
			nt.nodes[i] = t.nodes[i]
		}
	}
	return nt
}

func createRootSparseTable(lf leafI) tableI {
	var idx = lf.Hash().Index(0)

	var ct = new(sparseTable)
	//ct.hashPath = 0
	//ct.depth = 0
	//ct.nodeMap = uint32(1 << idx)
	ct.nodeMap.Set(idx)
	ct.nodes = make([]nodeI, 1, sparseTableInitCap)
	ct.nodes[0] = lf

	return ct
}

func createSparseTable(depth uint, leaf1 leafI, leaf2 *flatLeaf) tableI {
	_ = AssertOn && assert(depth > 0, "createSparseTable(): depth < 1")

	_ = AssertOn && assertf(
		leaf1.Hash().HashPath(depth) == leaf2.Hash().HashPath(depth),
		"createSparseTable(): hp1,%s != hp2,%s",
		leaf1.Hash().HashPath(depth),
		leaf2.Hash().HashPath(depth))

	var retTable = new(sparseTable)
	retTable.hashPath = leaf1.Hash().HashPath(depth)
	retTable.depth = depth
	//retTable.nodeMap = 0
	retTable.nodes = make([]nodeI, 0, sparseTableInitCap)

	var idx1 = leaf1.Hash().Index(depth)
	var idx2 = leaf2.Hash().Index(depth)
	if idx1 != idx2 {
		retTable.insert(idx1, leaf1)
		retTable.insert(idx2, leaf2)
	} else { //idx1 == idx2
		var node nodeI
		if depth == MaxDepth {
			node = newCollisionLeaf(append(leaf1.keyVals(), leaf2.keyVals()...))
		} else {
			node = createSparseTable(depth+1, leaf1, leaf2)
		}
		retTable.insert(idx1, node)
	}

	return retTable
}

// downgradeToSparseTable() converts fixedTable structs that have less than
// or equal to downgradeThreshold tableEntry's. One important thing we know is
// that none of the entries will collide with another.
//
// The ents []tableEntry slice is guaranteed to be in order from lowest idx to
// highest. tableI.entries() also adhears to this contract.
func downgradeToSparseTable(
	hashPath HashVal,
	depth uint,
	ents []tableEntry,
) *sparseTable {
	var nt = new(sparseTable)
	nt.hashPath = hashPath
	//nt.nodeMap = 0
	nt.nodes = make([]nodeI, len(ents), len(ents)+1)

	for i := 0; i < len(ents); i++ {
		var ent = ents[i]
		nt.nodeMap.Set(ent.idx)
		nt.nodes[i] = ent.node
	}

	return nt
}

// Hash returns an incomplete Hash of this table. Any levels past it's current
// depth should be zero.
func (t *sparseTable) Hash() HashVal {
	return t.hashPath
}

// String return a string representation of this table including the hashPath,
// depth, and number of entries.
func (t *sparseTable) String() string {
	return fmt.Sprintf("sparseTable{hashPath:%s, depth=%d, nentries()=%d}",
		t.hashPath, t.depth, t.nentries())
}

// LongString returns a string representation of this table and all the tables
// contained herein recursively.
func (t *sparseTable) LongString(indent string, depth uint) string {
	var strs = make([]string, 3+len(t.nodes))

	strs[0] = indent +
		fmt.Sprintf("sparseTable{hashPath=%s, depth=%d, nentries()=%d,",
			t.hashPath.HashPathString(depth), t.depth, t.nentries())

	strs[1] = indent + "\tnodeMap=" + t.nodeMap.String() + ","

	for i, n := range t.nodes {
		var idx = n.Hash().Index(depth)
		if t, isTable := n.(tableI); isTable {
			strs[2+i] = indent +
				fmt.Sprintf("\tt.nodes[%d]:\n%s",
					idx, t.LongString(indent+"\t", depth+1))
		} else {
			strs[2+i] = indent + fmt.Sprintf("\tt.nodes[%d]: %s", idx, n)
		}
	}

	strs[len(strs)-1] = indent + "}"

	return strings.Join(strs, "\n")
}

func (t *sparseTable) nentries() uint {
	return uint(len(t.nodes))
	//return t.nodeMap.Count(IndexLimit)
}

func (t *sparseTable) entries() []tableEntry {
	var n = t.nentries()
	var ents = make([]tableEntry, n)

	for idx, j := uint(0), uint(0); idx < IndexLimit; idx++ {
		if t.nodeMap.IsSet(idx) {
			ents[j] = tableEntry{idx, t.nodes[j]}
			j++
		}
	}

	return ents
}

func (t *sparseTable) get(idx uint) nodeI {
	if !t.nodeMap.IsSet(idx) {
		return nil
	}

	var j = t.nodeMap.Count(idx)

	return t.nodes[j]
}

func (t *sparseTable) insert(idx uint, n nodeI) {
	_ = AssertOn && assert(!t.nodeMap.IsSet(idx),
		"t.insert(idx, n) where idx slot is NOT empty; this should be a replace")

	var j = t.nodeMap.Count(idx)
	if j == uint(len(t.nodes)) {
		t.nodes = append(t.nodes, n)
	} else {
		t.nodes = append(t.nodes[:j], append([]nodeI{n}, t.nodes[j:]...)...)
	}

	t.nodeMap.Set(idx)
}

func (t *sparseTable) replace(idx uint, n nodeI) {
	_ = AssertOn && assert(t.nodeMap.IsSet(idx),
		"t.replace(idx, n) where idx slot is empty; this should be an insert")

	var j = t.nodeMap.Count(idx)
	t.nodes[j] = n
}

func (t *sparseTable) remove(idx uint) {
	_ = AssertOn && assert(t.nodeMap.IsSet(idx),
		"t.remove(idx) where idx slot is already empty")

	var j = t.nodeMap.Count(idx)
	if int(j) == len(t.nodes)-1 {
		t.nodes = t.nodes[:j]
	} else {
		t.nodes = append(t.nodes[:j], t.nodes[j+1:]...)
	}

	t.nodeMap.Unset(idx)
}
<|endoftext|>


<commit_before>package raft

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
)

type appendEntryRequest struct {
	Term         int
	LeaderID     string
	PrevLogIndex int
	PrevLogTerm  int
	Entry        db.Entry
	LeaderCommit int
}

type appendRequest struct {
	Req        appendEntryRequest
	ReturnChan chan appendEntryResponse
}

type appendEntryResponse struct {
	Term    int
	Success bool
}

type followerResponse struct {
	ServerIndex int
	Resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	prevLogIndex := len(s.db.Log.Entries) - 1
	prevLogTerm := 0
	if prevLogIndex > 0 {
		prevLogTerm = s.db.Log.Entries[prevLogIndex].Term
	}
	a := &appendEntryRequest{s.term, s.id, prevLogIndex, prevLogTerm, entry, s.commitIndex}
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(a)
	resp, err := http.Post("http://"+follower+"/append", "application/json", b)
	if err != nil {
		fmt.Println("Couldn't send append entry request to " + follower)
		fmt.Println(err)
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	} else {
		r := &appendEntryResponse{}
		err := json.NewDecoder(resp.Body).Decode(r)
		if err != nil {
			fmt.Println("Couldn't decode append entries response from " + s.config[followerIndex])
			return
		}
		defer resp.Body.Close()
		if r.Term > s.term {
			fmt.Println("SETTING FOLLOWER: got append entry RPC with term greater than current term")
			s.term = r.Term
			s.state = "follower"
			s.electionTimeout.reset()
		}
		if r.Success {
			s.term = r.Term
			s.nextIndex[followerIndex]++
			s.matchIndex[followerIndex]++
			followerResp := &followerResponse{followerIndex, *r}
			respChan <- *followerResp
		} else {
			s.nextIndex[followerIndex]--
			go s.sendAppendEntryRequest(followerIndex, entry, respChan)
		}
	}
}

func (s *server) handleAppendEntryRequest(a appendRequest) {
	fmt.Println("Got append entry request: ", a.Req)
	returnChan := a.ReturnChan
	req := a.Req
	if req.Term > s.term {
		fmt.Println("SETTING FOLLOWER & RESETTING ELECTION TIMEOUT - append entries RPC has term greater than current term")
		s.term = req.Term
		s.state = "follower"
		s.electionTimeout.reset()
	}
	if req.Term < s.term {
		resp := &appendEntryResponse{s.term, false}
		returnChan <- *resp
	} else if req.PrevLogIndex > -1 &&
		len(s.db.Log.Entries) > req.PrevLogIndex &&
		s.db.Log.Entries[req.PrevLogIndex].Term != req.PrevLogTerm {
		resp := &appendEntryResponse{s.term, false}
		returnChan <- *resp
	} else {
		if len(s.db.Log.Entries) > req.PrevLogIndex+2 {
			if s.db.Log.Entries[req.PrevLogIndex+1].Term != req.Term {
				// If existing entry conflicts with new entry
				// Delete entry and all that follow it
				s.db.Log.SetEntries(s.db.Log.Entries[:req.PrevLogIndex])
			}
		}
		s.db.Log.AppendEntry(req.Entry)
		if req.LeaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.LeaderCommit < req.PrevLogIndex+1 {
				s.commitIndex = req.LeaderCommit
			} else {
				s.commitIndex = req.PrevLogIndex + 1
			}
		}
		resp := &appendEntryResponse{s.term, true}
		returnChan <- *resp
	}
}
<commit_msg>switch back to code that supports stable initial election for now<commit_after>package raft

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
)

type appendEntryRequest struct {
	Term         int
	LeaderID     string
	PrevLogIndex int
	PrevLogTerm  int
	Entry        db.Entry
	LeaderCommit int
}

type appendRequest struct {
	Req        appendEntryRequest
	ReturnChan chan appendEntryResponse
}

type appendEntryResponse struct {
	Term    int
	Success bool
}

type followerResponse struct {
	ServerIndex int
	Resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	prevLogIndex := len(s.db.Log.Entries) - 1
	prevLogTerm := 0
	if prevLogIndex > 0 {
		prevLogTerm = s.db.Log.Entries[prevLogIndex].Term
	}
	a := &appendEntryRequest{s.term, s.id, prevLogIndex, prevLogTerm, entry, s.commitIndex}
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(a)
	resp, err := http.Post("http://"+follower+"/append", "application/json", b)
	if err != nil {
		fmt.Println("Couldn't send append entry request to " + follower)
		fmt.Println(err)
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	} else {
		r := &appendEntryResponse{}
		err := json.NewDecoder(resp.Body).Decode(r)
		if err != nil {
			fmt.Println("Couldn't decode append entries response from " + s.config[followerIndex])
			return
		}
		defer resp.Body.Close()
		if r.Term > s.term {
			fmt.Println("SETTING FOLLOWER: got append entry RPC with term greater than current term")
			s.term = r.Term
			s.state = "follower"
			s.electionTimeout.reset()
		}
		if r.Success {
			s.term = r.Term
			s.nextIndex[followerIndex]++
			s.matchIndex[followerIndex]++
			followerResp := &followerResponse{followerIndex, *r}
			respChan <- *followerResp
		} else {
			s.nextIndex[followerIndex]--
			go s.sendAppendEntryRequest(followerIndex, entry, respChan)
		}
	}
}

func (s *server) handleAppendEntryRequest(a appendRequest) {
	fmt.Println("Got append entry request: ", a.Req)
	returnChan := a.ReturnChan
	req := a.Req
	/*
		if req.Term > s.term {
			fmt.Println("SETTING FOLLOWER & RESETTING ELECTION TIMEOUT - append entries RPC has term greater than current term")
			s.term = req.Term
			s.state = "follower"
			s.electionTimeout.reset()
		}
	*/
	if req.Term < s.term {
		resp := &appendEntryResponse{s.term, false}
		returnChan <- *resp
	} else if req.PrevLogIndex == -1 {
		fmt.Println("SETTING FOLLOWER & RESETTING ELECTION TIMEOUT - append entries RPC has term greater than current term")
		s.term = req.Term
		s.state = "follower"
		s.electionTimeout.reset()
		resp := &appendEntryResponse{s.term, true}
		returnChan <- *resp
	} else if req.PrevLogIndex > -1 &&
		len(s.db.Log.Entries) > req.PrevLogIndex &&
		s.db.Log.Entries[req.PrevLogIndex].Term != req.PrevLogTerm {
		resp := &appendEntryResponse{s.term, false}
		returnChan <- *resp
	} else {
		if len(s.db.Log.Entries) > req.PrevLogIndex+2 {
			if s.db.Log.Entries[req.PrevLogIndex+1].Term != req.Term {
				// If existing entry conflicts with new entry
				// Delete entry and all that follow it
				s.db.Log.SetEntries(s.db.Log.Entries[:req.PrevLogIndex])
			}
		}
		s.db.Log.AppendEntry(req.Entry)
		if req.LeaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.LeaderCommit < req.PrevLogIndex+1 {
				s.commitIndex = req.LeaderCommit
			} else {
				s.commitIndex = req.PrevLogIndex + 1
			}
		}
		resp := &appendEntryResponse{s.term, true}
		returnChan <- *resp
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"log"
	"time"

	example "github.com/rpcx-ecosystem/rpcx-examples3"
	"github.com/smallnest/rpcx/client"
)

var (
	addr = flag.String("addr", "localhost:8972", "server address")
)

func main() {
	flag.Parse()

	d := client.NewPeer2PeerDiscovery("tcp@"+*addr, "")
	xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption)
	defer xclient.Close()

	args := example.Args{
		A: 10,
		B: 20,
	}

	for {
		reply := &example.Reply{}
		err := xclient.Call(context.Background(), "Mul", args, reply)
		if err != nil {
			log.Fatalf("failed to call: %v", err)
		}

		log.Printf("%d * %d = %d", args.A, args.B, reply.C)

		time.Sleep(time.Second)
	}

}
<commit_msg>Update client.go<commit_after>package main

import (
	"context"
	"flag"
	"log"
	"time"

	example "github.com/rpcx-ecosystem/rpcx-examples3"
	"github.com/smallnest/rpcx/client"
)

var (
	addr = flag.String("addr", "localhost:8972", "server address")
)

func main() {
	flag.Parse()

	d := client.NewPeer2PeerDiscovery("tcp@"+*addr, "")
	xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption)
	defer xclient.Close()

	args := example.Args{
		A: 10,
		B: 20,
	}

	for {
		reply := &example.Reply{}
		err := xclient.Call(context.Background(), "Mul", args, reply)
		if err != nil {
			log.Printf("failed to call: %v", err)
		}

		log.Printf("%d * %d = %d", args.A, args.B, reply.C)

		time.Sleep(time.Second)
	}

}
<|endoftext|>


<commit_before>package main_test

import (
	"io"
	"strings"

	. "github.com/rightscale/right_st"

	"github.com/go-yaml/yaml"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("RightScript Metadata", func() {
	var (
		validScript                     io.ReadSeeker
		noMetadataScript                io.ReadSeeker
		missingEndDelimiterScript       io.ReadSeeker
		invalidYamlSyntaxScript         io.ReadSeeker
		invalidMetadataStructureScript  io.ReadSeeker
		incorrectInputTypeSyntaxScript  io.ReadSeeker
		incorrectInputValueSyntaxScript io.ReadSeeker
		emptyTextValueScript            io.ReadSeeker
		unknownFieldScript              io.ReadSeeker
		buffer                          *gbytes.Buffer
		emptyMetadata                   RightScriptMetadata
		emptyMetadataScript             string
		populatedMetadata               RightScriptMetadata
		populatedMetadataScript         string
		differentCommentMetadata        RightScriptMetadata
		differentCommentMetadataScript  string
	)

	BeforeEach(func() {
		validScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#       - text:foobar
#       - text:barfoo
#   SUPPORTED_VERSIONS:
#     Category: Uncategorized
#     Description: Some array input
#     Input Type: array
#     Required: false
#     Advanced: true
#     Default: array:["text:v1","text:v2"]
# Attachments:
#   - attachments/some_attachment.zip
#   - attachments/another_attachment.tar.xz
# ...
`)
		noMetadataScript = strings.NewReader(`#!/bin/bash
# There is no metadata comment here
`)
		missingEndDelimiterScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#       - text:foobar
#       - text:barfoo
#
# We should have used the '...' end delimiter above
`)
		invalidYamlSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: bogus
#     Required: true
#     Advanced: false
#     Default: text:
# ...
# The Default line is invalid YAML
`)
		invalidMetadataStructureScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   - TEXT_INPUT
# ...
# The Inputs field should have a map not an array
`)
		incorrectInputTypeSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: bogus
#     Required: true
#     Advanced: false
# ...
# The Input Type line is not a valid type
`)
		incorrectInputValueSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: foobar
# ...
# The Default line is not valid Inputs 2.0 syntax
`)
		emptyTextValueScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: "text:"
# ...
# The Default line should be blank or ignore in Inputs 2.0 syntax
`)
		unknownFieldScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Some Bogus Field: Some bogus value
# ...
`)
		buffer = gbytes.NewBuffer()
		emptyMetadata = RightScriptMetadata{}
		emptyMetadataScript = `# ---
# RightScript Name: ""
# Description: ""
# Inputs: {}
# Attachments: []
# ...
`
		populatedMetadata = RightScriptMetadata{
			Name:        "Some RightScript Name",
			Description: "Some description of stuff",
			Inputs: InputMap{
				InputMetadata{
					Name:           "TEXT_INPUT",
					Category:       "Uncategorized",
					Description:    "Some test input",
					InputType:      0,
					Required:       true,
					Advanced:       false,
					Default:        &InputValue{"text", "foobar"},
					PossibleValues: []*InputValue{&InputValue{"text", "foobar"}, &InputValue{"text", "barfoo"}},
				},
				InputMetadata{
					Name:        "SUPPORTED_VERSIONS",
					Category:    "Uncategorized",
					Description: "Some array input",
					InputType:   1,
					Required:    false,
					Advanced:    true,
					Default:     &InputValue{"array", `["text:v1","text:v2"]`},
				},
			},
			Attachments: []string{
				"attachments/some_attachment.zip",
				"attachments/another_attachment.tar.xz",
			},
		}
		populatedMetadataScript = `# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#     - text:foobar
#     - text:barfoo
#   SUPPORTED_VERSIONS:
#     Category: Uncategorized
#     Description: Some array input
#     Input Type: array
#     Required: false
#     Advanced: true
#     Default: array:["text:v1","text:v2"]
# Attachments:
# - attachments/some_attachment.zip
# - attachments/another_attachment.tar.xz
# ...
`
		differentCommentMetadata = RightScriptMetadata{Comment: "//"}
		differentCommentMetadataScript = `// ---
// RightScript Name: ""
// Description: ""
// Inputs: {}
// Attachments: []
// ...
`
	})

	Describe("Parse RightScript metadata", func() {
		Context("With valid script metadata", func() {
			It("should parse correctly", func() {
				metadata, err := ParseRightScriptMetadata(validScript)
				Expect(err).To(Succeed())
				Expect(metadata).NotTo(BeNil())
				Expect(metadata.Name).To(Equal("Some RightScript Name"))
				Expect(metadata.Description).To(Equal("Some description of stuff"))
				Expect(metadata.Inputs).To(Equal(InputMap{
					InputMetadata{
						Name:           "TEXT_INPUT",
						Category:       "Uncategorized",
						Description:    "Some test input",
						InputType:      0,
						Required:       true,
						Advanced:       false,
						Default:        &InputValue{"text", "foobar"},
						PossibleValues: []*InputValue{&InputValue{"text", "foobar"}, &InputValue{"text", "barfoo"}},
					},
					InputMetadata{
						Name:        "SUPPORTED_VERSIONS",
						Category:    "Uncategorized",
						Description: "Some array input",
						InputType:   1,
						Required:    false,
						Advanced:    true,
						Default:     &InputValue{"array", `["text:v1","text:v2"]`},
					},
				}))
				Expect(metadata.Attachments).To(Equal([]string{
					"attachments/some_attachment.zip",
					"attachments/another_attachment.tar.xz",
				}))
			})
		})

		Context("With no script metadata", func() {
			It("should not return metadata", func() {
				metadata, err := ParseRightScriptMetadata(noMetadataScript)
				Expect(err).To(Succeed())
				Expect(metadata).To(BeNil())
			})
		})

		Context("With missing end delimiter in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(missingEndDelimiterScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Unterminated RightScript metadata comment"))
			})
		})

		Context("With invalid YAML syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(invalidYamlSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("yaml: line 12: mapping values are not allowed in this context"))
			})
		})

		Context("With invalid structure in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(invalidMetadataStructureScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(&yaml.TypeError{
					Errors: []string{
						"line 7: cannot unmarshal !!seq into map[string]main.InputMetadata",
					},
				}))
			})
		})

		Context("With incorrect input type syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(incorrectInputTypeSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Invalid input type value: bogus"))
			})
		})

		Context("With incorrect input value syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(incorrectInputValueSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Invalid input value: foobar"))
			})
		})

		Context("With a blank text input value in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(emptyTextValueScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Use 'blank' or 'ignore' instead of 'text:'"))
			})
		})

		Context("With an unknown field in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(unknownFieldScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(&yaml.TypeError{
					Errors: []string{
						"line 4: no such field 'Some Bogus Field' in struct 'main.RightScriptMetadata'",
					},
				}))
			})
		})
	})

	Describe("Write RightScript metadata", func() {
		Context("With empty metadata", func() {
			It("should write a metadata comment", func() {
				n, err := emptyMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(emptyMetadataScript))
				Expect(n).To(BeEquivalentTo(84))
			})
		})
		Context("With populated metadata", func() {
			It("should write a metadata comment", func() {
				n, err := populatedMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(populatedMetadataScript))
				Expect(n).To(BeEquivalentTo(637))
			})
		})
		Context("With a different comment string for metadata", func() {
			It("should write a metadata comment", func() {
				n, err := differentCommentMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(differentCommentMetadataScript))
				Expect(n).To(BeEquivalentTo(90))
			})
		})
	})
})
<commit_msg>Fix specs. Omit empty descriptions now.<commit_after>package main_test

import (
	"io"
	"strings"

	. "github.com/rightscale/right_st"

	"github.com/go-yaml/yaml"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("RightScript Metadata", func() {
	var (
		validScript                     io.ReadSeeker
		noMetadataScript                io.ReadSeeker
		missingEndDelimiterScript       io.ReadSeeker
		invalidYamlSyntaxScript         io.ReadSeeker
		invalidMetadataStructureScript  io.ReadSeeker
		incorrectInputTypeSyntaxScript  io.ReadSeeker
		incorrectInputValueSyntaxScript io.ReadSeeker
		emptyTextValueScript            io.ReadSeeker
		unknownFieldScript              io.ReadSeeker
		buffer                          *gbytes.Buffer
		emptyMetadata                   RightScriptMetadata
		emptyMetadataScript             string
		populatedMetadata               RightScriptMetadata
		populatedMetadataScript         string
		differentCommentMetadata        RightScriptMetadata
		differentCommentMetadataScript  string
	)

	BeforeEach(func() {
		validScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#       - text:foobar
#       - text:barfoo
#   SUPPORTED_VERSIONS:
#     Category: Uncategorized
#     Description: Some array input
#     Input Type: array
#     Required: false
#     Advanced: true
#     Default: array:["text:v1","text:v2"]
# Attachments:
#   - attachments/some_attachment.zip
#   - attachments/another_attachment.tar.xz
# ...
`)
		noMetadataScript = strings.NewReader(`#!/bin/bash
# There is no metadata comment here
`)
		missingEndDelimiterScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#       - text:foobar
#       - text:barfoo
#
# We should have used the '...' end delimiter above
`)
		invalidYamlSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: bogus
#     Required: true
#     Advanced: false
#     Default: text:
# ...
# The Default line is invalid YAML
`)
		invalidMetadataStructureScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   - TEXT_INPUT
# ...
# The Inputs field should have a map not an array
`)
		incorrectInputTypeSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: bogus
#     Required: true
#     Advanced: false
# ...
# The Input Type line is not a valid type
`)
		incorrectInputValueSyntaxScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: foobar
# ...
# The Default line is not valid Inputs 2.0 syntax
`)
		emptyTextValueScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: "text:"
# ...
# The Default line should be blank or ignore in Inputs 2.0 syntax
`)
		unknownFieldScript = strings.NewReader(`#!/bin/bash
# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Some Bogus Field: Some bogus value
# ...
`)
		buffer = gbytes.NewBuffer()
		emptyMetadata = RightScriptMetadata{}
		emptyMetadataScript = `# ---
# RightScript Name: ""
# Inputs: {}
# Attachments: []
# ...
`
		populatedMetadata = RightScriptMetadata{
			Name:        "Some RightScript Name",
			Description: "Some description of stuff",
			Inputs: InputMap{
				InputMetadata{
					Name:           "TEXT_INPUT",
					Category:       "Uncategorized",
					Description:    "Some test input",
					InputType:      0,
					Required:       true,
					Advanced:       false,
					Default:        &InputValue{"text", "foobar"},
					PossibleValues: []*InputValue{&InputValue{"text", "foobar"}, &InputValue{"text", "barfoo"}},
				},
				InputMetadata{
					Name:        "SUPPORTED_VERSIONS",
					Category:    "Uncategorized",
					Description: "Some array input",
					InputType:   1,
					Required:    false,
					Advanced:    true,
					Default:     &InputValue{"array", `["text:v1","text:v2"]`},
				},
			},
			Attachments: []string{
				"attachments/some_attachment.zip",
				"attachments/another_attachment.tar.xz",
			},
		}
		populatedMetadataScript = `# ---
# RightScript Name: Some RightScript Name
# Description: Some description of stuff
# Inputs:
#   TEXT_INPUT:
#     Category: Uncategorized
#     Description: Some test input
#     Input Type: single
#     Required: true
#     Advanced: false
#     Default: text:foobar
#     Possible Values:
#     - text:foobar
#     - text:barfoo
#   SUPPORTED_VERSIONS:
#     Category: Uncategorized
#     Description: Some array input
#     Input Type: array
#     Required: false
#     Advanced: true
#     Default: array:["text:v1","text:v2"]
# Attachments:
# - attachments/some_attachment.zip
# - attachments/another_attachment.tar.xz
# ...
`
		differentCommentMetadata = RightScriptMetadata{Comment: "//"}
		differentCommentMetadataScript = `// ---
// RightScript Name: ""
// Inputs: {}
// Attachments: []
// ...
`
	})

	Describe("Parse RightScript metadata", func() {
		Context("With valid script metadata", func() {
			It("should parse correctly", func() {
				metadata, err := ParseRightScriptMetadata(validScript)
				Expect(err).To(Succeed())
				Expect(metadata).NotTo(BeNil())
				Expect(metadata.Name).To(Equal("Some RightScript Name"))
				Expect(metadata.Description).To(Equal("Some description of stuff"))
				Expect(metadata.Inputs).To(Equal(InputMap{
					InputMetadata{
						Name:           "TEXT_INPUT",
						Category:       "Uncategorized",
						Description:    "Some test input",
						InputType:      0,
						Required:       true,
						Advanced:       false,
						Default:        &InputValue{"text", "foobar"},
						PossibleValues: []*InputValue{&InputValue{"text", "foobar"}, &InputValue{"text", "barfoo"}},
					},
					InputMetadata{
						Name:        "SUPPORTED_VERSIONS",
						Category:    "Uncategorized",
						Description: "Some array input",
						InputType:   1,
						Required:    false,
						Advanced:    true,
						Default:     &InputValue{"array", `["text:v1","text:v2"]`},
					},
				}))
				Expect(metadata.Attachments).To(Equal([]string{
					"attachments/some_attachment.zip",
					"attachments/another_attachment.tar.xz",
				}))
			})
		})

		Context("With no script metadata", func() {
			It("should not return metadata", func() {
				metadata, err := ParseRightScriptMetadata(noMetadataScript)
				Expect(err).To(Succeed())
				Expect(metadata).To(BeNil())
			})
		})

		Context("With missing end delimiter in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(missingEndDelimiterScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Unterminated RightScript metadata comment"))
			})
		})

		Context("With invalid YAML syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(invalidYamlSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("yaml: line 12: mapping values are not allowed in this context"))
			})
		})

		Context("With invalid structure in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(invalidMetadataStructureScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(&yaml.TypeError{
					Errors: []string{
						"line 7: cannot unmarshal !!seq into map[string]main.InputMetadata",
					},
				}))
			})
		})

		Context("With incorrect input type syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(incorrectInputTypeSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Invalid input type value: bogus"))
			})
		})

		Context("With incorrect input value syntax in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(incorrectInputValueSyntaxScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Invalid input value: foobar"))
			})
		})

		Context("With a blank text input value in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(emptyTextValueScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError("Use 'blank' or 'ignore' instead of 'text:'"))
			})
		})

		Context("With an unknown field in script metadata", func() {
			It("should return an error", func() {
				_, err := ParseRightScriptMetadata(unknownFieldScript)
				Expect(err).To(HaveOccurred())
				Expect(err).To(MatchError(&yaml.TypeError{
					Errors: []string{
						"line 4: no such field 'Some Bogus Field' in struct 'main.RightScriptMetadata'",
					},
				}))
			})
		})
	})

	Describe("Write RightScript metadata", func() {
		Context("With empty metadata", func() {
			It("should write a metadata comment", func() {
				n, err := emptyMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(emptyMetadataScript))
				Expect(n).To(BeEquivalentTo(66))
			})
		})
		Context("With populated metadata", func() {
			It("should write a metadata comment", func() {
				n, err := populatedMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(populatedMetadataScript))
				Expect(n).To(BeEquivalentTo(637))
			})
		})
		Context("With a different comment string for metadata", func() {
			It("should write a metadata comment", func() {
				n, err := differentCommentMetadata.WriteTo(buffer)
				Expect(err).To(Succeed())
				Expect(buffer.Contents()).To(BeEquivalentTo(differentCommentMetadataScript))
				Expect(n).To(BeEquivalentTo(71))
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipv4

import (
	"net"
	"syscall"
)

// A packetHandler represents the IPv4 datagram handler.
type packetHandler struct {
	c *net.IPConn
	rawOpt
}

func (c *packetHandler) ok() bool { return c != nil && c.c != nil }

// ReadFrom reads an IPv4 datagram from the endpoint c, copying the
// datagram into b.  It returns the received datagram as the IPv4
// header h, the payload p and the control message cm.
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
	if !c.ok() {
		return nil, nil, nil, syscall.EINVAL
	}
	oob := newControlMessage(&c.rawOpt)
	n, oobn, _, src, err := c.c.ReadMsgIP(b, oob)
	if err != nil {
		return nil, nil, nil, err
	}
	var hs []byte
	if hs, p, err = slicePacket(b[:n]); err != nil {
		return nil, nil, nil, err
	}
	if h, err = ParseHeader(hs); err != nil {
		return nil, nil, nil, err
	}
	if cm, err = parseControlMessage(oob[:oobn]); err != nil {
		return nil, nil, nil, err
	}
	if src != nil && cm != nil {
		cm.Src = src.IP
	}
	return
}

func slicePacket(b []byte) (h, p []byte, err error) {
	if len(b) < HeaderLen {
		return nil, nil, errHeaderTooShort
	}
	hdrlen := int(b[0]&0x0f) << 2
	return b[:hdrlen], b[hdrlen:], nil
}

// WriteTo writes an IPv4 datagram through the endpoint c, copying the
// datagram from the IPv4 header h and the payload p.  The control
// message cm allows the datagram path and the outgoing interface to be
// specified.  Currently only Linux supports this.  The cm may be nil
// if control of the outgoing datagram is not required.
//
// The IPv4 header h must contain appropriate fields that include:
//
//	Version       = ipv4.Version
//	Len           = <must be specified>
//	TOS           = <must be specified>
//	TotalLen      = <must be specified>
//	ID            = platform sets an appropriate value if ID is zero
//	FragOff       = <must be specified>
//	TTL           = <must be specified>
//	Protocol      = <must be specified>
//	Checksum      = platform sets an appropriate value if Checksum is zero
//	Src           = platform sets an appropriate value if Src is nil
//	Dst           = <must be specified>
//	h.Options     = optional
func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	oob := marshalControlMessage(cm)
	wh, err := h.Marshal()
	if err != nil {
		return err
	}
	dst := &net.IPAddr{}
	if cm != nil {
		if ip := cm.Dst.To4(); ip != nil {
			dst.IP = ip
		}
	}
	if dst.IP == nil {
		dst.IP = h.Dst
	}
	wh = append(wh, p...)
	_, _, err = c.c.WriteMsgIP(wh, oob, dst)
	return err
}
<commit_msg>go.net/ipv4: fix typo<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipv4

import (
	"net"
	"syscall"
)

// A packetHandler represents the IPv4 datagram handler.
type packetHandler struct {
	c *net.IPConn
	rawOpt
}

func (c *packetHandler) ok() bool { return c != nil && c.c != nil }

// ReadFrom reads an IPv4 datagram from the endpoint c, copying the
// datagram into b.  It returns the received datagram as the IPv4
// header h, the payload p and the control message cm.
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
	if !c.ok() {
		return nil, nil, nil, syscall.EINVAL
	}
	oob := newControlMessage(&c.rawOpt)
	n, oobn, _, src, err := c.c.ReadMsgIP(b, oob)
	if err != nil {
		return nil, nil, nil, err
	}
	var hs []byte
	if hs, p, err = slicePacket(b[:n]); err != nil {
		return nil, nil, nil, err
	}
	if h, err = ParseHeader(hs); err != nil {
		return nil, nil, nil, err
	}
	if cm, err = parseControlMessage(oob[:oobn]); err != nil {
		return nil, nil, nil, err
	}
	if src != nil && cm != nil {
		cm.Src = src.IP
	}
	return
}

func slicePacket(b []byte) (h, p []byte, err error) {
	if len(b) < HeaderLen {
		return nil, nil, errHeaderTooShort
	}
	hdrlen := int(b[0]&0x0f) << 2
	return b[:hdrlen], b[hdrlen:], nil
}

// WriteTo writes an IPv4 datagram through the endpoint c, copying the
// datagram from the IPv4 header h and the payload p.  The control
// message cm allows the datagram path and the outgoing interface to be
// specified.  Currently only Linux supports this.  The cm may be nil
// if control of the outgoing datagram is not required.
//
// The IPv4 header h must contain appropriate fields that include:
//
//	Version       = ipv4.Version
//	Len           = <must be specified>
//	TOS           = <must be specified>
//	TotalLen      = <must be specified>
//	ID            = platform sets an appropriate value if ID is zero
//	FragOff       = <must be specified>
//	TTL           = <must be specified>
//	Protocol      = <must be specified>
//	Checksum      = platform sets an appropriate value if Checksum is zero
//	Src           = platform sets an appropriate value if Src is nil
//	Dst           = <must be specified>
//	Options       = optional
func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	oob := marshalControlMessage(cm)
	wh, err := h.Marshal()
	if err != nil {
		return err
	}
	dst := &net.IPAddr{}
	if cm != nil {
		if ip := cm.Dst.To4(); ip != nil {
			dst.IP = ip
		}
	}
	if dst.IP == nil {
		dst.IP = h.Dst
	}
	wh = append(wh, p...)
	_, _, err = c.c.WriteMsgIP(wh, oob, dst)
	return err
}
<|endoftext|>


<commit_before>package create

import (
	"bytes"
	"text/template"

	"github.com/giantswarm/microerror"
)

const (
	userDataScriptTemplate = `#!/bin/bash

# user-data in EC2 instances has a 16KB limit.
# To circumvent this limit, we:
#
# 1. Upload the final cloudconfig to s3
# 2. Generate a "small cloudconfig" whose only task is fetching the
#    final cloudconfig from s3
# 3. Configure the instance to be able to access the s3 URI where the
#    final cloudconfig is stored
# 4. Start the instance with the "small cloudconfig"
#
# This file is the "small cloudconfig" mentioned before. Here we simply fetch a
# gzip+base64 file (the final cloudconfig) from AWS S3 and run coreos-cloudinit
# with it as an argument.

. /etc/environment
USERDATA_FILE={{.MachineType}}

/usr/bin/rkt run \
    --net=host \
    --volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf  \
    --volume=awsenv,kind=host,source=/var/run/coreos,readOnly=false --mount volume=awsenv,target=/var/run/coreos \
    --trust-keys-from-https \
    quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 -- aws s3 --region {{.Region}} cp s3://{{.S3URI}}/cloudconfig/$USERDATA_FILE /var/run/coreos/temp.txt
base64 -d /var/run/coreos/temp.txt | gunzip > /var/run/coreos/$USERDATA_FILE
exec /usr/bin/coreos-cloudinit --from-file /var/run/coreos/$USERDATA_FILE`

	encryptionConfigTemplate = `
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: {{.EncryptionKey}}
    - identity: {}
`
)

func (s *Service) EncryptionConfig(encryptionKey string) (string, error) {
	tmpl, err := template.New("encryptionConfig").Parse(encryptionConfigTemplate)
	if err != nil {
		return "", microerror.Mask(err)
	}

	buf := new(bytes.Buffer)
	err = tmpl.Execute(buf, struct {
		EncryptionKey string
	}{
		EncryptionKey: encryptionKey,
	})
	if err != nil {
		return "", microerror.Mask(err)
	}

	return string(buf.Bytes()), nil
}
<commit_msg>Wait for S3 domain in small cloudconfig (#460)<commit_after>package create

import (
	"bytes"
	"text/template"

	"github.com/giantswarm/microerror"
)

const (
	userDataScriptTemplate = `#!/bin/bash

# user-data in EC2 instances has a 16KB limit.
# To circumvent this limit, we:
#
# 1. Upload the final cloudconfig to s3
# 2. Generate a "small cloudconfig" whose only task is fetching the
#    final cloudconfig from s3
# 3. Configure the instance to be able to access the s3 URI where the
#    final cloudconfig is stored
# 4. Start the instance with the "small cloudconfig"
#
# This file is the "small cloudconfig" mentioned before. Here we simply fetch a
# gzip+base64 file (the final cloudconfig) from AWS S3 and run coreos-cloudinit
# with it as an argument.

. /etc/environment
USERDATA_FILE={{.MachineType}}

# Wait for S3 bucket to be available.
s3_http_uri="https://s3.{{.Region}}.amazonaws.com/{{.S3URI}}/cloudconfig/$USERDATA_FILE"
retry=30

until [ $(curl --output /dev/null --silent --head --fail -w "%{http_code}" $s3_http_uri) -eq "403" ]; do
   retry=$(( retry - 1))
   if [ $retry -le 0 ]; then
     echo "timed out waiting for s3 bucket"
     exit 1
   fi

   echo "waiting for $s3_http_uri to be available"
   sleep 5
done

/usr/bin/rkt run \
    --net=host \
    --volume=dns,kind=host,source=/etc/resolv.conf,readOnly=true --mount volume=dns,target=/etc/resolv.conf  \
    --volume=awsenv,kind=host,source=/var/run/coreos,readOnly=false --mount volume=awsenv,target=/var/run/coreos \
    --trust-keys-from-https \
    quay.io/coreos/awscli:025a357f05242fdad6a81e8a6b520098aa65a600 -- aws s3 --region {{.Region}} cp s3://{{.S3URI}}/cloudconfig/$USERDATA_FILE /var/run/coreos/temp.txt
base64 -d /var/run/coreos/temp.txt | gunzip > /var/run/coreos/$USERDATA_FILE
exec /usr/bin/coreos-cloudinit --from-file /var/run/coreos/$USERDATA_FILE`

	encryptionConfigTemplate = `
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: {{.EncryptionKey}}
    - identity: {}
`
)

func (s *Service) EncryptionConfig(encryptionKey string) (string, error) {
	tmpl, err := template.New("encryptionConfig").Parse(encryptionConfigTemplate)
	if err != nil {
		return "", microerror.Mask(err)
	}

	buf := new(bytes.Buffer)
	err = tmpl.Execute(buf, struct {
		EncryptionKey string
	}{
		EncryptionKey: encryptionKey,
	})
	if err != nil {
		return "", microerror.Mask(err)
	}

	return string(buf.Bytes()), nil
}
<|endoftext|>


<commit_before>package helpers

import (
	"context"
	"os"

	"io"

	vision "cloud.google.com/go/vision/apiv1"
	vision2 "google.golang.org/genproto/googleapis/cloud/vision/v1"
)

var visionClient *vision.ImageAnnotatorClient

func PictureIsSafe(reader io.Reader) (safe bool) {
	var err error
	ctx := context.Background()

	if visionClient == nil {
		os.Setenv(
			"GOOGLE_APPLICATION_CREDENTIALS",
			GetConfig().Path("google.client_credentials_json_location").Data().(string),
		)

		visionClient, err = vision.NewImageAnnotatorClient(ctx)
		if err != nil {
			RelaxLog(err)
			return false
		}
	}

	image, err := vision.NewImageFromReader(reader)
	if err != nil {
		RelaxLog(err)
		return false
	}

	safeData, err := visionClient.DetectSafeSearch(ctx, image, nil)
	if err != nil {
		RelaxLog(err)
		return false
	}

	if safeData.GetAdult() == vision2.Likelihood_LIKELY || safeData.GetAdult() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetMedical() == vision2.Likelihood_LIKELY || safeData.GetMedical() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetViolence() == vision2.Likelihood_LIKELY || safeData.GetViolence() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetRacy() == vision2.Likelihood_LIKELY || safeData.GetRacy() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	return true
}
<commit_msg>[cloudvision] decreases filter strength for less false alarms<commit_after>package helpers

import (
	"context"
	"os"

	"io"

	vision "cloud.google.com/go/vision/apiv1"
	vision2 "google.golang.org/genproto/googleapis/cloud/vision/v1"
)

var visionClient *vision.ImageAnnotatorClient

func PictureIsSafe(reader io.Reader) (safe bool) {
	var err error
	ctx := context.Background()

	if visionClient == nil {
		os.Setenv(
			"GOOGLE_APPLICATION_CREDENTIALS",
			GetConfig().Path("google.client_credentials_json_location").Data().(string),
		)

		visionClient, err = vision.NewImageAnnotatorClient(ctx)
		if err != nil {
			RelaxLog(err)
			return false
		}
	}

	image, err := vision.NewImageFromReader(reader)
	if err != nil {
		RelaxLog(err)
		return false
	}

	safeData, err := visionClient.DetectSafeSearch(ctx, image, nil)
	if err != nil {
		RelaxLog(err)
		return false
	}

	if safeData.GetAdult() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetMedical() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetViolence() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	if safeData.GetRacy() == vision2.Likelihood_VERY_LIKELY {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"fmt"
	"path"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/timeutil"

	"xorm.io/builder"
)

// ActionType represents the type of an action.
type ActionType int

// Possible action types.
const (
	ActionCreateRepo                ActionType = iota + 1 // 1
	ActionRenameRepo                                      // 2
	ActionStarRepo                                        // 3
	ActionWatchRepo                                       // 4
	ActionCommitRepo                                      // 5
	ActionCreateIssue                                     // 6
	ActionCreatePullRequest                               // 7
	ActionTransferRepo                                    // 8
	ActionPushTag                                         // 9
	ActionCommentIssue                                    // 10
	ActionMergePullRequest                                // 11
	ActionCloseIssue                                      // 12
	ActionReopenIssue                                     // 13
	ActionClosePullRequest                                // 14
	ActionReopenPullRequest                               // 15
	ActionDeleteTag                                       // 16
	ActionDeleteBranch                                    // 17
	ActionMirrorSyncPush                                  // 18
	ActionMirrorSyncCreate                                // 19
	ActionMirrorSyncDelete                                // 20
	ActionApprovePullRequest                              // 21
	ActionRejectPullRequest                               // 22
	ActionCommentPull                                     // 23
	ActionPublishRelease                                  // 24
	ActionPullReviewDismissed                             // 25
	ActionPullRequestReadyForReview                       // 26
)

// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
type Action struct {
	ID          int64 `xorm:"pk autoincr"`
	UserID      int64 `xorm:"INDEX"` // Receiver user id.
	OpType      ActionType
	ActUserID   int64       `xorm:"INDEX"` // Action user id.
	ActUser     *User       `xorm:"-"`
	RepoID      int64       `xorm:"INDEX"`
	Repo        *Repository `xorm:"-"`
	CommentID   int64       `xorm:"INDEX"`
	Comment     *Comment    `xorm:"-"`
	IsDeleted   bool        `xorm:"INDEX NOT NULL DEFAULT false"`
	RefName     string
	IsPrivate   bool               `xorm:"INDEX NOT NULL DEFAULT false"`
	Content     string             `xorm:"TEXT"`
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}

func init() {
	db.RegisterModel(new(Action))
}

// GetOpType gets the ActionType of this action.
func (a *Action) GetOpType() ActionType {
	return a.OpType
}

// LoadActUser loads a.ActUser
func (a *Action) LoadActUser() {
	if a.ActUser != nil {
		return
	}
	var err error
	a.ActUser, err = GetUserByID(a.ActUserID)
	if err == nil {
		return
	} else if IsErrUserNotExist(err) {
		a.ActUser = NewGhostUser()
	} else {
		log.Error("GetUserByID(%d): %v", a.ActUserID, err)
	}
}

func (a *Action) loadRepo() {
	if a.Repo != nil {
		return
	}
	var err error
	a.Repo, err = GetRepositoryByID(a.RepoID)
	if err != nil {
		log.Error("GetRepositoryByID(%d): %v", a.RepoID, err)
	}
}

// GetActFullName gets the action's user full name.
func (a *Action) GetActFullName() string {
	a.LoadActUser()
	return a.ActUser.FullName
}

// GetActUserName gets the action's user name.
func (a *Action) GetActUserName() string {
	a.LoadActUser()
	return a.ActUser.Name
}

// ShortActUserName gets the action's user name trimmed to max 20
// chars.
func (a *Action) ShortActUserName() string {
	return base.EllipsisString(a.GetActUserName(), 20)
}

// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
func (a *Action) GetDisplayName() string {
	if setting.UI.DefaultShowFullName {
		trimmedFullName := strings.TrimSpace(a.GetActFullName())
		if len(trimmedFullName) > 0 {
			return trimmedFullName
		}
	}
	return a.ShortActUserName()
}

// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
func (a *Action) GetDisplayNameTitle() string {
	if setting.UI.DefaultShowFullName {
		return a.ShortActUserName()
	}
	return a.GetActFullName()
}

// GetRepoUserName returns the name of the action repository owner.
func (a *Action) GetRepoUserName() string {
	a.loadRepo()
	return a.Repo.OwnerName
}

// ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars.
func (a *Action) ShortRepoUserName() string {
	return base.EllipsisString(a.GetRepoUserName(), 20)
}

// GetRepoName returns the name of the action repository.
func (a *Action) GetRepoName() string {
	a.loadRepo()
	return a.Repo.Name
}

// ShortRepoName returns the name of the action repository
// trimmed to max 33 chars.
func (a *Action) ShortRepoName() string {
	return base.EllipsisString(a.GetRepoName(), 33)
}

// GetRepoPath returns the virtual path to the action repository.
func (a *Action) GetRepoPath() string {
	return path.Join(a.GetRepoUserName(), a.GetRepoName())
}

// ShortRepoPath returns the virtual path to the action repository
// trimmed to max 20 + 1 + 33 chars.
func (a *Action) ShortRepoPath() string {
	return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
}

// GetRepoLink returns relative link to action repository.
func (a *Action) GetRepoLink() string {
	if len(setting.AppSubURL) > 0 {
		return path.Join(setting.AppSubURL, a.GetRepoPath())
	}
	return "/" + a.GetRepoPath()
}

// GetRepositoryFromMatch returns a *Repository from a username and repo strings
func GetRepositoryFromMatch(ownerName, repoName string) (*Repository, error) {
	var err error
	refRepo, err := GetRepositoryByOwnerAndName(ownerName, repoName)
	if err != nil {
		if IsErrRepoNotExist(err) {
			log.Warn("Repository referenced in commit but does not exist: %v", err)
			return nil, err
		}
		log.Error("GetRepositoryByOwnerAndName: %v", err)
		return nil, err
	}
	return refRepo, nil
}

// GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string {
	return a.getCommentLink(db.DefaultContext().Engine())
}

func (a *Action) getCommentLink(e db.Engine) string {
	if a == nil {
		return "#"
	}
	if a.Comment == nil && a.CommentID != 0 {
		a.Comment, _ = getCommentByID(e, a.CommentID)
	}
	if a.Comment != nil {
		return a.Comment.HTMLURL()
	}
	if len(a.GetIssueInfos()) == 0 {
		return "#"
	}
	// Return link to issue
	issueIDString := a.GetIssueInfos()[0]
	issueID, err := strconv.ParseInt(issueIDString, 10, 64)
	if err != nil {
		return "#"
	}

	issue, err := getIssueByID(e, issueID)
	if err != nil {
		return "#"
	}

	if err = issue.loadRepo(e); err != nil {
		return "#"
	}

	return issue.HTMLURL()
}

// GetBranch returns the action's repository branch.
func (a *Action) GetBranch() string {
	return strings.TrimPrefix(a.RefName, git.BranchPrefix)
}

// GetTag returns the action's repository tag.
func (a *Action) GetTag() string {
	return strings.TrimPrefix(a.RefName, git.TagPrefix)
}

// GetContent returns the action's content.
func (a *Action) GetContent() string {
	return a.Content
}

// GetCreate returns the action creation time.
func (a *Action) GetCreate() time.Time {
	return a.CreatedUnix.AsTime()
}

// GetIssueInfos returns a list of issues associated with
// the action.
func (a *Action) GetIssueInfos() []string {
	return strings.SplitN(a.Content, "|", 3)
}

// GetIssueTitle returns the title of first issue associated
// with the action.
func (a *Action) GetIssueTitle() string {
	index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
	issue, err := GetIssueByIndex(a.RepoID, index)
	if err != nil {
		log.Error("GetIssueByIndex: %v", err)
		return "500 when get issue"
	}
	return issue.Title
}

// GetIssueContent returns the content of first issue associated with
// this action.
func (a *Action) GetIssueContent() string {
	index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
	issue, err := GetIssueByIndex(a.RepoID, index)
	if err != nil {
		log.Error("GetIssueByIndex: %v", err)
		return "500 when get issue"
	}
	return issue.Content
}

// GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct {
	RequestedUser   *User  // the user we want activity for
	RequestedTeam   *Team  // the team we want activity for
	Actor           *User  // the user viewing the activity
	IncludePrivate  bool   // include private actions
	OnlyPerformedBy bool   // only actions performed by requested user
	IncludeDeleted  bool   // include deleted actions
	Date            string // the day we want activity for: YYYY-MM-DD
}

// GetFeeds returns actions according to the provided options
func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
	if !activityReadable(opts.RequestedUser, opts.Actor) {
		return make([]*Action, 0), nil
	}

	cond, err := activityQueryCondition(opts)
	if err != nil {
		return nil, err
	}

	actions := make([]*Action, 0, setting.UI.FeedPagingNum)

	if err := db.DefaultContext().Engine().Limit(setting.UI.FeedPagingNum).Desc("id").Where(cond).Find(&actions); err != nil {
		return nil, fmt.Errorf("Find: %v", err)
	}

	if err := ActionList(actions).LoadAttributes(); err != nil {
		return nil, fmt.Errorf("LoadAttributes: %v", err)
	}

	return actions, nil
}

func activityReadable(user, doer *User) bool {
	var doerID int64
	if doer != nil {
		doerID = doer.ID
	}
	if doer == nil || !doer.IsAdmin {
		if user.KeepActivityPrivate && doerID != user.ID {
			return false
		}
	}
	return true
}

func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
	cond := builder.NewCond()

	var repoIDs []int64
	var actorID int64
	if opts.Actor != nil {
		actorID = opts.Actor.ID
	}

	// check readable repositories by doer/actor
	if opts.Actor == nil || !opts.Actor.IsAdmin {
		if opts.RequestedUser.IsOrganization() {
			env, err := opts.RequestedUser.AccessibleReposEnv(actorID)
			if err != nil {
				return nil, fmt.Errorf("AccessibleReposEnv: %v", err)
			}
			if repoIDs, err = env.RepoIDs(1, opts.RequestedUser.NumRepos); err != nil {
				return nil, fmt.Errorf("GetUserRepositories: %v", err)
			}
			cond = cond.And(builder.In("repo_id", repoIDs))
		} else {
			cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor)))
		}
	}

	if opts.RequestedTeam != nil {
		env := opts.RequestedUser.AccessibleTeamReposEnv(opts.RequestedTeam)
		teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
		if err != nil {
			return nil, fmt.Errorf("GetTeamRepositories: %v", err)
		}
		cond = cond.And(builder.In("repo_id", teamRepoIDs))
	}

	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})

	if opts.OnlyPerformedBy {
		cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
	}
	if !opts.IncludePrivate {
		cond = cond.And(builder.Eq{"is_private": false})
	}
	if !opts.IncludeDeleted {
		cond = cond.And(builder.Eq{"is_deleted": false})
	}

	if opts.Date != "" {
		dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
		if err != nil {
			log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
		} else {
			dateHigh := dateLow.Add(86399000000000) // 23h59m59s

			cond = cond.And(builder.Gte{"created_unix": dateLow.Unix()})
			cond = cond.And(builder.Lte{"created_unix": dateHigh.Unix()})
		}
	}

	return cond, nil
}

// DeleteOldActions deletes all old actions from database.
func DeleteOldActions(olderThan time.Duration) (err error) {
	if olderThan <= 0 {
		return nil
	}

	_, err = db.DefaultContext().Engine().Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
	return
}
<commit_msg>Fix problem when database id is not increment as expected (#17124)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"fmt"
	"path"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/timeutil"

	"xorm.io/builder"
)

// ActionType represents the type of an action.
type ActionType int

// Possible action types.
const (
	ActionCreateRepo                ActionType = iota + 1 // 1
	ActionRenameRepo                                      // 2
	ActionStarRepo                                        // 3
	ActionWatchRepo                                       // 4
	ActionCommitRepo                                      // 5
	ActionCreateIssue                                     // 6
	ActionCreatePullRequest                               // 7
	ActionTransferRepo                                    // 8
	ActionPushTag                                         // 9
	ActionCommentIssue                                    // 10
	ActionMergePullRequest                                // 11
	ActionCloseIssue                                      // 12
	ActionReopenIssue                                     // 13
	ActionClosePullRequest                                // 14
	ActionReopenPullRequest                               // 15
	ActionDeleteTag                                       // 16
	ActionDeleteBranch                                    // 17
	ActionMirrorSyncPush                                  // 18
	ActionMirrorSyncCreate                                // 19
	ActionMirrorSyncDelete                                // 20
	ActionApprovePullRequest                              // 21
	ActionRejectPullRequest                               // 22
	ActionCommentPull                                     // 23
	ActionPublishRelease                                  // 24
	ActionPullReviewDismissed                             // 25
	ActionPullRequestReadyForReview                       // 26
)

// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
type Action struct {
	ID          int64 `xorm:"pk autoincr"`
	UserID      int64 `xorm:"INDEX"` // Receiver user id.
	OpType      ActionType
	ActUserID   int64       `xorm:"INDEX"` // Action user id.
	ActUser     *User       `xorm:"-"`
	RepoID      int64       `xorm:"INDEX"`
	Repo        *Repository `xorm:"-"`
	CommentID   int64       `xorm:"INDEX"`
	Comment     *Comment    `xorm:"-"`
	IsDeleted   bool        `xorm:"INDEX NOT NULL DEFAULT false"`
	RefName     string
	IsPrivate   bool               `xorm:"INDEX NOT NULL DEFAULT false"`
	Content     string             `xorm:"TEXT"`
	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}

func init() {
	db.RegisterModel(new(Action))
}

// GetOpType gets the ActionType of this action.
func (a *Action) GetOpType() ActionType {
	return a.OpType
}

// LoadActUser loads a.ActUser
func (a *Action) LoadActUser() {
	if a.ActUser != nil {
		return
	}
	var err error
	a.ActUser, err = GetUserByID(a.ActUserID)
	if err == nil {
		return
	} else if IsErrUserNotExist(err) {
		a.ActUser = NewGhostUser()
	} else {
		log.Error("GetUserByID(%d): %v", a.ActUserID, err)
	}
}

func (a *Action) loadRepo() {
	if a.Repo != nil {
		return
	}
	var err error
	a.Repo, err = GetRepositoryByID(a.RepoID)
	if err != nil {
		log.Error("GetRepositoryByID(%d): %v", a.RepoID, err)
	}
}

// GetActFullName gets the action's user full name.
func (a *Action) GetActFullName() string {
	a.LoadActUser()
	return a.ActUser.FullName
}

// GetActUserName gets the action's user name.
func (a *Action) GetActUserName() string {
	a.LoadActUser()
	return a.ActUser.Name
}

// ShortActUserName gets the action's user name trimmed to max 20
// chars.
func (a *Action) ShortActUserName() string {
	return base.EllipsisString(a.GetActUserName(), 20)
}

// GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
func (a *Action) GetDisplayName() string {
	if setting.UI.DefaultShowFullName {
		trimmedFullName := strings.TrimSpace(a.GetActFullName())
		if len(trimmedFullName) > 0 {
			return trimmedFullName
		}
	}
	return a.ShortActUserName()
}

// GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
func (a *Action) GetDisplayNameTitle() string {
	if setting.UI.DefaultShowFullName {
		return a.ShortActUserName()
	}
	return a.GetActFullName()
}

// GetRepoUserName returns the name of the action repository owner.
func (a *Action) GetRepoUserName() string {
	a.loadRepo()
	return a.Repo.OwnerName
}

// ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars.
func (a *Action) ShortRepoUserName() string {
	return base.EllipsisString(a.GetRepoUserName(), 20)
}

// GetRepoName returns the name of the action repository.
func (a *Action) GetRepoName() string {
	a.loadRepo()
	return a.Repo.Name
}

// ShortRepoName returns the name of the action repository
// trimmed to max 33 chars.
func (a *Action) ShortRepoName() string {
	return base.EllipsisString(a.GetRepoName(), 33)
}

// GetRepoPath returns the virtual path to the action repository.
func (a *Action) GetRepoPath() string {
	return path.Join(a.GetRepoUserName(), a.GetRepoName())
}

// ShortRepoPath returns the virtual path to the action repository
// trimmed to max 20 + 1 + 33 chars.
func (a *Action) ShortRepoPath() string {
	return path.Join(a.ShortRepoUserName(), a.ShortRepoName())
}

// GetRepoLink returns relative link to action repository.
func (a *Action) GetRepoLink() string {
	if len(setting.AppSubURL) > 0 {
		return path.Join(setting.AppSubURL, a.GetRepoPath())
	}
	return "/" + a.GetRepoPath()
}

// GetRepositoryFromMatch returns a *Repository from a username and repo strings
func GetRepositoryFromMatch(ownerName, repoName string) (*Repository, error) {
	var err error
	refRepo, err := GetRepositoryByOwnerAndName(ownerName, repoName)
	if err != nil {
		if IsErrRepoNotExist(err) {
			log.Warn("Repository referenced in commit but does not exist: %v", err)
			return nil, err
		}
		log.Error("GetRepositoryByOwnerAndName: %v", err)
		return nil, err
	}
	return refRepo, nil
}

// GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string {
	return a.getCommentLink(db.DefaultContext().Engine())
}

func (a *Action) getCommentLink(e db.Engine) string {
	if a == nil {
		return "#"
	}
	if a.Comment == nil && a.CommentID != 0 {
		a.Comment, _ = getCommentByID(e, a.CommentID)
	}
	if a.Comment != nil {
		return a.Comment.HTMLURL()
	}
	if len(a.GetIssueInfos()) == 0 {
		return "#"
	}
	// Return link to issue
	issueIDString := a.GetIssueInfos()[0]
	issueID, err := strconv.ParseInt(issueIDString, 10, 64)
	if err != nil {
		return "#"
	}

	issue, err := getIssueByID(e, issueID)
	if err != nil {
		return "#"
	}

	if err = issue.loadRepo(e); err != nil {
		return "#"
	}

	return issue.HTMLURL()
}

// GetBranch returns the action's repository branch.
func (a *Action) GetBranch() string {
	return strings.TrimPrefix(a.RefName, git.BranchPrefix)
}

// GetTag returns the action's repository tag.
func (a *Action) GetTag() string {
	return strings.TrimPrefix(a.RefName, git.TagPrefix)
}

// GetContent returns the action's content.
func (a *Action) GetContent() string {
	return a.Content
}

// GetCreate returns the action creation time.
func (a *Action) GetCreate() time.Time {
	return a.CreatedUnix.AsTime()
}

// GetIssueInfos returns a list of issues associated with
// the action.
func (a *Action) GetIssueInfos() []string {
	return strings.SplitN(a.Content, "|", 3)
}

// GetIssueTitle returns the title of first issue associated
// with the action.
func (a *Action) GetIssueTitle() string {
	index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
	issue, err := GetIssueByIndex(a.RepoID, index)
	if err != nil {
		log.Error("GetIssueByIndex: %v", err)
		return "500 when get issue"
	}
	return issue.Title
}

// GetIssueContent returns the content of first issue associated with
// this action.
func (a *Action) GetIssueContent() string {
	index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64)
	issue, err := GetIssueByIndex(a.RepoID, index)
	if err != nil {
		log.Error("GetIssueByIndex: %v", err)
		return "500 when get issue"
	}
	return issue.Content
}

// GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct {
	RequestedUser   *User  // the user we want activity for
	RequestedTeam   *Team  // the team we want activity for
	Actor           *User  // the user viewing the activity
	IncludePrivate  bool   // include private actions
	OnlyPerformedBy bool   // only actions performed by requested user
	IncludeDeleted  bool   // include deleted actions
	Date            string // the day we want activity for: YYYY-MM-DD
}

// GetFeeds returns actions according to the provided options
func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
	if !activityReadable(opts.RequestedUser, opts.Actor) {
		return make([]*Action, 0), nil
	}

	cond, err := activityQueryCondition(opts)
	if err != nil {
		return nil, err
	}

	actions := make([]*Action, 0, setting.UI.FeedPagingNum)

	if err := db.DefaultContext().Engine().Limit(setting.UI.FeedPagingNum).Desc("created_unix").Where(cond).Find(&actions); err != nil {
		return nil, fmt.Errorf("Find: %v", err)
	}

	if err := ActionList(actions).LoadAttributes(); err != nil {
		return nil, fmt.Errorf("LoadAttributes: %v", err)
	}

	return actions, nil
}

func activityReadable(user, doer *User) bool {
	var doerID int64
	if doer != nil {
		doerID = doer.ID
	}
	if doer == nil || !doer.IsAdmin {
		if user.KeepActivityPrivate && doerID != user.ID {
			return false
		}
	}
	return true
}

func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
	cond := builder.NewCond()

	var repoIDs []int64
	var actorID int64
	if opts.Actor != nil {
		actorID = opts.Actor.ID
	}

	// check readable repositories by doer/actor
	if opts.Actor == nil || !opts.Actor.IsAdmin {
		if opts.RequestedUser.IsOrganization() {
			env, err := opts.RequestedUser.AccessibleReposEnv(actorID)
			if err != nil {
				return nil, fmt.Errorf("AccessibleReposEnv: %v", err)
			}
			if repoIDs, err = env.RepoIDs(1, opts.RequestedUser.NumRepos); err != nil {
				return nil, fmt.Errorf("GetUserRepositories: %v", err)
			}
			cond = cond.And(builder.In("repo_id", repoIDs))
		} else {
			cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor)))
		}
	}

	if opts.RequestedTeam != nil {
		env := opts.RequestedUser.AccessibleTeamReposEnv(opts.RequestedTeam)
		teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos)
		if err != nil {
			return nil, fmt.Errorf("GetTeamRepositories: %v", err)
		}
		cond = cond.And(builder.In("repo_id", teamRepoIDs))
	}

	cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})

	if opts.OnlyPerformedBy {
		cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
	}
	if !opts.IncludePrivate {
		cond = cond.And(builder.Eq{"is_private": false})
	}
	if !opts.IncludeDeleted {
		cond = cond.And(builder.Eq{"is_deleted": false})
	}

	if opts.Date != "" {
		dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
		if err != nil {
			log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
		} else {
			dateHigh := dateLow.Add(86399000000000) // 23h59m59s

			cond = cond.And(builder.Gte{"created_unix": dateLow.Unix()})
			cond = cond.And(builder.Lte{"created_unix": dateHigh.Unix()})
		}
	}

	return cond, nil
}

// DeleteOldActions deletes all old actions from database.
func DeleteOldActions(olderThan time.Duration) (err error) {
	if olderThan <= 0 {
		return nil
	}

	_, err = db.DefaultContext().Engine().Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
	return
}
<|endoftext|>