<commit_before>package sra

// What do the different SRA accessions represent?
// http://www.ncbi.nlm.nih.gov/books/NBK56913/#search.what_do_the_different_sra_accessi

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"time"
)

type SRASetter interface {
	GetItems() []Itemer
	GetAccessions() []string
}

type Itemer interface {
	String() string
	XMLString() string
	GetAccession() string
}

type SraItem struct {
	Id           string
	SubmissionId string
	XMLFileName  string
	Type         string
	Status       string
	Updated      time.Time
	Published    time.Time
	Received     time.Time
	Visibility   string
	Experiment   string
	Sample       string
	Study        string
	MD5          string
	BioSample    string
	BioProject   string
	Data         Itemer
}

func (si *SraItem) setId() {
	accession := si.Data.GetAccession()
	si.Id = accession
}

func (si *SraItem) AddAttrFromAccessionRecords(
	db *map[string]*AccessionRecord,
) {
	if data, ok := (*db)[si.Id]; ok {
		si.Status = data.Status
		si.Updated = data.Updated
		si.Published = data.Published
		si.Received = data.Received
		si.Visibility = data.Visibility
		si.Experiment = data.Experiment
		si.Sample = data.Sample
		si.Study = data.Study
		si.MD5 = data.MD5
		si.BioSample = data.BioSample
		si.BioProject = data.BioProject
	}
}

func (si *SraItem) UnmarshalJSON(data []byte) error {
	var aux struct {
		Id           string
		SubmissionId string
		XMLFileName  string
		Type         string
		Status       string
		Visibility   string
		Updated      string
		Published    string
		Received     string
		Data         json.RawMessage
	}

	dec := json.NewDecoder(bytes.NewReader(data))
	if err := dec.Decode(&aux); err != nil {
		return fmt.Errorf("decode sra item: %v", err)
	}

	si.Id = aux.Id
	si.SubmissionId = aux.SubmissionId
	si.XMLFileName = aux.XMLFileName
	si.Type = aux.Type
	si.Status = aux.Status
	si.Visibility = aux.Visibility

	t, err := time.Parse("2006-01-02T15:04:05Z", aux.Updated)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Updated,
			err,
		)
	}
	si.Updated = t

	t, err = time.Parse("2006-01-02T15:04:05Z", aux.Published)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Published,
			err,
		)
	}
	si.Published = t

	t, err = time.Parse("2006-01-02T15:04:05Z", aux.Received)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Received,
			err,
		)
	}
	si.Received = t

	var item Itemer
	switch si.Type {
	case "analysis":
		var analysis SraAnalysis
		err = json.Unmarshal([]byte(aux.Data), &analysis)
		if err != nil {
			return fmt.Errorf(
				"[SraAnalysis] JSON Unmarshal error: %v", err,
			)
		}
		item = analysis
	case "experiment":
		var exp SraExp
		err = json.Unmarshal([]byte(aux.Data), &exp)
		if err != nil {
			return fmt.Errorf(
				"[SraExp] JSON Unmarshal error: %v", err,
			)
		}
		item = exp
	case "run":
		var run SraRun
		err = json.Unmarshal([]byte(aux.Data), &run)
		if err != nil {
			return fmt.Errorf(
				"[SraRun] JSON Unmarshal error: %v", err,
			)
		}
		item = run
	case "sample":
		var sample SraSample
		err = json.Unmarshal([]byte(aux.Data), &sample)
		if err != nil {
			return fmt.Errorf(
				"[SraSample] JSON Unmarshal error: %v", err,
			)
		}
		item = sample
	case "study":
		var study SraStudy
		err = json.Unmarshal([]byte(aux.Data), &study)
		if err != nil {
			return fmt.Errorf(
				"[SraStudy] JSON Unmarshal error: %v", err,
			)
		}
		item = study
	case "submission":
		var submission SraSubmission
		err = json.Unmarshal([]byte(aux.Data), &submission)
		if err != nil {
			return fmt.Errorf(
				"[SraSubmission] JSON Unmarshal error: %v", err,
			)
		}
		item = submission
	default:
		return fmt.Errorf(
			"Don't know how to parse sra item of type '%s'\n",
			si.Type,
		)
	}

	si.Data = item
	return nil
}

func NewSraItemsFromXML(filename string, contents []byte) []*SraItem {
	basename := filepath.Base(filename)
	id, sraType, _ := parseXMLFileName(basename)
	set := parseXMLContents(sraType, contents)

	sraItems := make([]*SraItem, 0)

	for _, item := range set.GetItems() {
		si := &SraItem{
			SubmissionId: id,
			XMLFileName:  basename,
			Type:         sraType,
			Data:         item,
		}
		si.setId()
		sraItems = append(sraItems, si)
	}
	return sraItems
}

func parseXMLFileName(filename string) (string, string, string) {
	items := strings.Split(filename, ".")
	submissionAccession, sraType, extension := items[0], items[1], items[2]
	return submissionAccession, sraType, extension
}

func parseXMLContents(sraType string, contents []byte) SRASetter {
	var data SRASetter
	switch sraType {
	case "analysis":
		var analyses SraAnalysisSet
		xml.Unmarshal(contents, &analyses)
		data = analyses
	case "experiment":
		var exps SraExpSet
		xml.Unmarshal(contents, &exps)
		data = exps
	case "run":
		var runs SraRunSet
		xml.Unmarshal(contents, &runs)
		data = runs
	case "sample":
		var samples SraSampleSet
		xml.Unmarshal(contents, &samples)
		data = samples
	case "study":
		var studies SraStudySet
		xml.Unmarshal(contents, &studies)
		data = studies
	case "submission":
		var submission SraSubmission
		xml.Unmarshal(contents, &submission)
		data = submission
	default:
		log.Fatalf(
			"Don't know how to parse '%s' XML contents!",
			sraType,
		)
	}
	return data
}
<commit_msg>+ add new Accession Fields when UnMarshalJSON on SraItem<commit_after>package sra

// What do the different SRA accessions represent?
// http://www.ncbi.nlm.nih.gov/books/NBK56913/#search.what_do_the_different_sra_accessi

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"time"
)

type SRASetter interface {
	GetItems() []Itemer
	GetAccessions() []string
}

type Itemer interface {
	String() string
	XMLString() string
	GetAccession() string
}

type SraItem struct {
	Id           string
	SubmissionId string
	XMLFileName  string
	Type         string
	Status       string
	Updated      time.Time
	Published    time.Time
	Received     time.Time
	Visibility   string
	Experiment   string
	Sample       string
	Study        string
	MD5          string
	BioSample    string
	BioProject   string
	Data         Itemer
}

func (si *SraItem) setId() {
	accession := si.Data.GetAccession()
	si.Id = accession
}

func (si *SraItem) AddAttrFromAccessionRecords(
	db *map[string]*AccessionRecord,
) {
	if data, ok := (*db)[si.Id]; ok {
		si.Status = data.Status
		si.Updated = data.Updated
		si.Published = data.Published
		si.Received = data.Received
		si.Visibility = data.Visibility
		si.Experiment = data.Experiment
		si.Sample = data.Sample
		si.Study = data.Study
		si.MD5 = data.MD5
		si.BioSample = data.BioSample
		si.BioProject = data.BioProject
	}
}

func (si *SraItem) UnmarshalJSON(data []byte) error {
	var aux struct {
		Id           string
		SubmissionId string
		XMLFileName  string
		Type         string
		Status       string
		Visibility   string
		Updated      string
		Published    string
		Received     string
		Experiment   string
		Sample       string
		Study        string
		MD5          string
		BioSample    string
		BioProject   string
		Data         json.RawMessage
	}

	dec := json.NewDecoder(bytes.NewReader(data))
	if err := dec.Decode(&aux); err != nil {
		return fmt.Errorf("decode sra item: %v", err)
	}

	si.Id = aux.Id
	si.SubmissionId = aux.SubmissionId
	si.XMLFileName = aux.XMLFileName
	si.Type = aux.Type
	si.Status = aux.Status
	si.Visibility = aux.Visibility
	si.Experiment = aux.Experiment
	si.Sample = aux.Sample
	si.Study = aux.Study
	si.MD5 = aux.MD5
	si.BioSample = aux.BioSample
	si.BioProject = aux.BioProject

	t, err := time.Parse("2006-01-02T15:04:05Z", aux.Updated)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Updated,
			err,
		)
	}
	si.Updated = t

	t, err = time.Parse("2006-01-02T15:04:05Z", aux.Published)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Published,
			err,
		)
	}
	si.Published = t

	t, err = time.Parse("2006-01-02T15:04:05Z", aux.Received)
	if err != nil {
		return fmt.Errorf(
			"%s: '%s' : %s\n",
			"JSON Unmarshal error: Trouble parsing timestamp",
			aux.Received,
			err,
		)
	}
	si.Received = t

	var item Itemer
	switch si.Type {
	case "analysis":
		var analysis SraAnalysis
		err = json.Unmarshal([]byte(aux.Data), &analysis)
		if err != nil {
			return fmt.Errorf(
				"[SraAnalysis] JSON Unmarshal error: %v", err,
			)
		}
		item = analysis
	case "experiment":
		var exp SraExp
		err = json.Unmarshal([]byte(aux.Data), &exp)
		if err != nil {
			return fmt.Errorf(
				"[SraExp] JSON Unmarshal error: %v", err,
			)
		}
		item = exp
	case "run":
		var run SraRun
		err = json.Unmarshal([]byte(aux.Data), &run)
		if err != nil {
			return fmt.Errorf(
				"[SraRun] JSON Unmarshal error: %v", err,
			)
		}
		item = run
	case "sample":
		var sample SraSample
		err = json.Unmarshal([]byte(aux.Data), &sample)
		if err != nil {
			return fmt.Errorf(
				"[SraSample] JSON Unmarshal error: %v", err,
			)
		}
		item = sample
	case "study":
		var study SraStudy
		err = json.Unmarshal([]byte(aux.Data), &study)
		if err != nil {
			return fmt.Errorf(
				"[SraStudy] JSON Unmarshal error: %v", err,
			)
		}
		item = study
	case "submission":
		var submission SraSubmission
		err = json.Unmarshal([]byte(aux.Data), &submission)
		if err != nil {
			return fmt.Errorf(
				"[SraSubmission] JSON Unmarshal error: %v", err,
			)
		}
		item = submission
	default:
		return fmt.Errorf(
			"Don't know how to parse sra item of type '%s'\n",
			si.Type,
		)
	}

	si.Data = item
	return nil
}

func NewSraItemsFromXML(filename string, contents []byte) []*SraItem {
	basename := filepath.Base(filename)
	id, sraType, _ := parseXMLFileName(basename)
	set := parseXMLContents(sraType, contents)

	sraItems := make([]*SraItem, 0)

	for _, item := range set.GetItems() {
		si := &SraItem{
			SubmissionId: id,
			XMLFileName:  basename,
			Type:         sraType,
			Data:         item,
		}
		si.setId()
		sraItems = append(sraItems, si)
	}
	return sraItems
}

func parseXMLFileName(filename string) (string, string, string) {
	items := strings.Split(filename, ".")
	submissionAccession, sraType, extension := items[0], items[1], items[2]
	return submissionAccession, sraType, extension
}

func parseXMLContents(sraType string, contents []byte) SRASetter {
	var data SRASetter
	switch sraType {
	case "analysis":
		var analyses SraAnalysisSet
		xml.Unmarshal(contents, &analyses)
		data = analyses
	case "experiment":
		var exps SraExpSet
		xml.Unmarshal(contents, &exps)
		data = exps
	case "run":
		var runs SraRunSet
		xml.Unmarshal(contents, &runs)
		data = runs
	case "sample":
		var samples SraSampleSet
		xml.Unmarshal(contents, &samples)
		data = samples
	case "study":
		var studies SraStudySet
		xml.Unmarshal(contents, &studies)
		data = studies
	case "submission":
		var submission SraSubmission
		xml.Unmarshal(contents, &submission)
		data = submission
	default:
		log.Fatalf(
			"Don't know how to parse '%s' XML contents!",
			sraType,
		)
	}
	return data
}
<|endoftext|>


<commit_before>package ebpf

import (
	"strings"
	"testing"

	"github.com/cilium/ebpf/asm"
	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/testutils"
	"github.com/cilium/ebpf/internal/unix"
)

func TestMapInfoFromProc(t *testing.T) {
	hash, err := NewMap(&MapSpec{
		Name:       "testing",
		Type:       Hash,
		KeySize:    4,
		ValueSize:  5,
		MaxEntries: 2,
		Flags:      unix.BPF_F_NO_PREALLOC,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer hash.Close()

	info, err := newMapInfoFromProc(hash.fd)
	if err != nil {
		t.Fatal("Can't get map info:", err)
	}

	if info.Type != Hash {
		t.Error("Expected Hash, got", info.Type)
	}

	if info.KeySize != 4 {
		t.Error("Expected KeySize of 4, got", info.KeySize)
	}

	if info.ValueSize != 5 {
		t.Error("Expected ValueSize of 5, got", info.ValueSize)
	}

	if info.MaxEntries != 2 {
		t.Error("Expected MaxEntries of 2, got", info.MaxEntries)
	}

	if info.Flags != unix.BPF_F_NO_PREALLOC {
		t.Errorf("Expected Flags to be %d, got %d", unix.BPF_F_NO_PREALLOC, info.Flags)
	}

	if info.Name != "" && info.Name != "testing" {
		t.Error("Expected name to be testing, got", info.Name)
	}

	if _, ok := info.ID(); ok {
		t.Error("Expected ID to not be available")
	}

	nested, err := NewMap(&MapSpec{
		Type:       ArrayOfMaps,
		KeySize:    4,
		MaxEntries: 2,
		InnerMap: &MapSpec{
			Type:       Array,
			KeySize:    4,
			ValueSize:  4,
			MaxEntries: 2,
		},
	})
	testutils.SkipIfNotSupported(t, err)
	if err != nil {
		t.Fatal(err)
	}
	defer nested.Close()

	_, err = newMapInfoFromProc(nested.fd)
	if err != nil {
		t.Fatal("Can't get nested map info from /proc:", err)
	}
}

func TestProgramInfo(t *testing.T) {
	prog := createSocketFilter(t)
	defer prog.Close()

	for name, fn := range map[string]func(*internal.FD) (*ProgramInfo, error){
		"generic": newProgramInfoFromFd,
		"proc":    newProgramInfoFromProc,
	} {
		t.Run(name, func(t *testing.T) {
			info, err := fn(prog.fd)
			testutils.SkipIfNotSupported(t, err)
			if err != nil {
				t.Fatal("Can't get program info:", err)
			}

			if info.Type != SocketFilter {
				t.Error("Expected Type to be SocketFilter, got", info.Type)
			}

			if info.Name != "" && info.Name != "test" {
				t.Error("Expected Name to be test, got", info.Name)
			}

			if want := "d7edec644f05498d"; info.Tag != want {
				t.Errorf("Expected Tag to be %s, got %s", want, info.Tag)
			}

			if id, ok := info.ID(); ok && id == 0 {
				t.Error("Expected a valid ID:", id)
			} else if name == "proc" && ok {
				t.Error("Expected ID to not be available")
			}
		})
	}
}

func TestScanFdInfoReader(t *testing.T) {
	tests := []struct {
		fields map[string]interface{}
		valid  bool
	}{
		{nil, true},
		{map[string]interface{}{"foo": new(string)}, true},
		{map[string]interface{}{"zap": new(string)}, false},
		{map[string]interface{}{"foo": new(int)}, false},
	}

	for _, test := range tests {
		err := scanFdInfoReader(strings.NewReader("foo:\tbar\n"), test.fields)
		if test.valid {
			if err != nil {
				t.Errorf("fields %v returns an error: %s", test.fields, err)
			}
		} else {
			if err == nil {
				t.Errorf("fields %v doesn't return an error", test.fields)
			}
		}
	}
}

func TestStats(t *testing.T) {
	testutils.SkipOnOldKernel(t, "5.8", "BPF_ENABLE_STATS")

	spec := &ProgramSpec{
		Type: SocketFilter,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 42, asm.DWord),
			asm.Return(),
		},
		License: "MIT",
	}

	prog, err := NewProgram(spec)
	if err != nil {
		t.Fatal(err)
	}
	defer prog.Close()

	progInfo, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	if cnt, available := progInfo.RunCount(); cnt != 0 || !available {
		t.Errorf("expected a run count of 0 but got %d", cnt)
	}

	if runtime, available := progInfo.Runtime(); runtime != 0 || !available {
		t.Errorf("expected a runtime of 0ns but got %v", runtime)
	}

	disableStats, err := EnableStats(uint32(unix.BPF_STATS_RUN_TIME))
	if err != nil {
		t.Fatalf("failed to enable stats: %v", err)
	}
	defer disableStats.Close()

	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	progInfo2, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	if cnt, available := progInfo2.RunCount(); cnt != 1 || !available {
		t.Errorf("expected a run count of 1 but got %d", cnt)
	}

	if runtime, available := progInfo2.Runtime(); runtime == 0 || !available {
		t.Errorf("expected a runtime other than 0ns")
	}

	if err := disableStats.Close(); err != nil {
		t.Errorf("failed to disable statistics: %v", err)
	}

	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	progInfo3, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	if cnt, available := progInfo3.RunCount(); cnt != 1 || !available {
		t.Errorf("expected a run count of 1 but got %d", cnt)
	}

	if runtime, available := progInfo3.Runtime(); runtime == 0 || !available {
		t.Errorf("expected a runtime other than 0ns")
	}
}
<commit_msg>info_test: explicitly check RunCount and RunTime fields availability<commit_after>package ebpf

import (
	"strings"
	"testing"

	"github.com/cilium/ebpf/asm"
	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/testutils"
	"github.com/cilium/ebpf/internal/unix"
)

func TestMapInfoFromProc(t *testing.T) {
	hash, err := NewMap(&MapSpec{
		Name:       "testing",
		Type:       Hash,
		KeySize:    4,
		ValueSize:  5,
		MaxEntries: 2,
		Flags:      unix.BPF_F_NO_PREALLOC,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer hash.Close()

	info, err := newMapInfoFromProc(hash.fd)
	if err != nil {
		t.Fatal("Can't get map info:", err)
	}

	if info.Type != Hash {
		t.Error("Expected Hash, got", info.Type)
	}

	if info.KeySize != 4 {
		t.Error("Expected KeySize of 4, got", info.KeySize)
	}

	if info.ValueSize != 5 {
		t.Error("Expected ValueSize of 5, got", info.ValueSize)
	}

	if info.MaxEntries != 2 {
		t.Error("Expected MaxEntries of 2, got", info.MaxEntries)
	}

	if info.Flags != unix.BPF_F_NO_PREALLOC {
		t.Errorf("Expected Flags to be %d, got %d", unix.BPF_F_NO_PREALLOC, info.Flags)
	}

	if info.Name != "" && info.Name != "testing" {
		t.Error("Expected name to be testing, got", info.Name)
	}

	if _, ok := info.ID(); ok {
		t.Error("Expected ID to not be available")
	}

	nested, err := NewMap(&MapSpec{
		Type:       ArrayOfMaps,
		KeySize:    4,
		MaxEntries: 2,
		InnerMap: &MapSpec{
			Type:       Array,
			KeySize:    4,
			ValueSize:  4,
			MaxEntries: 2,
		},
	})
	testutils.SkipIfNotSupported(t, err)
	if err != nil {
		t.Fatal(err)
	}
	defer nested.Close()

	_, err = newMapInfoFromProc(nested.fd)
	if err != nil {
		t.Fatal("Can't get nested map info from /proc:", err)
	}
}

func TestProgramInfo(t *testing.T) {
	prog := createSocketFilter(t)
	defer prog.Close()

	for name, fn := range map[string]func(*internal.FD) (*ProgramInfo, error){
		"generic": newProgramInfoFromFd,
		"proc":    newProgramInfoFromProc,
	} {
		t.Run(name, func(t *testing.T) {
			info, err := fn(prog.fd)
			testutils.SkipIfNotSupported(t, err)
			if err != nil {
				t.Fatal("Can't get program info:", err)
			}

			if info.Type != SocketFilter {
				t.Error("Expected Type to be SocketFilter, got", info.Type)
			}

			if info.Name != "" && info.Name != "test" {
				t.Error("Expected Name to be test, got", info.Name)
			}

			if want := "d7edec644f05498d"; info.Tag != want {
				t.Errorf("Expected Tag to be %s, got %s", want, info.Tag)
			}

			if id, ok := info.ID(); ok && id == 0 {
				t.Error("Expected a valid ID:", id)
			} else if name == "proc" && ok {
				t.Error("Expected ID to not be available")
			}
		})
	}
}

func TestScanFdInfoReader(t *testing.T) {
	tests := []struct {
		fields map[string]interface{}
		valid  bool
	}{
		{nil, true},
		{map[string]interface{}{"foo": new(string)}, true},
		{map[string]interface{}{"zap": new(string)}, false},
		{map[string]interface{}{"foo": new(int)}, false},
	}

	for _, test := range tests {
		err := scanFdInfoReader(strings.NewReader("foo:\tbar\n"), test.fields)
		if test.valid {
			if err != nil {
				t.Errorf("fields %v returns an error: %s", test.fields, err)
			}
		} else {
			if err == nil {
				t.Errorf("fields %v doesn't return an error", test.fields)
			}
		}
	}
}

// TestStats loads a BPF program once and executes back-to-back test runs
// of the program. First, a test run is executed with runtime statistics
// enabled, followed by another with runtime stats disabled. Counters are only
// expected to increase on the runs where runtime stats are enabled.
//
// Due to runtime behaviour on Go 1.14 and higher, the syscall backing
// (*Program).Test() could be invoked multiple times for each call to Test(),
// resulting in RunCount incrementing by more than one. Expecting RunCount to
// be of a specific value after a call to Test() is therefore not possible.
// See https://golang.org/doc/go1.14#runtime for more details.
func TestStats(t *testing.T) {
	testutils.SkipOnOldKernel(t, "5.8", "BPF_ENABLE_STATS")

	spec := &ProgramSpec{
		Type: SocketFilter,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 42, asm.DWord),
			asm.Return(),
		},
		License: "MIT",
	}

	prog, err := NewProgram(spec)
	if err != nil {
		t.Fatal(err)
	}
	defer prog.Close()

	pi, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok := pi.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc != 0 {
		t.Errorf("expected a run count of 0 but got %d", rc)
	}

	rt, ok := pi.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt != 0 {
		t.Errorf("expected a runtime of 0ns but got %v", rt)
	}

	stats, err := EnableStats(uint32(unix.BPF_STATS_RUN_TIME))
	if err != nil {
		t.Fatalf("failed to enable stats: %v", err)
	}
	defer stats.Close()

	// Program execution with runtime statistics enabled.
	// Should increase both runtime and run counter.
	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	pi2, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok = pi2.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc < 1 {
		t.Errorf("expected a run count of at least 1 but got %d", rc)
	}
	// Store the run count for the next invocation.
	lc := rc

	rt, ok = pi2.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt == 0 {
		t.Errorf("expected a runtime other than 0ns")
	}
	// Store the runtime value for the next invocation.
	lt := rt

	if err := stats.Close(); err != nil {
		t.Errorf("failed to disable statistics: %v", err)
	}

	// Second program execution, with runtime statistics gathering disabled.
	// Total runtime and run counters are not expected to increase.
	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	pi3, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok = pi3.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc != lc {
		t.Errorf("run count unexpectedly increased over previous value (current: %v, prev: %v)", rc, lc)
	}

	rt, ok = pi3.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt != lt {
		t.Errorf("runtime unexpectedly increased over the previous value (current: %v, prev: %v)", rt, lt)
	}
}
<|endoftext|>


<commit_before>package ebpf

import (
	"strings"
	"testing"

	"github.com/cilium/ebpf/asm"
	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/testutils"
	"github.com/cilium/ebpf/internal/unix"
)

func TestMapInfoFromProc(t *testing.T) {
	hash, err := NewMap(&MapSpec{
		Name:       "testing",
		Type:       Hash,
		KeySize:    4,
		ValueSize:  5,
		MaxEntries: 2,
		Flags:      unix.BPF_F_NO_PREALLOC,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer hash.Close()

	info, err := newMapInfoFromProc(hash.fd)
	if err != nil {
		t.Fatal("Can't get map info:", err)
	}

	if info.Type != Hash {
		t.Error("Expected Hash, got", info.Type)
	}

	if info.KeySize != 4 {
		t.Error("Expected KeySize of 4, got", info.KeySize)
	}

	if info.ValueSize != 5 {
		t.Error("Expected ValueSize of 5, got", info.ValueSize)
	}

	if info.MaxEntries != 2 {
		t.Error("Expected MaxEntries of 2, got", info.MaxEntries)
	}

	if info.Flags != unix.BPF_F_NO_PREALLOC {
		t.Errorf("Expected Flags to be %d, got %d", unix.BPF_F_NO_PREALLOC, info.Flags)
	}

	if info.Name != "" && info.Name != "testing" {
		t.Error("Expected name to be testing, got", info.Name)
	}

	if _, ok := info.ID(); ok {
		t.Error("Expected ID to not be available")
	}

	nested, err := NewMap(&MapSpec{
		Type:       ArrayOfMaps,
		KeySize:    4,
		MaxEntries: 2,
		InnerMap: &MapSpec{
			Type:       Array,
			KeySize:    4,
			ValueSize:  4,
			MaxEntries: 2,
		},
	})
	testutils.SkipIfNotSupported(t, err)
	if err != nil {
		t.Fatal(err)
	}
	defer nested.Close()

	_, err = newMapInfoFromProc(nested.fd)
	if err != nil {
		t.Fatal("Can't get nested map info from /proc:", err)
	}
}

func TestProgramInfo(t *testing.T) {
	prog := createSocketFilter(t)
	defer prog.Close()

	for name, fn := range map[string]func(*internal.FD) (*ProgramInfo, error){
		"generic": newProgramInfoFromFd,
		"proc":    newProgramInfoFromProc,
	} {
		t.Run(name, func(t *testing.T) {
			info, err := fn(prog.fd)
			testutils.SkipIfNotSupported(t, err)
			if err != nil {
				t.Fatal("Can't get program info:", err)
			}

			if info.Type != SocketFilter {
				t.Error("Expected Type to be SocketFilter, got", info.Type)
			}

			if info.Name != "" && info.Name != "test" {
				t.Error("Expected Name to be test, got", info.Name)
			}

			if want := "d7edec644f05498d"; info.Tag != want {
				t.Errorf("Expected Tag to be %s, got %s", want, info.Tag)
			}

			if id, ok := info.ID(); ok && id == 0 {
				t.Error("Expected a valid ID:", id)
			} else if name == "proc" && ok {
				t.Error("Expected ID to not be available")
			}
		})
	}
}

func TestScanFdInfoReader(t *testing.T) {
	tests := []struct {
		fields map[string]interface{}
		valid  bool
	}{
		{nil, true},
		{map[string]interface{}{"foo": new(string)}, true},
		{map[string]interface{}{"zap": new(string)}, false},
		{map[string]interface{}{"foo": new(int)}, false},
	}

	for _, test := range tests {
		err := scanFdInfoReader(strings.NewReader("foo:\tbar\n"), test.fields)
		if test.valid {
			if err != nil {
				t.Errorf("fields %v returns an error: %s", test.fields, err)
			}
		} else {
			if err == nil {
				t.Errorf("fields %v doesn't return an error", test.fields)
			}
		}
	}
}

// TestStats loads a BPF program once and executes back-to-back test runs
// of the program. First, a test run is executed with runtime statistics
// enabled, followed by another with runtime stats disabled. Counters are only
// expected to increase on the runs where runtime stats are enabled.
//
// Due to runtime behaviour on Go 1.14 and higher, the syscall backing
// (*Program).Test() could be invoked multiple times for each call to Test(),
// resulting in RunCount incrementing by more than one. Expecting RunCount to
// be of a specific value after a call to Test() is therefore not possible.
// See https://golang.org/doc/go1.14#runtime for more details.
func TestStats(t *testing.T) {
	testutils.SkipOnOldKernel(t, "5.8", "BPF_ENABLE_STATS")

	spec := &ProgramSpec{
		Type: SocketFilter,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 42, asm.DWord),
			asm.Return(),
		},
		License: "MIT",
	}

	prog, err := NewProgram(spec)
	if err != nil {
		t.Fatal(err)
	}
	defer prog.Close()

	pi, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok := pi.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc != 0 {
		t.Errorf("expected a run count of 0 but got %d", rc)
	}

	rt, ok := pi.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt != 0 {
		t.Errorf("expected a runtime of 0ns but got %v", rt)
	}

	stats, err := EnableStats(uint32(unix.BPF_STATS_RUN_TIME))
	if err != nil {
		t.Fatalf("failed to enable stats: %v", err)
	}
	defer stats.Close()

	// Program execution with runtime statistics enabled.
	// Should increase both runtime and run counter.
	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	pi2, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok = pi2.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc < 1 {
		t.Errorf("expected a run count of at least 1 but got %d", rc)
	}
	// Store the run count for the next invocation.
	lc := rc

	rt, ok = pi2.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt == 0 {
		t.Errorf("expected a runtime other than 0ns")
	}
	// Store the runtime value for the next invocation.
	lt := rt

	if err := stats.Close(); err != nil {
		t.Errorf("failed to disable statistics: %v", err)
	}

	// Second program execution, with runtime statistics gathering disabled.
	// Total runtime and run counters are not expected to increase.
	if _, _, err := prog.Test(make([]byte, 14)); err != nil {
		t.Errorf("failed to trigger program: %v", err)
	}

	pi3, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok = pi3.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc != lc {
		t.Errorf("run count unexpectedly increased over previous value (current: %v, prev: %v)", rc, lc)
	}

	rt, ok = pi3.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt != lt {
		t.Errorf("runtime unexpectedly increased over the previous value (current: %v, prev: %v)", rt, lt)
	}
}
<commit_msg>info_test: BenchmarkStats for benching BPF runtime stats<commit_after>package ebpf

import (
	"errors"
	"fmt"
	"strings"
	"testing"

	"github.com/cilium/ebpf/asm"
	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/testutils"
	"github.com/cilium/ebpf/internal/unix"
)

func TestMapInfoFromProc(t *testing.T) {
	hash, err := NewMap(&MapSpec{
		Name:       "testing",
		Type:       Hash,
		KeySize:    4,
		ValueSize:  5,
		MaxEntries: 2,
		Flags:      unix.BPF_F_NO_PREALLOC,
	})
	if err != nil {
		t.Fatal(err)
	}
	defer hash.Close()

	info, err := newMapInfoFromProc(hash.fd)
	if err != nil {
		t.Fatal("Can't get map info:", err)
	}

	if info.Type != Hash {
		t.Error("Expected Hash, got", info.Type)
	}

	if info.KeySize != 4 {
		t.Error("Expected KeySize of 4, got", info.KeySize)
	}

	if info.ValueSize != 5 {
		t.Error("Expected ValueSize of 5, got", info.ValueSize)
	}

	if info.MaxEntries != 2 {
		t.Error("Expected MaxEntries of 2, got", info.MaxEntries)
	}

	if info.Flags != unix.BPF_F_NO_PREALLOC {
		t.Errorf("Expected Flags to be %d, got %d", unix.BPF_F_NO_PREALLOC, info.Flags)
	}

	if info.Name != "" && info.Name != "testing" {
		t.Error("Expected name to be testing, got", info.Name)
	}

	if _, ok := info.ID(); ok {
		t.Error("Expected ID to not be available")
	}

	nested, err := NewMap(&MapSpec{
		Type:       ArrayOfMaps,
		KeySize:    4,
		MaxEntries: 2,
		InnerMap: &MapSpec{
			Type:       Array,
			KeySize:    4,
			ValueSize:  4,
			MaxEntries: 2,
		},
	})
	testutils.SkipIfNotSupported(t, err)
	if err != nil {
		t.Fatal(err)
	}
	defer nested.Close()

	_, err = newMapInfoFromProc(nested.fd)
	if err != nil {
		t.Fatal("Can't get nested map info from /proc:", err)
	}
}

func TestProgramInfo(t *testing.T) {
	prog := createSocketFilter(t)
	defer prog.Close()

	for name, fn := range map[string]func(*internal.FD) (*ProgramInfo, error){
		"generic": newProgramInfoFromFd,
		"proc":    newProgramInfoFromProc,
	} {
		t.Run(name, func(t *testing.T) {
			info, err := fn(prog.fd)
			testutils.SkipIfNotSupported(t, err)
			if err != nil {
				t.Fatal("Can't get program info:", err)
			}

			if info.Type != SocketFilter {
				t.Error("Expected Type to be SocketFilter, got", info.Type)
			}

			if info.Name != "" && info.Name != "test" {
				t.Error("Expected Name to be test, got", info.Name)
			}

			if want := "d7edec644f05498d"; info.Tag != want {
				t.Errorf("Expected Tag to be %s, got %s", want, info.Tag)
			}

			if id, ok := info.ID(); ok && id == 0 {
				t.Error("Expected a valid ID:", id)
			} else if name == "proc" && ok {
				t.Error("Expected ID to not be available")
			}
		})
	}
}

func TestScanFdInfoReader(t *testing.T) {
	tests := []struct {
		fields map[string]interface{}
		valid  bool
	}{
		{nil, true},
		{map[string]interface{}{"foo": new(string)}, true},
		{map[string]interface{}{"zap": new(string)}, false},
		{map[string]interface{}{"foo": new(int)}, false},
	}

	for _, test := range tests {
		err := scanFdInfoReader(strings.NewReader("foo:\tbar\n"), test.fields)
		if test.valid {
			if err != nil {
				t.Errorf("fields %v returns an error: %s", test.fields, err)
			}
		} else {
			if err == nil {
				t.Errorf("fields %v doesn't return an error", test.fields)
			}
		}
	}
}

// TestStats loads a BPF program once and executes back-to-back test runs
// of the program. See testStats for details.
func TestStats(t *testing.T) {
	testutils.SkipOnOldKernel(t, "5.8", "BPF_ENABLE_STATS")

	spec := &ProgramSpec{
		Type: SocketFilter,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 42, asm.DWord),
			asm.Return(),
		},
		License: "MIT",
	}

	prog, err := NewProgram(spec)
	if err != nil {
		t.Fatal(err)
	}
	defer prog.Close()

	pi, err := prog.Info()
	if err != nil {
		t.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok := pi.RunCount()
	if !ok {
		t.Errorf("expected run count info to be available")
	}
	if rc != 0 {
		t.Errorf("expected a run count of 0 but got %d", rc)
	}

	rt, ok := pi.Runtime()
	if !ok {
		t.Errorf("expected runtime info to be available")
	}
	if rt != 0 {
		t.Errorf("expected a runtime of 0ns but got %v", rt)
	}

	if err := testStats(prog); err != nil {
		t.Error(err)
	}
}

// BenchmarkStats is a benchmark of TestStats. See testStats for details.
func BenchmarkStats(b *testing.B) {
	testutils.SkipOnOldKernel(b, "5.8", "BPF_ENABLE_STATS")

	spec := &ProgramSpec{
		Type: SocketFilter,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 42, asm.DWord),
			asm.Return(),
		},
		License: "MIT",
	}

	// Don't insert the program in a loop as it causes a flood of kaudit messages.
	prog, err := NewProgram(spec)
	if err != nil {
		b.Fatal(err)
	}
	defer prog.Close()

	for n := 0; n < b.N; n++ {
		if err := testStats(prog); err != nil {
			b.Fatal(fmt.Errorf("iter %d: %w", n, err))
		}
	}
}

// testStats implements the behaviour under test for TestStats
// and BenchmarkStats. First, a test run is executed with runtime statistics
// enabled, followed by another with runtime stats disabled. Counters are only
// expected to increase on the runs where runtime stats are enabled.
//
// Due to runtime behaviour on Go 1.14 and higher, the syscall backing
// (*Program).Test() could be invoked multiple times for each call to Test(),
// resulting in RunCount incrementing by more than one. Expecting RunCount to
// be of a specific value after a call to Test() is therefore not possible.
// See https://golang.org/doc/go1.14#runtime for more details.
func testStats(prog *Program) error {
	in := make([]byte, 14)

	stats, err := EnableStats(uint32(unix.BPF_STATS_RUN_TIME))
	if err != nil {
		return fmt.Errorf("failed to enable stats: %v", err)
	}
	defer stats.Close()

	// Program execution with runtime statistics enabled.
	// Should increase both runtime and run counter.
	if _, _, err := prog.Test(in); err != nil {
		return fmt.Errorf("failed to trigger program: %v", err)
	}

	pi, err := prog.Info()
	if err != nil {
		return fmt.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok := pi.RunCount()
	if !ok {
		return errors.New("expected run count info to be available")
	}
	if rc < 1 {
		return fmt.Errorf("expected a run count of at least 1 but got %d", rc)
	}
	// Store the run count for the next invocation.
	lc := rc

	rt, ok := pi.Runtime()
	if !ok {
		return errors.New("expected runtime info to be available")
	}
	if rt == 0 {
		return errors.New("expected a runtime other than 0ns")
	}
	// Store the runtime value for the next invocation.
	lt := rt

	if err := stats.Close(); err != nil {
		return fmt.Errorf("failed to disable statistics: %v", err)
	}

	// Second program execution, with runtime statistics gathering disabled.
	// Total runtime and run counters are not expected to increase.
	if _, _, err := prog.Test(in); err != nil {
		return fmt.Errorf("failed to trigger program: %v", err)
	}

	pi, err = prog.Info()
	if err != nil {
		return fmt.Errorf("failed to get ProgramInfo: %v", err)
	}

	rc, ok = pi.RunCount()
	if !ok {
		return errors.New("expected run count info to be available")
	}
	if rc != lc {
		return fmt.Errorf("run count unexpectedly increased over previous value (current: %v, prev: %v)", rc, lc)
	}

	rt, ok = pi.Runtime()
	if !ok {
		return errors.New("expected runtime info to be available")
	}
	if rt != lt {
		return fmt.Errorf("runtime unexpectedly increased over the previous value (current: %v, prev: %v)", rt, lt)
	}

	return nil
}
<|endoftext|>


<commit_before>package oak

import (
	"runtime"

	"github.com/oakmound/oak/dlog"
	pmouse "github.com/oakmound/oak/mouse"
	"golang.org/x/exp/shiny/gesture"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/size"
)

var (
	eFilter gesture.EventFilter
	eventFn func() interface{}
)

func inputLoop() {
	// Obtain input events in a manner dependant on config settings
	if conf.GestureSupport {
		eFilter = gesture.EventFilter{EventDeque: windowControl}
		eventFn = func() interface{} {
			return eFilter.Filter(eFilter.EventDeque.NextEvent())
		}
	} else {
		// Standard input
		eventFn = windowControl.NextEvent
	}
	schedCt := 0
	for {
		switch e := eventFn().(type) {
		// We only currently respond to death lifecycle events.
		case lifecycle.Event:
			if e.To == lifecycle.StageDead {
				quitCh <- true
				return
			}
			// ... this is where we would respond to window focus events

		// Send key events
		//
		// Key events have two varieties:
		// The "KeyDown" and "KeyUp" events, which trigger for all keys
		// and specific "KeyDown$key", etc events which trigger only for $key.
		// The specific key that is pressed is passed as the data interface for
		// the former events, but not for the latter.
		case key.Event:
			k := GetKeyBind(e.Code.String()[4:])
			if e.Direction == key.DirPress {
				//dlog.Verb("--------------------", e.Code.String()[4:], k)
				setDown(k)
				eb.Trigger("KeyDown", k)
				eb.Trigger("KeyDown"+k, nil)
			} else if e.Direction == key.DirRelease {
				setUp(k)
				eb.Trigger("KeyUp", k)
				eb.Trigger("KeyUp"+k, nil)
			}

		// Send mouse events
		//
		// Mouse events are parsed based on their button
		// and direction into an event name and then triggered:
		// 'MousePress', 'MouseRelease', 'MouseScrollDown', 'MouseScrollUp', and 'MouseDrag'
		//
		// The basic event name is meant for entities which
		// want to respond to the mouse event happening -anywhere-.
		//
		// For events which have mouse collision enabled, they'll receive
		// $eventName+"On" when the event occurs within their collision area.
		//
		// Mouse events all receive an x, y, and button string.
		case mouse.Event:
			button := pmouse.GetMouseButton(e.Button)
			var eventName string
			if e.Direction == mouse.DirPress {
				setDown(button)
				eventName = "MousePress"
			} else if e.Direction == mouse.DirRelease {
				setUp(button)
				eventName = "MouseRelease"
			} else if e.Button == -2 {
				eventName = "MouseScrollDown"
			} else if e.Button == -1 {
				eventName = "MouseScrollUp"
			} else {
				eventName = "MouseDrag"
			}
			// The event triggered for mouse events has the same scaling as the
			// render and collision space. I.e. if the viewport is at 0, the mouse's
			// position is exactly the same as the position of a visible entity
			// on screen. When not at zero, the offset will be exactly the viewport.
			// Todo: consider incorporating viewport into the event, see the
			// workaround needed in mouseDetails, and how mouse events might not
			// propagate to their expected position.
			mevent := pmouse.Event{
				X:      e.X / float32(windowRect.Max.X) * float32(ScreenWidth),
				Y:      e.Y / float32(windowRect.Max.Y) * float32(ScreenHeight),
				Button: button,
				Event:  eventName,
			}

			pmouse.LastMouseEvent = mevent

			eb.Trigger(eventName, mevent)
			pmouse.Propagate(eventName+"On", mevent)

		case gesture.Event:
			eventName := "Gesture" + e.Type.String()
			dlog.Verb(eventName)
			eb.Trigger(eventName, pmouse.FromShinyGesture(e))

		// There's something called a paint event that we don't respond to

		// Size events update what we scale the screen to
		case size.Event:
			//dlog.Verb("Got size event", e)
			ChangeWindow(e.WidthPx, e.HeightPx)
		case error:
			dlog.Error(e)
		}
		// This loop can be tight enough that the go scheduler never gets
		// a chance to take control from this thread. This is a hack that
		// solves that.
		schedCt++
		if schedCt > 1000 {
			schedCt = 0
			runtime.Gosched()
		}
	}
}
<commit_msg>Mouse now maps appropriately to aspect ratio scaled screens<commit_after>package oak

import (
	"fmt"
	"runtime"

	"github.com/oakmound/oak/dlog"
	pmouse "github.com/oakmound/oak/mouse"
	"golang.org/x/exp/shiny/gesture"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/mouse"
	"golang.org/x/mobile/event/size"
)

var (
	eFilter gesture.EventFilter
	eventFn func() interface{}
)

func inputLoop() {
	// Obtain input events in a manner dependant on config settings
	if conf.GestureSupport {
		eFilter = gesture.EventFilter{EventDeque: windowControl}
		eventFn = func() interface{} {
			return eFilter.Filter(eFilter.EventDeque.NextEvent())
		}
	} else {
		// Standard input
		eventFn = windowControl.NextEvent
	}
	schedCt := 0
	for {
		switch e := eventFn().(type) {
		// We only currently respond to death lifecycle events.
		case lifecycle.Event:
			if e.To == lifecycle.StageDead {
				quitCh <- true
				return
			}
			// ... this is where we would respond to window focus events

		// Send key events
		//
		// Key events have two varieties:
		// The "KeyDown" and "KeyUp" events, which trigger for all keys
		// and specific "KeyDown$key", etc events which trigger only for $key.
		// The specific key that is pressed is passed as the data interface for
		// the former events, but not for the latter.
		case key.Event:
			k := GetKeyBind(e.Code.String()[4:])
			if e.Direction == key.DirPress {
				//dlog.Verb("--------------------", e.Code.String()[4:], k)
				setDown(k)
				eb.Trigger("KeyDown", k)
				eb.Trigger("KeyDown"+k, nil)
			} else if e.Direction == key.DirRelease {
				setUp(k)
				eb.Trigger("KeyUp", k)
				eb.Trigger("KeyUp"+k, nil)
			}

		// Send mouse events
		//
		// Mouse events are parsed based on their button
		// and direction into an event name and then triggered:
		// 'MousePress', 'MouseRelease', 'MouseScrollDown', 'MouseScrollUp', and 'MouseDrag'
		//
		// The basic event name is meant for entities which
		// want to respond to the mouse event happening -anywhere-.
		//
		// For events which have mouse collision enabled, they'll receive
		// $eventName+"On" when the event occurs within their collision area.
		//
		// Mouse events all receive an x, y, and button string.
		case mouse.Event:
			button := pmouse.GetMouseButton(e.Button)
			var eventName string
			if e.Direction == mouse.DirPress {
				setDown(button)
				eventName = "MousePress"
			} else if e.Direction == mouse.DirRelease {
				setUp(button)
				eventName = "MouseRelease"
			} else if e.Button == -2 {
				eventName = "MouseScrollDown"
			} else if e.Button == -1 {
				eventName = "MouseScrollUp"
			} else {
				eventName = "MouseDrag"
			}
			// The event triggered for mouse events has the same scaling as the
			// render and collision space. I.e. if the viewport is at 0, the mouse's
			// position is exactly the same as the position of a visible entity
			// on screen. When not at zero, the offset will be exactly the viewport.
			// Todo: consider incorporating viewport into the event, see the
			// workaround needed in mouseDetails, and how mouse events might not
			// propagate to their expected position.
			mevent := pmouse.Event{
				X:      (((e.X - float32(windowRect.Min.X)) / float32(windowRect.Max.X-windowRect.Min.X)) * float32(ScreenWidth)),
				Y:      (((e.Y - float32(windowRect.Min.Y)) / float32(windowRect.Max.Y-windowRect.Min.Y)) * float32(ScreenHeight)),
				Button: button,
				Event:  eventName,
			}
			fmt.Println(e.X, e.Y, mevent.X, mevent.Y, windowRect, ScreenWidth, ScreenHeight)

			pmouse.LastMouseEvent = mevent

			eb.Trigger(eventName, mevent)
			pmouse.Propagate(eventName+"On", mevent)

		case gesture.Event:
			eventName := "Gesture" + e.Type.String()
			dlog.Verb(eventName)
			eb.Trigger(eventName, pmouse.FromShinyGesture(e))

		// There's something called a paint event that we don't respond to

		// Size events update what we scale the screen to
		case size.Event:
			//dlog.Verb("Got size event", e)
			ChangeWindow(e.WidthPx, e.HeightPx)
		case error:
			dlog.Error(e)
		}
		// This loop can be tight enough that the go scheduler never gets
		// a chance to take control from this thread. This is a hack that
		// solves that.
		schedCt++
		if schedCt > 1000 {
			schedCt = 0
			runtime.Gosched()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	raw "github.com/joekiller/gor/raw_socket_listener"
	"log"
	"net"
	"strings"
)

type RAWInput struct {
	data    chan []byte
	address string
}

func NewRAWInput(address string) (i *RAWInput) {
	i = new(RAWInput)
	i.data = make(chan []byte)
	i.address = address

	go i.listen(address)

	return
}

func (i *RAWInput) Read(data []byte) (int, error) {
	buf := <-i.data
	copy(data, buf)

	return len(buf), nil
}

func (i *RAWInput) listen(address string) {
	address = strings.Replace(address, "[::]", "127.0.0.1", -1)

	host, port, err := net.SplitHostPort(address)

	if err != nil {
		log.Fatal("input-raw: error while parsing address", err)
	}

	listener := raw.NewListener(host, port)

	for {
		// Receiving TCPMessage object
		m := listener.Receive()

		i.data <- m.Bytes()
	}
}

func (i *RAWInput) String() string {
	return "RAW Socket input: " + i.address
}
<commit_msg>update input raw import<commit_after>package main

import (
	raw "github.com/buger/gor/raw_socket_listener"
	"log"
	"net"
	"strings"
)

type RAWInput struct {
	data    chan []byte
	address string
}

func NewRAWInput(address string) (i *RAWInput) {
	i = new(RAWInput)
	i.data = make(chan []byte)
	i.address = address

	go i.listen(address)

	return
}

func (i *RAWInput) Read(data []byte) (int, error) {
	buf := <-i.data
	copy(data, buf)

	return len(buf), nil
}

func (i *RAWInput) listen(address string) {
	address = strings.Replace(address, "[::]", "127.0.0.1", -1)

	host, port, err := net.SplitHostPort(address)

	if err != nil {
		log.Fatal("input-raw: error while parsing address", err)
	}

	listener := raw.NewListener(host, port)

	for {
		// Receiving TCPMessage object
		m := listener.Receive()

		i.data <- m.Bytes()
	}
}

func (i *RAWInput) String() string {
	return "RAW Socket input: " + i.address
}
<|endoftext|>


<commit_before>package plugin

import (
	hclog "github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"google.golang.org/grpc"

	"github.com/hashicorp/terraform-plugin-go/tfprotov5"
	"github.com/hashicorp/terraform-plugin-go/tfprotov5/server"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
	// The constants below are the names of the plugins that can be dispensed
	// from the plugin server.
	ProviderPluginName = "provider"
)

// Handshake is the HandshakeConfig used to configure clients and servers.
var Handshake = plugin.HandshakeConfig{
	// The magic cookie values should NEVER be changed.
	MagicCookieKey:   "TF_PLUGIN_MAGIC_COOKIE",
	MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
}

type ProviderFunc func() *schema.Provider
type GRPCProviderFunc func() tfprotov5.ProviderServer

// ServeOpts are the configurations to serve a plugin.
type ServeOpts struct {
	ProviderFunc ProviderFunc

	// Wrapped versions of the above plugins will automatically shimmed and
	// added to the GRPC functions when possible.
	GRPCProviderFunc GRPCProviderFunc

	// Logger is the logger that go-plugin will use.
	Logger hclog.Logger

	// TestConfig should only be set when the provider is being tested; it
	// will opt out of go-plugin's lifecycle management and other features,
	// and will use the supplied configuration options to control the
	// plugin's lifecycle and communicate connection information. See the
	// go-plugin GoDoc for more information.
	TestConfig *plugin.ServeTestConfig
}

// Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin.
func Serve(opts *ServeOpts) {
	// since the plugins may not yet be aware of the new protocol, we
	// automatically wrap the plugins in the grpc shims.
	if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
		opts.GRPCProviderFunc = func() tfprotov5.ProviderServer {
			return schema.NewGRPCProviderServer(opts.ProviderFunc())
		}
	}

	provider := opts.GRPCProviderFunc()
	plugin.Serve(&plugin.ServeConfig{
		HandshakeConfig: Handshake,
		VersionedPlugins: map[int]plugin.PluginSet{
			5: {
				ProviderPluginName: &tf5server.GRPCProviderPlugin{
					GRPCProvider: func() tfprotov5.ProviderServer {
						return provider
					},
				},
			},
		},
		GRPCServer: func(opts []grpc.ServerOption) *grpc.Server {
			return grpc.NewServer(opts...)
		},
		Logger: opts.Logger,
		Test:   opts.TestConfig,
	})
}
<commit_msg>inject an hclog.Logger into the std log package<commit_after>package plugin

import (
	"log"

	hclog "github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"google.golang.org/grpc"

	"github.com/hashicorp/terraform-plugin-go/tfprotov5"
	tf5server "github.com/hashicorp/terraform-plugin-go/tfprotov5/server"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
	// The constants below are the names of the plugins that can be dispensed
	// from the plugin server.
	ProviderPluginName = "provider"
)

// Handshake is the HandshakeConfig used to configure clients and servers.
var Handshake = plugin.HandshakeConfig{
	// The magic cookie values should NEVER be changed.
	MagicCookieKey:   "TF_PLUGIN_MAGIC_COOKIE",
	MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
}

type ProviderFunc func() *schema.Provider
type GRPCProviderFunc func() tfprotov5.ProviderServer

// ServeOpts are the configurations to serve a plugin.
type ServeOpts struct {
	ProviderFunc ProviderFunc

	// Wrapped versions of the above plugins will automatically shimmed and
	// added to the GRPC functions when possible.
	GRPCProviderFunc GRPCProviderFunc

	// Logger is the logger that go-plugin will use.
	Logger hclog.Logger

	// TestConfig should only be set when the provider is being tested; it
	// will opt out of go-plugin's lifecycle management and other features,
	// and will use the supplied configuration options to control the
	// plugin's lifecycle and communicate connection information. See the
	// go-plugin GoDoc for more information.
	TestConfig *plugin.ServeTestConfig
}

// Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin.
func Serve(opts *ServeOpts) {
	// In order to allow go-plugin to correctly pass log-levels through to
	// terraform, we need to use an hclog.Logger with JSON output. We can
	// inject this into the std `log` package here, so existing providers will
	// make use of it automatically.
	logger := hclog.New(&hclog.LoggerOptions{
		// We send all output to terraform. Go-plugin will take the output and
		// pass it through another hclog.Logger on the client side where it can
		// be filtered.
		Level:      hclog.Trace,
		JSONFormat: true,
	})
	log.SetOutput(logger.StandardWriter(&hclog.StandardLoggerOptions{InferLevels: true}))

	// since the plugins may not yet be aware of the new protocol, we
	// automatically wrap the plugins in the grpc shims.
	if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
		opts.GRPCProviderFunc = func() tfprotov5.ProviderServer {
			return schema.NewGRPCProviderServer(opts.ProviderFunc())
		}
	}

	provider := opts.GRPCProviderFunc()
	plugin.Serve(&plugin.ServeConfig{
		HandshakeConfig: Handshake,
		VersionedPlugins: map[int]plugin.PluginSet{
			5: {
				ProviderPluginName: &tf5server.GRPCProviderPlugin{
					GRPCProvider: func() tfprotov5.ProviderServer {
						return provider
					},
				},
			},
		},
		GRPCServer: func(opts []grpc.ServerOption) *grpc.Server {
			return grpc.NewServer(opts...)
		},
		Logger: opts.Logger,
		Test:   opts.TestConfig,
	})
}
<|endoftext|>


<commit_before>package wiringpi

import (
	"os"
	"fmt"
)

var (
	board2pin = []int{
		-1,
		-1,
		-1,
		8,
		-1,
		9,
		-1,
		7,
		15,
		-1,
		16,
		0,
		1,
		2,
		-1,
		-1,
		4,
		-1,
		5,
		12,
		-1,
		13,
		6,
		14,
		10,
		-1,
		11,
	}
	gpio2pin = []int{
		8,
		9,
		-1,
		-1,
		7,
		-1,
		-1,
		11,
		10,
		13,
		12,
		14,
		-1,
		-1,
		15,
		16,
		-1,
		0,
		1,
		-1,
		-1,
		2,
		3,
		4,
		5,
		6,
		-1,
		-1,
		17,
		18,
		19,
		20,
	}

	gpioModes = []string  {"IN", "OUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3"}
)

const (
	PIN_GPIO_0  = 0
	PIN_GPIO_1  = 1
	PIN_GPIO_2  = 2
	PIN_GPIO_3  = 3
	PIN_GPIO_4  = 4
	PIN_GPIO_5  = 5
	PIN_GPIO_6  = 6
	PIN_GPIO_7  = 7
	PIN_SDA     = 8
	PIN_SCL     = 9
	PIN_CE0     = 10
	PIN_CE1     = 11
	PIN_MOSI    = 12
	PIN_MOSO    = 13
	PIN_SCLK    = 14
	PIN_TXD     = 15
	PIN_RXD     = 16
	PIN_GPIO_8  = 17
	PIN_GPIO_9  = 18
	PIN_GPIO_10 = 19
	PIN_GPIO_11 = 20

	MODE_IN  = 0
	MODE_OUT = 1
	MODE_ALT5 = 2
	MODE_ALT4 = 3
	MODE_ALT0 = 4
	MODE_ALT1 = 5
	MODE_ALT2 = 6
	MODE_ALT3 = 7
)

//use RPi.GPIO's BOARD numbering
func BoardToPin(pin int) int {
	if pin < 1 || pin >= len(board2pin) {
		panic(fmt.Sprintf("Invalid board pin number: %d", pin))
	}
	return board2pin[pin]
}

func GpioToPin(pin int) int {
	if pin < 0 || pin >= len(gpio2pin) {
		panic(fmt.Sprintf("Invalid bcm gpio number: %d", pin))
	}
	return gpio2pin[pin]
}

func PinToGpio(pin int) int {
	return internalPinToGpio(pin)
}

func Setup() error {
	return internalSetup()
}

func PinMode(pin int, mode int) {
	internalPinMode(pin, mode)
}

func DigitalWrite(pin int, mode int) {
	internalDigitalWrite(pin, mode)
}

func DigitalRead(pin int) int {
	return internalDigitalRead(pin)
}

func DigitalReadStr(pin int) string {
	if internalDigitalRead(pin) == LOW {
		return "LOW"
	}
	return "HIGH"
}

func GetMode(pin int) int {
	return internalGetMode(pin)
}

func GetModeStr(pin int) string {
	var mode = internalGetMode(pin)

	if mode > len(gpioModes) {
		return "INVALID"
	}

	return gpioModes[GetMode(pin)]
}

func Delay(ms int) {
	internalDelay(ms)
}

func DelayMicroseconds(microSec int) {
	internalDelayMicroseconds(microSec)
}

func WiringISR(pin int, mode int) chan int {
	return internalWiringISR(pin, mode)
}

func IsRaspberryPi() bool{
	if _, err := os.Stat("/opt/vc/include/bcm_host.h"); os.IsNotExist(err) {
		return false
	}

	return true
}<commit_msg>Little more cleanup.... make it tidy.<commit_after>package wiringpi

import (
	"os"
	"fmt"
)

var (
	board2pin = []int{
		-1,
		-1,
		-1,
		8,
		-1,
		9,
		-1,
		7,
		15,
		-1,
		16,
		0,
		1,
		2,
		-1,
		-1,
		4,
		-1,
		5,
		12,
		-1,
		13,
		6,
		14,
		10,
		-1,
		11,
	}
	gpio2pin = []int{
		8,
		9,
		-1,
		-1,
		7,
		-1,
		-1,
		11,
		10,
		13,
		12,
		14,
		-1,
		-1,
		15,
		16,
		-1,
		0,
		1,
		-1,
		-1,
		2,
		3,
		4,
		5,
		6,
		-1,
		-1,
		17,
		18,
		19,
		20,
	}

	gpioModes = []string  {"IN", "OUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3"}
)

//noinspection GoUnusedConst
const (
	PIN_GPIO_0  = 0
	PIN_GPIO_1  = 1
	PIN_GPIO_2  = 2
	PIN_GPIO_3  = 3
	PIN_GPIO_4  = 4
	PIN_GPIO_5  = 5
	PIN_GPIO_6  = 6
	PIN_GPIO_7  = 7
	PIN_SDA     = 8
	PIN_SCL     = 9
	PIN_CE0     = 10
	PIN_CE1     = 11
	PIN_MOSI    = 12
	PIN_MOSO    = 13
	PIN_SCLK    = 14
	PIN_TXD     = 15
	PIN_RXD     = 16
	PIN_GPIO_8  = 17
	PIN_GPIO_9  = 18
	PIN_GPIO_10 = 19
	PIN_GPIO_11 = 20

	MODE_IN  = 0
	MODE_OUT = 1
	MODE_ALT5 = 2
	MODE_ALT4 = 3
	MODE_ALT0 = 4
	MODE_ALT1 = 5
	MODE_ALT2 = 6
	MODE_ALT3 = 7
)

//use RPi.GPIO's BOARD numbering
//noinspection GoUnusedExportedFunction
func BoardToPin(pin int) int {
	if pin < 1 || pin >= len(board2pin) {
		panic(fmt.Sprintf("Invalid board pin number: %d", pin))
	}
	return board2pin[pin]
}

//noinspection GoUnusedExportedFunction
func GpioToPin(pin int) int {
	if pin < 0 || pin >= len(gpio2pin) {
		panic(fmt.Sprintf("Invalid bcm gpio number: %d", pin))
	}
	return gpio2pin[pin]
}

//noinspection GoUnusedExportedFunction
func PinToGpio(pin int) int {
	return internalPinToGpio(pin)
}

//noinspection GoUnusedExportedFunction
func Setup() error {
	return internalSetup()
}

//noinspection GoUnusedExportedFunction
func PinMode(pin int, mode int) {
	internalPinMode(pin, mode)
}

//noinspection GoUnusedExportedFunction
func DigitalWrite(pin int, mode int) {
	internalDigitalWrite(pin, mode)
}

//noinspection GoUnusedExportedFunction
func DigitalRead(pin int) int {
	return internalDigitalRead(pin)
}

//noinspection GoUnusedExportedFunction
func DigitalReadStr(pin int) string {
	if internalDigitalRead(pin) == LOW {
		return "LOW"
	}
	return "HIGH"
}

func GetMode(pin int) int {
	return internalGetMode(pin)
}

//noinspection GoUnusedExportedFunction
func GetModeStr(pin int) string {
	var mode = internalGetMode(pin)

	if mode > len(gpioModes) {
		return "INVALID"
	}

	return gpioModes[GetMode(pin)]
}

//noinspection GoUnusedExportedFunction
func Delay(ms int) {
	internalDelay(ms)
}

//noinspection GoUnusedExportedFunction
func DelayMicroseconds(microSec int) {
	internalDelayMicroseconds(microSec)
}

//noinspection GoUnusedExportedFunction
func WiringISR(pin int, mode int) chan int {
	return internalWiringISR(pin, mode)
}

func IsRaspberryPi() bool{
	if _, err := os.Stat("/opt/vc/include/bcm_host.h"); os.IsNotExist(err) {
		return false
	}

	return true
}<|endoftext|>


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

// Package intf implements mechanisms to access underlying interfaces in
// a manner that is agnostic to the underlying implementation. An implementation
// is included that uses netlink to write to a Linux kernl implementation.
// Additional implementations can be provided to allow writing to e.g. a
// gRPCwire implementation.
package intf

import (
	"fmt"
	"net"
)

// Interface represents information corresponding to a single interface on the
// underlying system.
type Interface struct {
	// Index is an integer index used to refer to the interface.
	Index int
	// Name is the name used to refer to the interface in the system.
	Name string
	// MAC is the MAC address of the interface.
	MAC net.HardwareAddr
}

// ARPEntry is a representation of an ARP entry on the underlying system.
type ARPEntry struct {
	// IP is the IP address of the neighbour.
	IP net.IP
	// Interface is the name of the interface on which the ARP entry was learnt.
	Interface string
	// MAC is the MAC address of the neighbour.
	MAC net.HardwareAddr
}

// ARPEvent is used to describe a particular event on the ARP table.
type ARPEvent int64

const (
	// ARPUnknown is used when the event is not an add or delete.
	ARPUnknown ARPEvent = iota
	// ARPAdd indicates that the ARP neighbour was added.
	ARPAdd
	// ARPDelete inidcates that the ARP neighbour was deleted.
	ARPDelete
)

// ARPUpdate is used to describe a change to the ARP table.
type ARPUpdate struct {
	// Type indicates whether the event was an add or delete.
	Type ARPEvent
	// Neigh is the neighbour that the change corresponds to
	Neigh ARPEntry
}

// NetworkAccessor is an interface implemented by the underlying system access
// interface. Through implementing the NetworkAccessor interface it is possible
// to use the functions within this package whilst using a different underlying
// implementation (e.g., netlink on Linux to access the kernel).
type NetworkAccessor interface {
	// Links returns a set of links that are present on the local system.
	Interfaces() ([]*Interface, error)
	// Link retrieves the link with the specified name.
	Interface(name string) (*Interface, error)
	// AddressList lists the IP addresses configured on a particular interface.
	InterfaceAddresses(name string) ([]*net.IPNet, error)
	// AddressAdd adds address ip to the interface name.
	AddInterfaceIP(name string, ip *net.IPNet) error
	// ARPList lists the set of ARP neighbours on the system.
	ARPList() ([]*ARPNeigh, error)
	// ARPSubscribe writes changes to the ARP table to the channel updates, and uses
	// done to indicate that the subscription is complete.
	ARPSubscribe(updates chan ARPUpdate, done chan struct{}) error
}

// unimplementedAccessor is an accessor interface that returns unimplemented
// for all underlying methods.
type unimplementedAccessor struct{}

// Interface returns unimplemented for the interface call.
func (u unimplementedAccessor) Interface(_ string) (*Interface, error) {
	return nil, fmt.Errorf("unimplemented")
}

// Interfaces returns unimplemented when asked to list interfaces.
func (u unimplementedAccessor) Interfaces() ([]*Interface, error) {
	return nil, fmt.Errorf("unimplemented")
}

// InterfaceAddresses returns unimplemented when asked for list IP addresses.
func (u unimplementedAccessor) InterfaceAddresses(_ string) ([]*net.IPNet, error) {
	return nil, fmt.Errorf("unimplemented")
}

// AddInterfaceIP returns unimplemented when asked to add an interface.
func (u unimplementedAccessor) AddInterfaceIP(_ string, _ *net.IPNet) error {
	return fmt.Errorf("unimplemented")
}

// ARPList returns unimplemented when asked to list ARP entries.
func (u unimplementedAccessor) ARPList() ([]*ARPNeigh, error) {
	return nil, fmt.Errorf("unimplemented")
}

// ARPSubscribe returns unimplemented when asked to subscribe to ARP changes.
func (u unimplementedAccessor) ARPSubscribe(_ chan ARPUpdate, _ chan struct{}) error {
	return fmt.Errorf("unimplemented")
}

// accessor is the implementation of the network accessor that should be used. It
// should be set by init() [which may be a platform-specific initiation].
var accessor NetworkAccessor

// ValidInterface determines whether the interface name is valid for the
// current system.
func ValidInterface(name string) bool {
	if accessor == nil {
		panic("accessor was nil, this package was not built on a supported system.")
	}
	if _, err := accessor.Interface(name); err != nil {
		return false
	}
	return true
}

// AddIP adds an IP address addr to the interface intf.
func AddIP(intf string, addr *net.IPNet) error {
	addrs, err := accessor.InterfaceAddresses(intf)
	if err != nil {
		return err
	}

	for _, a := range addrs {
		if a.IP.Equal(addr.IP) {
			return nil // already configured.
		}
	}

	// Configure the address.
	if err := accessor.AddInterfaceIP(intf, addr); err != nil {
		return fmt.Errorf("cannot add address, %v", err)
	}
	return nil
}
<commit_msg>Rename symbol.<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package intf implements mechanisms to access underlying interfaces in
// a manner that is agnostic to the underlying implementation. An implementation
// is included that uses netlink to write to a Linux kernl implementation.
// Additional implementations can be provided to allow writing to e.g. a
// gRPCwire implementation.
package intf

import (
	"fmt"
	"net"
)

// Interface represents information corresponding to a single interface on the
// underlying system.
type Interface struct {
	// Index is an integer index used to refer to the interface.
	Index int
	// Name is the name used to refer to the interface in the system.
	Name string
	// MAC is the MAC address of the interface.
	MAC net.HardwareAddr
}

// ARPEntry is a representation of an ARP entry on the underlying system.
type ARPEntry struct {
	// IP is the IP address of the neighbour.
	IP net.IP
	// Interface is the name of the interface on which the ARP entry was learnt.
	Interface string
	// MAC is the MAC address of the neighbour.
	MAC net.HardwareAddr
}

// ARPEvent is used to describe a particular event on the ARP table.
type ARPEvent int64

const (
	// ARPUnknown is used when the event is not an add or delete.
	ARPUnknown ARPEvent = iota
	// ARPAdd indicates that the ARP neighbour was added.
	ARPAdd
	// ARPDelete inidcates that the ARP neighbour was deleted.
	ARPDelete
)

// ARPUpdate is used to describe a change to the ARP table.
type ARPUpdate struct {
	// Type indicates whether the event was an add or delete.
	Type ARPEvent
	// Neigh is the neighbour that the change corresponds to
	Neigh ARPEntry
}

// NetworkAccessor is an interface implemented by the underlying system access
// interface. Through implementing the NetworkAccessor interface it is possible
// to use the functions within this package whilst using a different underlying
// implementation (e.g., netlink on Linux to access the kernel).
type NetworkAccessor interface {
	// Links returns a set of links that are present on the local system.
	Interfaces() ([]*Interface, error)
	// Link retrieves the link with the specified name.
	Interface(name string) (*Interface, error)
	// AddressList lists the IP addresses configured on a particular interface.
	InterfaceAddresses(name string) ([]*net.IPNet, error)
	// AddressAdd adds address ip to the interface name.
	AddInterfaceIP(name string, ip *net.IPNet) error
	// ARPList lists the set of ARP neighbours on the system.
	ARPList() ([]*ARPEntry, error)
	// ARPSubscribe writes changes to the ARP table to the channel updates, and uses
	// done to indicate that the subscription is complete.
	ARPSubscribe(updates chan ARPUpdate, done chan struct{}) error
}

// unimplementedAccessor is an accessor interface that returns unimplemented
// for all underlying methods.
type unimplementedAccessor struct{}

// Interface returns unimplemented for the interface call.
func (u unimplementedAccessor) Interface(_ string) (*Interface, error) {
	return nil, fmt.Errorf("unimplemented")
}

// Interfaces returns unimplemented when asked to list interfaces.
func (u unimplementedAccessor) Interfaces() ([]*Interface, error) {
	return nil, fmt.Errorf("unimplemented")
}

// InterfaceAddresses returns unimplemented when asked for list IP addresses.
func (u unimplementedAccessor) InterfaceAddresses(_ string) ([]*net.IPNet, error) {
	return nil, fmt.Errorf("unimplemented")
}

// AddInterfaceIP returns unimplemented when asked to add an interface.
func (u unimplementedAccessor) AddInterfaceIP(_ string, _ *net.IPNet) error {
	return fmt.Errorf("unimplemented")
}

// ARPList returns unimplemented when asked to list ARP entries.
func (u unimplementedAccessor) ARPList() ([]*ARPEntry, error) {
	return nil, fmt.Errorf("unimplemented")
}

// ARPSubscribe returns unimplemented when asked to subscribe to ARP changes.
func (u unimplementedAccessor) ARPSubscribe(_ chan ARPUpdate, _ chan struct{}) error {
	return fmt.Errorf("unimplemented")
}

// accessor is the implementation of the network accessor that should be used. It
// should be set by init() [which may be a platform-specific initiation].
var accessor NetworkAccessor

// ValidInterface determines whether the interface name is valid for the
// current system.
func ValidInterface(name string) bool {
	if accessor == nil {
		panic("accessor was nil, this package was not built on a supported system.")
	}
	if _, err := accessor.Interface(name); err != nil {
		return false
	}
	return true
}

// AddIP adds an IP address addr to the interface intf.
func AddIP(intf string, addr *net.IPNet) error {
	addrs, err := accessor.InterfaceAddresses(intf)
	if err != nil {
		return err
	}

	for _, a := range addrs {
		if a.IP.Equal(addr.IP) {
			return nil // already configured.
		}
	}

	// Configure the address.
	if err := accessor.AddInterfaceIP(intf, addr); err != nil {
		return fmt.Errorf("cannot add address, %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

/*
  #cgo CFLAGS: -I../../headers
  #cgo LDFLAGS: -ljson-c

  #include <stdlib.h>
  #include "kuzzlesdk.h"
  #include "sdk_wrappers_internal.h"
*/
import "C"
import (
	"github.com/kuzzleio/sdk-go/kuzzle"
	"strconv"
	"time"
	"unsafe"
)

//export kuzzle_list_collections
func kuzzle_list_collections(k *C.kuzzle, index *C.char, options *C.query_options) *C.collection_entry_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).ListCollections(
		C.GoString(index),
		SetQueryOptions(options))

	return goToCCollectionListResult(res, err)
}

//export kuzzle_list_indexes
func kuzzle_list_indexes(k *C.kuzzle, options *C.query_options) *C.string_array_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).ListIndexes(SetQueryOptions(options))

	return goToCStringArrayResult(res, err)
}

//export kuzzle_create_index
func kuzzle_create_index(k *C.kuzzle, index *C.char, options *C.query_options) *C.bool_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).CreateIndex(
		C.GoString(index),
		SetQueryOptions(options))

	return goToCBoolResult(res, err)
}

//export kuzzle_refresh_index
func kuzzle_refresh_index(k *C.kuzzle, index *C.char, options *C.query_options) *C.shards_result {
	result := (*C.shards_result)(C.calloc(1, C.sizeof_shards_result))
	opts := SetQueryOptions(options)

	shards, err := (*kuzzle.Kuzzle)(k.instance).RefreshIndex(C.GoString(index), opts)
	if err != nil {
		Set_shards_result_error(result, err)
		return result
	}

	result.result = goToCShards(shards)

	return result
}

//export kuzzle_set_auto_refresh
func kuzzle_set_auto_refresh(k *C.kuzzle, index *C.char, auto_refresh C.bool, options *C.query_options) *C.bool_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).SetAutoRefresh(
		C.GoString(index),
		bool(auto_refresh),
		SetQueryOptions(options))

	return goToCBoolResult(res, err)
}

//export kuzzle_get_auto_refresh
func kuzzle_get_auto_refresh(k *C.kuzzle, index *C.char, options *C.query_options) *C.bool_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).GetAutoRefresh(
		C.GoString(index),
		SetQueryOptions(options))

	return goToCBoolResult(res, err)
}

//export kuzzle_get_server_info
func kuzzle_get_server_info(k *C.kuzzle, options *C.query_options) *C.json_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).GetServerInfo(SetQueryOptions(options))

	return goToCJsonResult(res, err)
}

//export kuzzle_get_all_statistics
func kuzzle_get_all_statistics(k *C.kuzzle, options *C.query_options) *C.all_statistics_result {
	result := (*C.all_statistics_result)(C.calloc(1, C.sizeof_statistics_result))
	opts := SetQueryOptions(options)

	stats, err := (*kuzzle.Kuzzle)(k.instance).GetAllStatistics(opts)

	if err != nil {
		Set_all_statistics_error(result, err)
		return result
	}

	result.result = (*C.statistics)(C.calloc(C.size_t(len(stats)), C.sizeof_statistics))
	result.result_length = C.size_t(len(stats))
	statistics := (*[1<<30 - 1]C.statistics)(unsafe.Pointer(result.result))[:len(stats):len(stats)]

	for i, stat := range stats {
		fillStatistics(stat, &statistics[i])
	}

	return result
}

//export kuzzle_get_statistics
func kuzzle_get_statistics(k *C.kuzzle, start_time C.time_t, stop_time C.time_t, options *C.query_options) *C.statistics_result {
	result := (*C.statistics_result)(C.calloc(1, C.sizeof_statistics_result))
	opts := SetQueryOptions(options)

	t, _ := strconv.ParseInt(C.GoString(C.ctime(&start_time)), 10, 64)
	start := time.Unix(t, 0)
	t, _ = strconv.ParseInt(C.GoString(C.ctime(&stop_time)), 10, 64)
	stop := time.Unix(t, 0)

	res, err := (*kuzzle.Kuzzle)(k.instance).GetStatistics(&start, &stop, opts)

	if err != nil {
		Set_statistics_error(result, err)
		return result
	}

	fillStatistics(res, result.result)

	return result
}

//export kuzzle_now
func kuzzle_now(k *C.kuzzle, options *C.query_options) *C.date_result {
	time, err := (*kuzzle.Kuzzle)(k.instance).Now(SetQueryOptions(options))

	return goToCDateResult(time, err)
}
<commit_msg>Delete old function call in root_api CGO<commit_after>package main

/*
  #cgo CFLAGS: -I../../headers
  #cgo LDFLAGS: -ljson-c

  #include <stdlib.h>
  #include "kuzzlesdk.h"
  #include "sdk_wrappers_internal.h"
*/
import "C"
import (
	"strconv"
	"time"
	"unsafe"

	"github.com/kuzzleio/sdk-go/kuzzle"
)

//export kuzzle_list_collections
func kuzzle_list_collections(k *C.kuzzle, index *C.char, options *C.query_options) *C.collection_entry_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).ListCollections(
		C.GoString(index),
		SetQueryOptions(options))

	return goToCCollectionListResult(res, err)
}

//export kuzzle_list_indexes
func kuzzle_list_indexes(k *C.kuzzle, options *C.query_options) *C.string_array_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).ListIndexes(SetQueryOptions(options))

	return goToCStringArrayResult(res, err)
}

//export kuzzle_get_auto_refresh
func kuzzle_get_auto_refresh(k *C.kuzzle, index *C.char, options *C.query_options) *C.bool_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).GetAutoRefresh(
		C.GoString(index),
		SetQueryOptions(options))

	return goToCBoolResult(res, err)
}

//export kuzzle_get_server_info
func kuzzle_get_server_info(k *C.kuzzle, options *C.query_options) *C.json_result {
	res, err := (*kuzzle.Kuzzle)(k.instance).GetServerInfo(SetQueryOptions(options))

	return goToCJsonResult(res, err)
}

//export kuzzle_get_all_statistics
func kuzzle_get_all_statistics(k *C.kuzzle, options *C.query_options) *C.all_statistics_result {
	result := (*C.all_statistics_result)(C.calloc(1, C.sizeof_statistics_result))
	opts := SetQueryOptions(options)

	stats, err := (*kuzzle.Kuzzle)(k.instance).GetAllStatistics(opts)

	if err != nil {
		Set_all_statistics_error(result, err)
		return result
	}

	result.result = (*C.statistics)(C.calloc(C.size_t(len(stats)), C.sizeof_statistics))
	result.result_length = C.size_t(len(stats))
	statistics := (*[1<<30 - 1]C.statistics)(unsafe.Pointer(result.result))[:len(stats):len(stats)]

	for i, stat := range stats {
		fillStatistics(stat, &statistics[i])
	}

	return result
}

//export kuzzle_get_statistics
func kuzzle_get_statistics(k *C.kuzzle, start_time C.time_t, stop_time C.time_t, options *C.query_options) *C.statistics_result {
	result := (*C.statistics_result)(C.calloc(1, C.sizeof_statistics_result))
	opts := SetQueryOptions(options)

	t, _ := strconv.ParseInt(C.GoString(C.ctime(&start_time)), 10, 64)
	start := time.Unix(t, 0)
	t, _ = strconv.ParseInt(C.GoString(C.ctime(&stop_time)), 10, 64)
	stop := time.Unix(t, 0)

	res, err := (*kuzzle.Kuzzle)(k.instance).GetStatistics(&start, &stop, opts)

	if err != nil {
		Set_statistics_error(result, err)
		return result
	}

	fillStatistics(res, result.result)

	return result
}

//export kuzzle_now
func kuzzle_now(k *C.kuzzle, options *C.query_options) *C.date_result {
	time, err := (*kuzzle.Kuzzle)(k.instance).Now(SetQueryOptions(options))

	return goToCDateResult(time, err)
}
<|endoftext|>


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

package steven

import (
	"fmt"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/ui"
	"github.com/thinkofdeath/steven/ui/scene"
)

var (
	InvPlayer = playerInventory{}

	invScreen = &inventoryScreen{}
)

type InventoryType interface {
	Draw(scene *scene.Type, inv *Inventory)
}

type Inventory struct {
	Type InventoryType
	ID   int

	Items []*ItemStack

	scene *scene.Type
}

func NewInventory(ty InventoryType, id, size int) *Inventory {
	return &Inventory{
		Type:  ty,
		ID:    id,
		Items: make([]*ItemStack, size),
		scene: scene.New(true),
	}
}

func (inv *Inventory) Update() {
	was := inv.scene.IsVisible()
	inv.scene.Hide()
	inv.scene = scene.New(was)
	inv.Type.Draw(inv.scene, inv)
}

func (inv *Inventory) Close() {
	inv.scene.Hide()
	Client.network.Write(&protocol.CloseWindow{ID: byte(inv.ID)})
}

func (inv *Inventory) Hide() {
	inv.scene.Hide()
}

func (inv *Inventory) Show() {
	inv.scene.Show()
}

func openInventory(inv *Inventory) {
	Client.activeInventory = inv
	Client.activeInventory.Show()
	Client.activeInventory.Update()
	setScreen(invScreen)
}

func closeInventory() {
	if inv := Client.activeInventory; inv != nil {
		inv.Close()
		Client.activeInventory = nil
		setScreen(nil)
	}
	Client.playerInventory.Update()
}

type inventoryScreen struct {
	prev glfw.KeyCallback

	activeSlot int
	inWindow   bool

	cursorItem     *ItemStack
	cursorIcon     *ui.Container
	lastMX, lastMY float64
	scene          *scene.Type
}

func (i *inventoryScreen) init() {
	i.prev = window.SetKeyCallback(i.onKey)
	i.activeSlot = -1
	i.cursorItem = nil
	if i.scene != nil {
		i.scene.Hide()
	}
	i.scene = scene.New(true)
}
func (i *inventoryScreen) tick(delta float64) {}

func (i *inventoryScreen) hover(x, y float64, w, h int) {
	i.lastMX, i.lastMY = x, y
	if i.cursorIcon != nil {
		i.cursorIcon.SetX(x - 16)
		i.cursorIcon.SetY(y - 16)
	}
	ui.Hover(x, y, w, h)
}
func (i *inventoryScreen) click(down bool, x, y float64, w, h int) {
	if down {
		if i.activeSlot != -1 {
			item := Client.activeInventory.Items[i.activeSlot]
			Client.activeInventory.Items[i.activeSlot] = i.cursorItem
			Client.network.Write(&protocol.ClickWindow{
				ID:           byte(Client.activeInventory.ID),
				Slot:         int16(i.activeSlot),
				Button:       0,
				Mode:         0,
				ActionNumber: 42,
				ClickedItem:  ItemStackToProtocol(item),
			})
			i.setCursor(item)
		} else if !i.inWindow {
			Client.network.Write(&protocol.ClickWindow{
				ID:           byte(Client.activeInventory.ID),
				Slot:         int16(-999),
				Button:       0,
				Mode:         0,
				ActionNumber: 42,
				ClickedItem:  ItemStackToProtocol(nil),
			})
			i.setCursor(nil)
		}
		return
	}
	ui.Click(x, y, w, h)
}

func (i *inventoryScreen) setCursor(item *ItemStack) {
	i.scene.Hide()
	i.scene = scene.New(true)
	i.cursorItem = item
	i.cursorIcon = nil
	if item != nil {
		i.cursorIcon = createItemIcon(item, i.scene, i.lastMX-16, i.lastMY-16)
		i.cursorIcon.SetLayer(100)
	}
	Client.activeInventory.Update()
}

func (i *inventoryScreen) onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action != glfw.Release {
		return
	}
	if key == glfw.KeyE || key == glfw.KeyEscape {
		closeInventory()
	}
}

func (i *inventoryScreen) remove() {
	window.SetKeyCallback(i.prev)
	i.scene.Hide()
}

// Player

type playerInventory struct {
}

const invPlayerHotbarOffset = 36

func (playerInventory) Draw(s *scene.Type, inv *Inventory) {
	full := Client.activeInventory == Client.playerInventory

	if !full {
		// Slots 36-44 are the hotbar
		Client.hotbarScene.Hide()
		Client.hotbarScene = scene.New(true)
		hs := Client.hotbarScene
		for i := invPlayerHotbarOffset; i < invPlayerHotbarOffset+9; i++ {
			if inv.Items[i] == nil {
				continue
			}
			item := inv.Items[i]
			container := createItemIcon(item, hs, 6+40*float64(i-36), 6).
				Attach(ui.Top, ui.Left)
			container.AttachTo(Client.hotbar)
		}
		return
	}

	background := ui.NewImage(
		render.GetTexture("gui/container/inventory"),
		0, 0, 176*2, 166*2,
		0, 0, 176/256.0, 166/256.0,
		255, 255, 255,
	)
	s.AddDrawable(background.Attach(ui.Middle, ui.Center))

	check := ui.NewContainer(0, 0, 176*2, 166*2)
	s.AddDrawable(check.Attach(ui.Middle, ui.Center))
	check.HoverFunc = func(over bool) {
		invScreen.inWindow = over
	}

	var slotPositions = [45][2]float64{
		0: {144, 36}, // Craft-out
		// Craft-In
		1: {88, 26},
		2: {106, 26},
		3: {88, 44},
		4: {106, 44},
		// Armor
		5: {8, 8},
		6: {8, 26},
		7: {8, 44},
		8: {8, 62},
	}
	for i := 9; i <= 35; i++ {
		x := i % 9
		y := (i / 9) - 1
		slotPositions[i] = [2]float64{
			8 + 18*float64(x), 84 + 18*float64(y),
		}
	}
	for i := 0; i < 9; i++ {
		slotPositions[i+36] = [2]float64{
			8 + 18*float64(i), 142,
		}
	}

	solid := render.GetTexture("solid")

	for i, pos := range slotPositions {
		i := i
		ctn := ui.NewContainer(pos[0]*2, pos[1]*2, 32, 32)
		ctn.AttachTo(background)
		s.AddDrawable(ctn)

		item := inv.Items[i]
		if item != nil {
			container := createItemIcon(item, s, pos[0]*2, pos[1]*2)
			container.AttachTo(background)
		} else if i >= 5 && i <= 8 {
			tex := render.GetTexture([]string{
				"items/empty_armor_slot_helmet",
				"items/empty_armor_slot_chestplate",
				"items/empty_armor_slot_leggings",
				"items/empty_armor_slot_boots",
			}[i-5])
			img := ui.NewImage(tex, pos[0]*2, pos[1]*2, 32, 32, 0, 0, 1, 1, 255, 255, 255)
			img.AttachTo(background)
			s.AddDrawable(img)
		}

		highlight := ui.NewImage(solid, pos[0]*2, pos[1]*2, 32, 32, 0, 0, 1, 1, 255, 255, 255)
		highlight.SetA(0)
		highlight.AttachTo(background)
		highlight.SetLayer(25)
		s.AddDrawable(highlight)

		ctn.HoverFunc = func(over bool) {
			if over {
				highlight.SetA(100)
				invScreen.activeSlot = i
			} else {
				highlight.SetA(0)
				if i == invScreen.activeSlot {
					invScreen.activeSlot = -1
				}
			}
		}
	}
}

func createItemIcon(item *ItemStack, scene *scene.Type, x, y float64) *ui.Container {
	mdl := getModel(item.Type.Name())

	container := ui.NewContainer(x, y, 32, 32)
	if mdl == nil || mdl.builtIn == builtInGenerated {
		var tex render.TextureInfo
		if mdl == nil {
			tex = render.GetTexture("missing_texture")

			img := ui.NewImage(tex, 0, 0, 32, 32, 0, 0, 1, 1, 255, 255, 255)
			img.AttachTo(container)
			scene.AddDrawable(img.Attach(ui.Top, ui.Left))
		} else {
			for i := 0; i < 9; i++ {
				v := fmt.Sprintf("layer%d", i)
				if _, ok := mdl.textureVars[v]; !ok {
					break
				}
				tex = mdl.lookupTexture("#" + v)

				img := ui.NewImage(tex, 0, 0, 32, 32, 0, 0, 1, 1, 255, 255, 255)
				img.AttachTo(container)
				scene.AddDrawable(img.Attach(ui.Top, ui.Left))
			}
		}
	} else if mdl.builtIn == builtInFalse {
		var blk Block
		if bt, ok := item.Type.(*blockItem); ok {
			blk = bt.block
		}
		u := modelToUI(mdl, blk)
		u.AttachTo(container)
		scene.AddDrawable(u.Attach(ui.Top, ui.Center))
	}
	if dam, ok := item.Type.(ItemDamagable); ok && dam.Damage() > 0 {
		val := 1.0 - (float64(dam.Damage()) / float64(dam.MaxDamage()))
		barShadow := ui.NewImage(render.GetTexture("solid"), 0, 2, 28, 4, 0, 0, 1, 1,
			0, 0, 0,
		)
		barShadow.SetLayer(2)
		barShadow.AttachTo(container)
		scene.AddDrawable(barShadow.Attach(ui.Bottom, ui.Center))
		bar := ui.NewImage(render.GetTexture("solid"), 0, 0, 28*val, 2, 0, 0, 1, 1,
			int(255*(1.0-val)), int(255*val), 0,
		)
		bar.SetLayer(2)
		bar.AttachTo(barShadow)
		scene.AddDrawable(bar.Attach(ui.Top, ui.Left))
	}
	if item.Count > 1 {
		txt := ui.NewText(fmt.Sprint(item.Count), -2, -2, 255, 255, 255).
			Attach(ui.Bottom, ui.Right)
		txt.AttachTo(container)
		txt.SetLayer(2)
		scene.AddDrawable(txt)
	}
	return container
}
<commit_msg>steven: revert a change made by mistake<commit_after>// Copyright 2015 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package steven

import (
	"fmt"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/ui"
	"github.com/thinkofdeath/steven/ui/scene"
)

var (
	InvPlayer = playerInventory{}

	invScreen = &inventoryScreen{}
)

type InventoryType interface {
	Draw(scene *scene.Type, inv *Inventory)
}

type Inventory struct {
	Type InventoryType
	ID   int

	Items []*ItemStack

	scene *scene.Type
}

func NewInventory(ty InventoryType, id, size int) *Inventory {
	return &Inventory{
		Type:  ty,
		ID:    id,
		Items: make([]*ItemStack, size),
		scene: scene.New(true),
	}
}

func (inv *Inventory) Update() {
	was := inv.scene.IsVisible()
	inv.scene.Hide()
	inv.scene = scene.New(was)
	inv.Type.Draw(inv.scene, inv)
}

func (inv *Inventory) Close() {
	inv.scene.Hide()
	Client.network.Write(&protocol.CloseWindow{ID: byte(inv.ID)})
}

func (inv *Inventory) Hide() {
	inv.scene.Hide()
}

func (inv *Inventory) Show() {
	inv.scene.Show()
}

func openInventory(inv *Inventory) {
	Client.activeInventory = inv
	Client.activeInventory.Show()
	Client.activeInventory.Update()
	setScreen(invScreen)
}

func closeInventory() {
	if inv := Client.activeInventory; inv != nil {
		inv.Close()
		Client.activeInventory = nil
		setScreen(nil)
	}
	Client.playerInventory.Update()
}

type inventoryScreen struct {
	prev glfw.KeyCallback

	activeSlot int
	inWindow   bool

	cursorItem     *ItemStack
	cursorIcon     *ui.Container
	lastMX, lastMY float64
	scene          *scene.Type
}

func (i *inventoryScreen) init() {
	i.prev = window.SetKeyCallback(i.onKey)
	i.activeSlot = -1
	i.cursorItem = nil
	if i.scene != nil {
		i.scene.Hide()
	}
	i.scene = scene.New(true)
}
func (i *inventoryScreen) tick(delta float64) {}

func (i *inventoryScreen) hover(x, y float64, w, h int) {
	i.lastMX, i.lastMY = x, y
	if i.cursorIcon != nil {
		i.cursorIcon.SetX(x - 16)
		i.cursorIcon.SetY(y - 16)
	}
	ui.Hover(x, y, w, h)
}
func (i *inventoryScreen) click(down bool, x, y float64, w, h int) {
	if down {
		if i.activeSlot != -1 {
			item := Client.activeInventory.Items[i.activeSlot]
			Client.activeInventory.Items[i.activeSlot] = i.cursorItem
			Client.network.Write(&protocol.ClickWindow{
				ID:           byte(Client.activeInventory.ID),
				Slot:         int16(i.activeSlot),
				Button:       0,
				Mode:         0,
				ActionNumber: 42,
				ClickedItem:  ItemStackToProtocol(item),
			})
			i.setCursor(item)
		} else if !i.inWindow {
			Client.network.Write(&protocol.ClickWindow{
				ID:           byte(Client.activeInventory.ID),
				Slot:         int16(-999),
				Button:       0,
				Mode:         0,
				ActionNumber: 42,
				ClickedItem:  ItemStackToProtocol(nil),
			})
			i.setCursor(nil)
		}
		return
	}
	ui.Click(x, y, w, h)
}

func (i *inventoryScreen) setCursor(item *ItemStack) {
	i.scene.Hide()
	i.scene = scene.New(true)
	i.cursorItem = item
	i.cursorIcon = nil
	if item != nil {
		i.cursorIcon = createItemIcon(item, i.scene, i.lastMX-16, i.lastMY-16)
		i.cursorIcon.SetLayer(100)
	}
	Client.activeInventory.Update()
}

func (i *inventoryScreen) onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action != glfw.Release {
		return
	}
	if key == glfw.KeyE || key == glfw.KeyEscape {
		closeInventory()
	}
}

func (i *inventoryScreen) remove() {
	window.SetKeyCallback(i.prev)
	i.scene.Hide()
}

// Player

type playerInventory struct {
}

const invPlayerHotbarOffset = 36

func (playerInventory) Draw(s *scene.Type, inv *Inventory) {
	full := Client.activeInventory == Client.playerInventory

	if !full {
		// Slots 36-44 are the hotbar
		Client.hotbarScene.Hide()
		Client.hotbarScene = scene.New(true)
		hs := Client.hotbarScene
		for i := invPlayerHotbarOffset; i < invPlayerHotbarOffset+9; i++ {
			if inv.Items[i] == nil {
				continue
			}
			item := inv.Items[i]
			container := createItemIcon(item, hs, 6+40*float64(i-36), 6).
				Attach(ui.Top, ui.Left)
			container.AttachTo(Client.hotbar)
		}
		return
	}

	background := ui.NewImage(
		render.GetTexture("gui/container/inventory"),
		0, 0, 176*2, 166*2,
		0, 0, 176/256.0, 166/256.0,
		255, 255, 255,
	)
	s.AddDrawable(background.Attach(ui.Middle, ui.Center))

	check := ui.NewContainer(0, 0, 176*2, 166*2)
	s.AddDrawable(check.Attach(ui.Middle, ui.Center))
	check.HoverFunc = func(over bool) {
		invScreen.inWindow = over
	}

	var slotPositions = [45][2]float64{
		0: {144, 36}, // Craft-out
		// Craft-In
		1: {88, 26},
		2: {106, 26},
		3: {88, 44},
		4: {106, 44},
		// Armor
		5: {8, 8},
		6: {8, 26},
		7: {8, 44},
		8: {8, 62},
	}
	for i := 9; i <= 35; i++ {
		x := i % 9
		y := (i / 9) - 1
		slotPositions[i] = [2]float64{
			8 + 18*float64(x), 84 + 18*float64(y),
		}
	}
	for i := 0; i < 9; i++ {
		slotPositions[i+36] = [2]float64{
			8 + 18*float64(i), 142,
		}
	}

	solid := render.GetTexture("solid")

	for i, pos := range slotPositions {
		i := i
		ctn := ui.NewContainer(pos[0]*2, pos[1]*2, 32, 32)
		ctn.AttachTo(background)
		s.AddDrawable(ctn)

		item := inv.Items[i]
		if item != nil {
			container := createItemIcon(item, s, pos[0]*2, pos[1]*2)
			container.AttachTo(background)
		} else if i >= 5 && i <= 8 {
			tex := render.GetTexture([]string{
				"items/empty_armor_slot_helmet",
				"items/empty_armor_slot_chestplate",
				"items/empty_armor_slot_leggings",
				"items/empty_armor_slot_boots",
			}[i-5])
			img := ui.NewImage(tex, pos[0]*2, pos[1]*2, 32, 32, 0, 0, 1, 1, 255, 255, 255)
			img.AttachTo(background)
			s.AddDrawable(img)
		}

		highlight := ui.NewImage(solid, pos[0]*2, pos[1]*2, 32, 32, 0, 0, 1, 1, 255, 255, 255)
		highlight.SetA(0)
		highlight.AttachTo(background)
		highlight.SetLayer(25)
		s.AddDrawable(highlight)

		ctn.HoverFunc = func(over bool) {
			if over {
				highlight.SetA(100)
				invScreen.activeSlot = i
			} else {
				highlight.SetA(0)
				if i == invScreen.activeSlot {
					invScreen.activeSlot = -1
				}
			}
		}
	}
}

func createItemIcon(item *ItemStack, scene *scene.Type, x, y float64) *ui.Container {
	mdl := getModel(item.Type.Name())

	container := ui.NewContainer(x, y, 32, 32)
	if mdl == nil || mdl.builtIn == builtInGenerated {
		var tex render.TextureInfo
		if mdl == nil {
			tex = render.GetTexture("missing_texture")

			img := ui.NewImage(tex, 0, 0, 32, 32, 0, 0, 1, 1, 255, 255, 255)
			img.AttachTo(container)
			scene.AddDrawable(img.Attach(ui.Top, ui.Left))
		} else {
			for i := 0; i < 9; i++ {
				v := fmt.Sprintf("layer%d", i)
				if _, ok := mdl.textureVars[v]; !ok {
					break
				}
				tex = mdl.lookupTexture("#" + v)

				img := ui.NewImage(tex, 0, 0, 32, 32, 0, 0, 1, 1, 255, 255, 255)
				img.AttachTo(container)
				scene.AddDrawable(img.Attach(ui.Top, ui.Left))
			}
		}
	} else if mdl.builtIn == builtInFalse {
		var blk Block
		if bt, ok := item.Type.(*blockItem); ok {
			blk = bt.block
		}
		u := modelToUI(mdl, blk)
		u.AttachTo(container)
		scene.AddDrawable(u.Attach(ui.Top, ui.Left))
	}
	if dam, ok := item.Type.(ItemDamagable); ok && dam.Damage() > 0 {
		val := 1.0 - (float64(dam.Damage()) / float64(dam.MaxDamage()))
		barShadow := ui.NewImage(render.GetTexture("solid"), 0, 2, 28, 4, 0, 0, 1, 1,
			0, 0, 0,
		)
		barShadow.SetLayer(2)
		barShadow.AttachTo(container)
		scene.AddDrawable(barShadow.Attach(ui.Bottom, ui.Center))
		bar := ui.NewImage(render.GetTexture("solid"), 0, 0, 28*val, 2, 0, 0, 1, 1,
			int(255*(1.0-val)), int(255*val), 0,
		)
		bar.SetLayer(2)
		bar.AttachTo(barShadow)
		scene.AddDrawable(bar.Attach(ui.Top, ui.Left))
	}
	if item.Count > 1 {
		txt := ui.NewText(fmt.Sprint(item.Count), -2, -2, 255, 255, 255).
			Attach(ui.Bottom, ui.Right)
		txt.AttachTo(container)
		txt.SetLayer(2)
		scene.AddDrawable(txt)
	}
	return container
}
<|endoftext|>


<commit_before>package localkube

import (
	"fmt"
	"net"
	"os"

	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
)

const (
	APIServerName = "apiserver"
	APIServerHost = "0.0.0.0"
	APIServerPort = 8080
)

var (
	APIServerURL   string
	ServiceIPRange = "10.1.30.0/24"
)

func init() {
	APIServerURL = fmt.Sprintf("http://%s:%d", APIServerHost, APIServerPort)
	if ipRange := os.Getenv("SERVICE_IP_RANGE"); len(ipRange) != 0 {
		ServiceIPRange = ipRange
	}
}

func NewAPIServer() Server {
	return SimpleServer{
		ComponentName: APIServerName,
		StartupFn:     StartAPIServer,
	}.NoShutdown()
}

func StartAPIServer() {
	config := options.NewAPIServer()

	// use host/port from vars
	config.InsecureBindAddress = net.ParseIP(APIServerHost)
	config.InsecurePort = APIServerPort

	// use localkube etcd
	config.EtcdConfig = etcdstorage.EtcdConfig{
		ServerList: EtcdClientURLs,
	}

	// set Service IP range
	_, ipnet, err := net.ParseCIDR(ServiceIPRange)
	if err != nil {
		panic(err)
	}
	config.ServiceClusterIPRange = *ipnet

	// defaults from apiserver command
	config.EnableProfiling = true
	config.EnableWatchCache = true
	config.MinRequestTimeout = 1800

	// start API server in it's own goroutine
	go apiserver.Run(config)
}
<commit_msg>gofmt<commit_after>package localkube

import (
	"fmt"
	"net"
	"os"

	apiserver "k8s.io/kubernetes/cmd/kube-apiserver/app"
	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
)

const (
	APIServerName = "apiserver"
	APIServerHost = "0.0.0.0"
	APIServerPort = 8080
)

var (
	APIServerURL   string
	ServiceIPRange = "10.1.30.0/24"
)

func init() {
	APIServerURL = fmt.Sprintf("http://%s:%d", APIServerHost, APIServerPort)
	if ipRange := os.Getenv("SERVICE_IP_RANGE"); len(ipRange) != 0 {
		ServiceIPRange = ipRange
	}
}

func NewAPIServer() Server {
	return SimpleServer{
		ComponentName: APIServerName,
		StartupFn:     StartAPIServer,
	}.NoShutdown()
}

func StartAPIServer() {
	config := options.NewAPIServer()

	// use host/port from vars
	config.InsecureBindAddress = net.ParseIP(APIServerHost)
	config.InsecurePort = APIServerPort

	// use localkube etcd
	config.EtcdConfig = etcdstorage.EtcdConfig{
		ServerList: EtcdClientURLs,
	}

	// set Service IP range
	_, ipnet, err := net.ParseCIDR(ServiceIPRange)
	if err != nil {
		panic(err)
	}
	config.ServiceClusterIPRange = *ipnet

	// defaults from apiserver command
	config.EnableProfiling = true
	config.EnableWatchCache = true
	config.MinRequestTimeout = 1800

	// start API server in it's own goroutine
	go apiserver.Run(config)
}
<|endoftext|>