<commit_before>/*
// Copyright (c) 2016 Intel Corporation
//
// 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 qemu provides methods and types for launching and managing QEMU
// instances.  Instances can be launched with the LaunchQemu function and
// managed thereafter via QMPStart and the QMP object that this function
// returns.  To manage a qemu instance after it has been launched you need
// to pass the -qmp option during launch requesting the qemu instance to create
// a QMP unix domain manageent socket, e.g.,
// -qmp unix:/tmp/qmp-socket,server,nowait.  For more information see the
// example below.
package qemu

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"

	"context"
)

// Config is the qemu configuration structure.
// It allows for passing custom settings and parameters to the qemu API.
type Config struct {
	// Path is the qemu binary path.
	Path string

	// Ctx is not used at the moment.
	Ctx context.Context

	// MachineType is the machine type to be used by qemu.
	MachineType string

	// MachineTypeAcceleration are the machine acceleration option to be used by qemu.
	MachineTypeAcceleration string

	// CPUModel is the CPU model to be used by qemu.
	CPUModel string

	// ExtraParams is a slice of options to pass to qemu.
	ExtraParams []string

	// FDs is a list of open file descriptors to be passed to the spawned qemu process
	FDs []*os.File
}

func appendMachineParams(params []string, config Config) []string {
	if config.MachineType != "" && config.MachineTypeAcceleration != "" {
		params = append(params, "-machine")
		params = append(params, fmt.Sprintf("%s,accel=%s", config.MachineType, config.MachineTypeAcceleration))
	}

	return params
}

func appendCPUModel(params []string, config Config) []string {
	if config.CPUModel != "" {
		params = append(params, "-cpu")
		params = append(params, config.CPUModel)
	}

	return params
}

// LaunchQemu can be used to launch a new qemu instance.
//
// The Config parameter contains a set of qemu parameters and settings.
//
// This function writes its log output via logger parameter.
//
// The function will block until the launched qemu process exits.  "", nil
// will be returned if the launch succeeds.  Otherwise a string containing
// the contents of stderr + a Go error object will be returned.
func LaunchQemu(config Config, logger QMPLog) (string, error) {
	var params []string

	params = appendMachineParams(params, config)
	params = appendCPUModel(params, config)
	params = append(params, config.ExtraParams...)

	return LaunchCustomQemu(config.Ctx, config.Path, params, config.FDs, logger)
}

// LaunchCustomQemu can be used to launch a new qemu instance.
//
// The path parameter is used to pass the qemu executable path.
//
// The ctx parameter is not currently used but has been added so that the
// signature of this function will not need to change when launch cancellation
// is implemented.
//
// params is a slice of options to pass to qemu-system-x86_64 and fds is a
// list of open file descriptors that are to be passed to the spawned qemu
// process.
//
// This function writes its log output via logger parameter.
//
// The function will block until the launched qemu process exits.  "", nil
// will be returned if the launch succeeds.  Otherwise a string containing
// the contents of stderr + a Go error object will be returned.
func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*os.File, logger QMPLog) (string, error) {
	if logger == nil {
		logger = qmpNullLogger{}
	}

	errStr := ""

	if path == "" {
		path = "qemu-system-x86_64"
	}

	cmd := exec.Command(path, params...)
	if len(fds) > 0 {
		logger.Infof("Adding extra file %v", fds)
		cmd.ExtraFiles = fds
	}

	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	logger.Infof("launching qemu with: %v", params)

	err := cmd.Run()
	if err != nil {
		logger.Errorf("Unable to launch qemu: %v", err)
		errStr = stderr.String()
		logger.Errorf("%s", errStr)
	}
	return errStr, err
}
<commit_msg>qemu: Add qemu's name to the Config structure<commit_after>/*
// Copyright (c) 2016 Intel Corporation
//
// 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 qemu provides methods and types for launching and managing QEMU
// instances.  Instances can be launched with the LaunchQemu function and
// managed thereafter via QMPStart and the QMP object that this function
// returns.  To manage a qemu instance after it has been launched you need
// to pass the -qmp option during launch requesting the qemu instance to create
// a QMP unix domain manageent socket, e.g.,
// -qmp unix:/tmp/qmp-socket,server,nowait.  For more information see the
// example below.
package qemu

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"

	"context"
)

// Config is the qemu configuration structure.
// It allows for passing custom settings and parameters to the qemu API.
type Config struct {
	// Path is the qemu binary path.
	Path string

	// Ctx is not used at the moment.
	Ctx context.Context

	// Name is the qemu guest name
	Name string

	// MachineType is the machine type to be used by qemu.
	MachineType string

	// MachineTypeAcceleration are the machine acceleration option to be used by qemu.
	MachineTypeAcceleration string

	// CPUModel is the CPU model to be used by qemu.
	CPUModel string

	// ExtraParams is a slice of options to pass to qemu.
	ExtraParams []string

	// FDs is a list of open file descriptors to be passed to the spawned qemu process
	FDs []*os.File
}

func appendName(params []string, config Config) []string {
	if config.Name != "" {
		params = append(params, "-name")
		params = append(params, config.Name)
	}

	return params
}

func appendMachineParams(params []string, config Config) []string {
	if config.MachineType != "" && config.MachineTypeAcceleration != "" {
		params = append(params, "-machine")
		params = append(params, fmt.Sprintf("%s,accel=%s", config.MachineType, config.MachineTypeAcceleration))
	}

	return params
}

func appendCPUModel(params []string, config Config) []string {
	if config.CPUModel != "" {
		params = append(params, "-cpu")
		params = append(params, config.CPUModel)
	}

	return params
}

// LaunchQemu can be used to launch a new qemu instance.
//
// The Config parameter contains a set of qemu parameters and settings.
//
// This function writes its log output via logger parameter.
//
// The function will block until the launched qemu process exits.  "", nil
// will be returned if the launch succeeds.  Otherwise a string containing
// the contents of stderr + a Go error object will be returned.
func LaunchQemu(config Config, logger QMPLog) (string, error) {
	var params []string

	params = appendName(params, config)
	params = appendMachineParams(params, config)
	params = appendCPUModel(params, config)
	params = append(params, config.ExtraParams...)

	return LaunchCustomQemu(config.Ctx, config.Path, params, config.FDs, logger)
}

// LaunchCustomQemu can be used to launch a new qemu instance.
//
// The path parameter is used to pass the qemu executable path.
//
// The ctx parameter is not currently used but has been added so that the
// signature of this function will not need to change when launch cancellation
// is implemented.
//
// params is a slice of options to pass to qemu-system-x86_64 and fds is a
// list of open file descriptors that are to be passed to the spawned qemu
// process.
//
// This function writes its log output via logger parameter.
//
// The function will block until the launched qemu process exits.  "", nil
// will be returned if the launch succeeds.  Otherwise a string containing
// the contents of stderr + a Go error object will be returned.
func LaunchCustomQemu(ctx context.Context, path string, params []string, fds []*os.File, logger QMPLog) (string, error) {
	if logger == nil {
		logger = qmpNullLogger{}
	}

	errStr := ""

	if path == "" {
		path = "qemu-system-x86_64"
	}

	cmd := exec.Command(path, params...)
	if len(fds) > 0 {
		logger.Infof("Adding extra file %v", fds)
		cmd.ExtraFiles = fds
	}

	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	logger.Infof("launching qemu with: %v", params)

	err := cmd.Run()
	if err != nil {
		logger.Errorf("Unable to launch qemu: %v", err)
		errStr = stderr.String()
		logger.Errorf("%s", errStr)
	}
	return errStr, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"database/sql"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	_ "github.com/lib/pq"
)

type Fataler interface {
	Fatal(...interface{})
}

func openTestDB(f Fataler) *sql.DB {
	dbname := os.Getenv("PGDATABASE")
	sslmode := os.Getenv("PGSSLMODE")
	timeout := os.Getenv("PGCONNECT_TIMEOUT")

	if dbname == "" {
		os.Setenv("PGDATABASE", "tablestruct_test")
	}

	if sslmode == "" {
		os.Setenv("PGSSLMODE", "disable")
	}

	if timeout == "" {
		os.Setenv("PGCONNECT_TIMEOUT", "10")
	}

	db, err := sql.Open("postgres", "")
	if err != nil {
		f.Fatal(err)
	}
	return db
}

func tempDir(f Fataler) string {
	name, err := ioutil.TempDir("", "tablestruct_test")
	if err != nil {
		f.Fatal(err)
	}
	return name
}

func tempFile(dir string, f Fataler) *os.File {
	file, err := ioutil.TempFile(dir, "tablestruct_test")
	if err != nil {
		f.Fatal(err)
	}
	return file
}

func tempGoFile(dir string, f Fataler) *os.File {
	file := tempFile(dir, f)
	os.Symlink(file.Name(), file.Name()+".go")
	return file
}

var get = CodeGenTest{
	CreateTableSQL: `CREATE TABLE t (id int, val int)`,
	CleanupSQL:     `DROP TABLE t`,
	TableSetupSQL:  `INSERT INTO t (SELECT generate_series(0, 10), generate_series(100, 110))`,
	Metadata: `
[
    {
        "struct": "T",
        "table": "t",
        "columns": [{
            "field": "Value",
            "column": "val",
            "type": "int"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type T struct {
    ID    int
    Value int
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewTMapper(db)
    t, err := m.Get(8)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d\n", t.Value)
}
`,
	Expected: "108\n",
}

var all = CodeGenTest{
	CreateTableSQL: `CREATE TABLE zipcodes (id int, zipcode varchar)`,
	CleanupSQL:     `DROP TABLE zipcodes`,
	TableSetupSQL:  `INSERT INTO zipcodes (SELECT generate_series(0, 9), generate_series(21230, 21239)::varchar)`,
	Metadata: `
[
    {
        "struct": "ZIPCode",
        "table": "zipcodes",
        "columns": [{
            "field": "Z5",
            "column": "zipcode",
            "type": "varchar"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type ZIPCode struct {
    ID    int
    Z5    string
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewZIPCodeMapper(db)
    zips, err := m.All()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d\n", len(zips))
    for i := range zips {
        fmt.Printf("%s\n", zips[i].Z5)
    }
}
`,
	Expected: `10
21230
21231
21232
21233
21234
21235
21236
21237
21238
21239
`}

var insert = CodeGenTest{
	CreateTableSQL: `CREATE TABLE person (id int, name varchar, age int)`,
	CleanupSQL:     `DROP TABLE person`,
	Metadata: `
[
    {
        "struct": "Person",
        "table": "person",
        "columns": [{
            "field": "Name",
            "column": "name",
            "type": "varchar"
        }, {
            "field": "Age",
            "column": "age",
            "type": "int"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type Person struct {
    ID      int64
    Name    string
    Age     int
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewPersonMapper(db)
    p := Person{42, "Paul Smith", 37}
    err = m.Insert(&p)
    if err != nil {
        log.Fatal(err)
    }
    dest := []interface{}{
        new(int64),
        new(string),
        new(int),
    }
    err = db.QueryRow("SELECT * FROM person WHERE id = 42").Scan(dest...)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d '%s' %d\n", *dest[0].(*int64), *dest[1].(*string), *dest[2].(*int))
}
`,
	Expected: "42 'Paul Smith' 37\n",
}

type CodeGenTest struct {
	CreateTableSQL string
	TableSetupSQL  string
	CleanupSQL     string
	Metadata       string
	DriverCode     string
	Expected       string
}

func testCodeGen(t *testing.T, test CodeGenTest) {
	db := openTestDB(t)
	defer db.Close()

	_, err := db.Exec(test.CreateTableSQL)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if test.CleanupSQL != "" {
			db.Exec(test.CleanupSQL)
		}
	}()

	if test.TableSetupSQL != "" {
		_, err = db.Exec(test.TableSetupSQL)
		if err != nil {
			t.Fatal(err)
		}
	}

	mapper, err := NewMap(strings.NewReader(test.Metadata))
	if err != nil {
		t.Fatal(err)
	}

	dir := tempDir(t)
	genCodeFile := tempGoFile(dir, t)
	driverCodeFile := tempGoFile(dir, t)

	defer func() {
		genCodeFile.Close()
		driverCodeFile.Close()
		os.RemoveAll(dir)
	}()

	code := NewCode()
	code.Gen(mapper, "main", genCodeFile)

	if _, err := driverCodeFile.WriteString(test.DriverCode); err != nil {
		t.Fatal(err)
	}

	genCodeFile.Sync()
	driverCodeFile.Sync()

	goFiles, err := filepath.Glob(filepath.Join(dir, "*.go"))
	if err != nil {
		t.Fatal(err)
	}

	args := []string{"run"}
	for i := range goFiles {
		args = append(args, goFiles[i])
	}

	cmd := exec.Command("go", args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		t.Log(stderr.String())
		t.Fatalf("error running generated Go code: %s", err)
	}

	if actual := stdout.String(); actual != test.Expected {
		t.Errorf("want %q, got %q", test.Expected, actual)
	}
}

func TestCodeGen(t *testing.T) {
	var tests = map[string]CodeGenTest{
		"Get":    get,
		"All":    all,
		"Insert": insert,
	}
	for name, test := range tests {
		t.Log(name)
		testCodeGen(t, test)
	}
}
<commit_msg>Tweak insert unit test<commit_after>package main

import (
	"bytes"
	"database/sql"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	_ "github.com/lib/pq"
)

type Fataler interface {
	Fatal(...interface{})
}

func openTestDB(f Fataler) *sql.DB {
	dbname := os.Getenv("PGDATABASE")
	sslmode := os.Getenv("PGSSLMODE")
	timeout := os.Getenv("PGCONNECT_TIMEOUT")

	if dbname == "" {
		os.Setenv("PGDATABASE", "tablestruct_test")
	}

	if sslmode == "" {
		os.Setenv("PGSSLMODE", "disable")
	}

	if timeout == "" {
		os.Setenv("PGCONNECT_TIMEOUT", "10")
	}

	db, err := sql.Open("postgres", "")
	if err != nil {
		f.Fatal(err)
	}
	return db
}

func tempDir(f Fataler) string {
	name, err := ioutil.TempDir("", "tablestruct_test")
	if err != nil {
		f.Fatal(err)
	}
	return name
}

func tempFile(dir string, f Fataler) *os.File {
	file, err := ioutil.TempFile(dir, "tablestruct_test")
	if err != nil {
		f.Fatal(err)
	}
	return file
}

func tempGoFile(dir string, f Fataler) *os.File {
	file := tempFile(dir, f)
	os.Symlink(file.Name(), file.Name()+".go")
	return file
}

var get = CodeGenTest{
	CreateTableSQL: `CREATE TABLE t (id int, val int)`,
	CleanupSQL:     `DROP TABLE t`,
	TableSetupSQL:  `INSERT INTO t (SELECT generate_series(0, 10), generate_series(100, 110))`,
	Metadata: `
[
    {
        "struct": "T",
        "table": "t",
        "columns": [{
            "field": "Value",
            "column": "val",
            "type": "int"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type T struct {
    ID    int
    Value int
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewTMapper(db)
    t, err := m.Get(8)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d\n", t.Value)
}
`,
	Expected: "108\n",
}

var all = CodeGenTest{
	CreateTableSQL: `CREATE TABLE zipcodes (id int, zipcode varchar)`,
	CleanupSQL:     `DROP TABLE zipcodes`,
	TableSetupSQL:  `INSERT INTO zipcodes (SELECT generate_series(0, 9), generate_series(21230, 21239)::varchar)`,
	Metadata: `
[
    {
        "struct": "ZIPCode",
        "table": "zipcodes",
        "columns": [{
            "field": "Z5",
            "column": "zipcode",
            "type": "varchar"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type ZIPCode struct {
    ID    int
    Z5    string
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewZIPCodeMapper(db)
    zips, err := m.All()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d\n", len(zips))
    for i := range zips {
        fmt.Printf("%s\n", zips[i].Z5)
    }
}
`,
	Expected: `10
21230
21231
21232
21233
21234
21235
21236
21237
21238
21239
`}

var insert = CodeGenTest{
	CreateTableSQL: `CREATE TABLE person (id int, name varchar, age int)`,
	CleanupSQL:     `DROP TABLE person`,
	Metadata: `
[
    {
        "struct": "Person",
        "table": "person",
        "columns": [{
            "field": "Name",
            "column": "name",
            "type": "varchar"
        }, {
            "field": "Age",
            "column": "age",
            "type": "int"
        }]
    }
]
`,
	DriverCode: `
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type Person struct {
    ID      int64
    Name    string
    Age     int
}

func main() {
    db, err := sql.Open("postgres", "")
    if err != nil {
        log.Fatal(err)
    }
    m := NewPersonMapper(db)
    var before, after int
    if err := db.QueryRow("SELECT COUNT(*) FROM person").Scan(&before); err != nil {
        log.Fatal(err)
    }
    p := Person{42, "Paul Smith", 37}
    if err = m.Insert(&p); err != nil {
        log.Fatal(err)
    }
    if err := db.QueryRow("SELECT COUNT(*) FROM person").Scan(&after); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("delta: %d\n", after-before)
    dest := []interface{}{
        new(int64),
        new(string),
        new(int),
    }
    err = db.QueryRow("SELECT * FROM person WHERE id = 42").Scan(dest...)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%d '%s' %d\n", *dest[0].(*int64), *dest[1].(*string), *dest[2].(*int))
}
`,
	Expected: `delta: 1
42 'Paul Smith' 37
`,
}

type CodeGenTest struct {
	CreateTableSQL string
	TableSetupSQL  string
	CleanupSQL     string
	Metadata       string
	DriverCode     string
	Expected       string
}

func testCodeGen(t *testing.T, test CodeGenTest) {
	db := openTestDB(t)
	defer db.Close()

	_, err := db.Exec(test.CreateTableSQL)
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if test.CleanupSQL != "" {
			db.Exec(test.CleanupSQL)
		}
	}()

	if test.TableSetupSQL != "" {
		_, err = db.Exec(test.TableSetupSQL)
		if err != nil {
			t.Fatal(err)
		}
	}

	mapper, err := NewMap(strings.NewReader(test.Metadata))
	if err != nil {
		t.Fatal(err)
	}

	dir := tempDir(t)
	genCodeFile := tempGoFile(dir, t)
	driverCodeFile := tempGoFile(dir, t)

	defer func() {
		genCodeFile.Close()
		driverCodeFile.Close()
		os.RemoveAll(dir)
	}()

	code := NewCode()
	code.Gen(mapper, "main", genCodeFile)

	if _, err := driverCodeFile.WriteString(test.DriverCode); err != nil {
		t.Fatal(err)
	}

	genCodeFile.Sync()
	driverCodeFile.Sync()

	goFiles, err := filepath.Glob(filepath.Join(dir, "*.go"))
	if err != nil {
		t.Fatal(err)
	}

	args := []string{"run"}
	for i := range goFiles {
		args = append(args, goFiles[i])
	}

	cmd := exec.Command("go", args...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		t.Log(stderr.String())
		t.Fatalf("error running generated Go code: %s", err)
	}

	if actual := stdout.String(); actual != test.Expected {
		t.Errorf("want %q, got %q", test.Expected, actual)
	}
}

func TestCodeGen(t *testing.T) {
	var tests = map[string]CodeGenTest{
		"Get":    get,
		"All":    all,
		"Insert": insert,
	}
	for name, test := range tests {
		t.Log(name)
		testCodeGen(t, test)
	}
}
<|endoftext|>


<commit_before>package queryable

import (
	"fmt"
	"reflect"
)

type re struct {
	msg string
}

func (err *re) Error() string {
	return err.msg
}

func ne(err string) *re {
	return &re{err}
}

func fv(v interface{}) reflect.Value {
	v0 := reflect.ValueOf(v)
	for v0.Kind() == reflect.Ptr {
		v0 = v0.Elem()
	}
	return v0
}

// Creates a new Queryable element.
// You can pass the Raw pointer to unmarshallers.
func New() *Queryable {
	return &Queryable{nil}
	//return &Queryable{make(map[string]interface{})}
}

type Queryable struct {
	Raw interface{}
}

// Runs a query with one or more indexes
func (q *Queryable) QT(indexes ...interface{}) (*Queryable, error) {
	//fmt.Printf("QT( %v ) \n", indexes)
	rval := fv(q.Raw)
	kind := rval.Kind()
	if len(indexes) > 0 {
		switch kind {
		case reflect.Slice, reflect.Array, reflect.String, reflect.Struct, reflect.Map:
			//OK
		default:
			return nil, ne("non queryable element type: " + kind.String() + " " + fmt.Sprintf("%v %v", len(indexes), indexes[0]))
		}
	} else {
		return q, nil
	}
	switch kind {
	case reflect.String:
		if len(indexes) > 1 {
			return nil, ne("a rune is not queryable")
		}
		if reflect.ValueOf(indexes[0]).Kind() != reflect.Int {
			return nil, ne("rune index should be an int")
		}
		return &Queryable{rval.String()[int(reflect.ValueOf(indexes[0]).Int())]}, nil
	case reflect.Map:
		if rval.Type().Key().Kind() != reflect.ValueOf(indexes[0]).Kind() {
			return nil, ne("key kind differs index kind")
		}
		//TODO: see if it needs to use fv() below
		a := rval.MapIndex(reflect.ValueOf(indexes[0])).Interface()
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	case reflect.Struct:
		if fv(indexes[0]).Kind() != reflect.String {
			return nil, ne("key kind differs index kind")
		}
		a := rval.FieldByName(fv(indexes[0]).String())
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	case reflect.Slice, reflect.Array:
		//TODO: catch out of range panics
		if fv(indexes[0]).Kind() != reflect.Int {
			return nil, ne("key of slice/array is not int")
		}
		a := rval.Index(int(fv(indexes[0]).Int())).Interface()
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	}
	//TODO: support chan
	//
	return nil, nil
}

// Runs a query with one or more indexes. Omits errors.
func (q *Queryable) Q(indexes ...interface{}) *Queryable {
	qt, err := q.QT(indexes...)
	if err != nil {
		fmt.Println("FATAL Queryable Q", err)
		return nil
	}
	return qt
}

// Runs a query with one or more indexes. It panics if an error is found.
func (q *Queryable) QMust(indexes ...interface{}) *Queryable {
	qt, err := q.QT(indexes...)
	if err != nil {
		panic("FATAL Queryable Q: " + err.Error())
	}
	return qt
}

// Returns the length of the contained value. It returns 0 if the value is not an Array, Slice, Chan, String or Map.
func (q *Queryable) Len() int {
	//TODO: maybe support struct
	rval := fv(q.Raw)
	kind := rval.Kind()
	switch kind {
	case reflect.Array, reflect.Slice, reflect.Chan, reflect.String, reflect.Map:
		return rval.Len()
	}
	return 0
}

// Loops through all elements of a map, slice or array.
func (q *Queryable) Foreach(f func(key, val *Queryable) bool) error {
	//TODO: maybe support struct
	rval := fv(q.Raw)
	kind := rval.Kind()
	switch kind {
	case reflect.Array, reflect.Slice, reflect.Map:
		// OK
	default:
		return ne("not loopable (Foreach works on arrays, slices and maps)")
	}
	if kind == reflect.Map {
		keys := rval.MapKeys()
		for i := 0; i < len(keys); i++ {
			val := rval.MapIndex(keys[i])
			ok := f(&Queryable{keys[i].Interface()}, &Queryable{val.Interface()})
			if !ok {
				return nil
			}
		}
	}
	// slice
	for i := 0; i < rval.Len(); i++ {
		val := rval.Index(i)
		ok := f(&Queryable{i}, &Queryable{val.Interface()})
		if !ok {
			return nil
		}
	}
	return nil
}

func (q *Queryable) IntT() (int, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return int(fvv.Int()), nil
	case reflect.Float64, reflect.Float32:
		return int(fvv.Float()), nil
	}
	return 0, ne("not an int " + fvv.Kind().String())
}

func (q *Queryable) Int64T() (int64, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return fvv.Int(), nil
	case reflect.Float64, reflect.Float32:
		return int64(fvv.Float()), nil
	}
	return 0, ne("not an int64 " + fvv.Kind().String())
}

func (q *Queryable) Float64T() (float64, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(fvv.Int()), nil
	case reflect.Float64, reflect.Float32:
		return fvv.Float(), nil
	}
	return 0, ne("not a float64 " + fvv.Kind().String())
}

func (q *Queryable) BoolT() (bool, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Bool:
		return fvv.Bool(), nil
	}
	return false, ne("not a bool " + fvv.Kind().String())
}

func (q *Queryable) StringT() (string, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.String:
		return fvv.String(), nil
	}
	return "", ne("not a string " + fvv.Kind().String())
}

func (q *Queryable) Int() int {
	v, _ := q.IntT()
	return v
}

func (q *Queryable) Int64() int64 {
	v, _ := q.Int64T()
	return v
}

func (q *Queryable) Float64() float64 {
	v, _ := q.Float64T()
	return v
}

func (q *Queryable) Bool() bool {
	v, _ := q.BoolT()
	return v
}

func (q *Queryable) String() string {
	v, _ := q.StringT()
	return v
}
<commit_msg>added time.Time unmarshal<commit_after>package queryable

import (
	"fmt"
	"reflect"
	"time"
)

type re struct {
	msg string
}

func (err *re) Error() string {
	return err.msg
}

func ne(err string) *re {
	return &re{err}
}

func fv(v interface{}) reflect.Value {
	v0 := reflect.ValueOf(v)
	for v0.Kind() == reflect.Ptr {
		v0 = v0.Elem()
	}
	return v0
}

// Creates a new Queryable element.
// You can pass the Raw pointer to unmarshallers.
func New() *Queryable {
	return &Queryable{nil}
	//return &Queryable{make(map[string]interface{})}
}

type Queryable struct {
	Raw interface{}
}

// Runs a query with one or more indexes
func (q *Queryable) QT(indexes ...interface{}) (*Queryable, error) {
	//fmt.Printf("QT( %v ) \n", indexes)
	rval := fv(q.Raw)
	kind := rval.Kind()
	if len(indexes) > 0 {
		switch kind {
		case reflect.Slice, reflect.Array, reflect.String, reflect.Struct, reflect.Map:
			//OK
		default:
			return nil, ne("non queryable element type: " + kind.String() + " " + fmt.Sprintf("%v %v", len(indexes), indexes[0]))
		}
	} else {
		return q, nil
	}
	switch kind {
	case reflect.String:
		if len(indexes) > 1 {
			return nil, ne("a rune is not queryable")
		}
		if reflect.ValueOf(indexes[0]).Kind() != reflect.Int {
			return nil, ne("rune index should be an int")
		}
		return &Queryable{rval.String()[int(reflect.ValueOf(indexes[0]).Int())]}, nil
	case reflect.Map:
		if rval.Type().Key().Kind() != reflect.ValueOf(indexes[0]).Kind() {
			return nil, ne("key kind differs index kind")
		}
		//TODO: see if it needs to use fv() below
		a := rval.MapIndex(reflect.ValueOf(indexes[0])).Interface()
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	case reflect.Struct:
		if fv(indexes[0]).Kind() != reflect.String {
			return nil, ne("key kind differs index kind")
		}
		a := rval.FieldByName(fv(indexes[0]).String())
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	case reflect.Slice, reflect.Array:
		//TODO: catch out of range panics
		if fv(indexes[0]).Kind() != reflect.Int {
			return nil, ne("key of slice/array is not int")
		}
		a := rval.Index(int(fv(indexes[0]).Int())).Interface()
		b := &Queryable{a}
		return b.QT(indexes[1:]...)
	}
	//TODO: support chan
	//
	return nil, nil
}

// Runs a query with one or more indexes. Omits errors.
func (q *Queryable) Q(indexes ...interface{}) *Queryable {
	qt, err := q.QT(indexes...)
	if err != nil {
		fmt.Println("FATAL Queryable Q", err)
		return nil
	}
	return qt
}

// Runs a query with one or more indexes. It panics if an error is found.
func (q *Queryable) QMust(indexes ...interface{}) *Queryable {
	qt, err := q.QT(indexes...)
	if err != nil {
		panic("FATAL Queryable Q: " + err.Error())
	}
	return qt
}

// Returns the length of the contained value. It returns 0 if the value is not an Array, Slice, Chan, String or Map.
func (q *Queryable) Len() int {
	//TODO: maybe support struct
	rval := fv(q.Raw)
	kind := rval.Kind()
	switch kind {
	case reflect.Array, reflect.Slice, reflect.Chan, reflect.String, reflect.Map:
		return rval.Len()
	}
	return 0
}

// Loops through all elements of a map, slice or array.
func (q *Queryable) Foreach(f func(key, val *Queryable) bool) error {
	//TODO: maybe support struct
	rval := fv(q.Raw)
	kind := rval.Kind()
	switch kind {
	case reflect.Array, reflect.Slice, reflect.Map:
		// OK
	default:
		return ne("not loopable (Foreach works on arrays, slices and maps)")
	}
	if kind == reflect.Map {
		keys := rval.MapKeys()
		for i := 0; i < len(keys); i++ {
			val := rval.MapIndex(keys[i])
			ok := f(&Queryable{keys[i].Interface()}, &Queryable{val.Interface()})
			if !ok {
				return nil
			}
		}
	}
	// slice
	for i := 0; i < rval.Len(); i++ {
		val := rval.Index(i)
		ok := f(&Queryable{i}, &Queryable{val.Interface()})
		if !ok {
			return nil
		}
	}
	return nil
}

func (q *Queryable) IntT() (int, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return int(fvv.Int()), nil
	case reflect.Float64, reflect.Float32:
		return int(fvv.Float()), nil
	}
	return 0, ne("not an int " + fvv.Kind().String())
}

func (q *Queryable) Int64T() (int64, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return fvv.Int(), nil
	case reflect.Float64, reflect.Float32:
		return int64(fvv.Float()), nil
	}
	return 0, ne("not an int64 " + fvv.Kind().String())
}

func (q *Queryable) Float64T() (float64, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(fvv.Int()), nil
	case reflect.Float64, reflect.Float32:
		return fvv.Float(), nil
	}
	return 0, ne("not a float64 " + fvv.Kind().String())
}

func (q *Queryable) BoolT() (bool, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.Bool:
		return fvv.Bool(), nil
	}
	return false, ne("not a bool " + fvv.Kind().String())
}

func (q *Queryable) StringT() (string, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.String:
		return fvv.String(), nil
	}
	return "", ne("not a string " + fvv.Kind().String())
}

func (q *Queryable) TimeT() (time.Time, error) {
	fvv := fv(q.Raw)
	switch fvv.Kind() {
	case reflect.String:
		t := time.Time{}
		err := t.UnmarshalText([]byte(fvv.String()))
		return t, err
	case reflect.Uint:
		return time.Unix(int64(fvv.Uint()), 0), nil
	case reflect.Int:
		return time.Unix(fvv.Int(), 0), nil
	case reflect.Struct:
		t, ok := q.Raw.(time.Time)
		if ok {
			return t, nil
		}
	}
	return time.Time{}, ne("not a valid time object " + fvv.Kind().String())
}

func (q *Queryable) Int() int {
	v, _ := q.IntT()
	return v
}

func (q *Queryable) Int64() int64 {
	v, _ := q.Int64T()
	return v
}

func (q *Queryable) Float64() float64 {
	v, _ := q.Float64T()
	return v
}

func (q *Queryable) Bool() bool {
	v, _ := q.BoolT()
	return v
}

func (q *Queryable) String() string {
	v, _ := q.StringT()
	return v
}

func (q *Queryable) Time() time.Time {
	v, _ := q.TimeT()
	return v
}
<|endoftext|>


<commit_before>package main

import (
	//"encoding/hex"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"

	"github.com/grantek/fkmd/krikzz_fkmd"
	"github.com/grantek/fkmd/mdcart"
	"github.com/grantek/fkmd/memcart"
	"github.com/jacobsa/go-serial/serial"
)

func usage() {
	fmt.Println("fkmd usage:")
	flag.PrintDefaults()
	os.Exit(-1)
}

//md specific
func ReadRom(mdc memcart.MemCart, romfile string, autoname bool) {
	var (
		romname   string
		romsize   int64
		blocksize int64 = 32768
		f         *os.File
		err       error
		mdr       memcart.MemBank
	)
	if autoname {
		romname, err = mdcart.GetRomName(mdc)
		if err != nil {
			panic(err)
		}
		re := regexp.MustCompile("  *")
		romname = re.ReplaceAllString(romname, " ")
		romname = strings.Title(strings.ToLower(strings.TrimSpace(romname)))
		romfile = fmt.Sprintf("%s.bin", romname)
	}

	err = mdc.SwitchBank(0)
	if err != nil {
		panic(err)
	}
	mdr = mdc.GetCurrentBank()
	if romfile == "-" {
		f = os.Stdout
	} else {
		f, err = os.Create(romfile)
		if err != nil {
			fmt.Println(err)
			return
		}
	}

	if f != os.Stdout {
		fmt.Println("Opened", romfile, "for writing")
		defer f.Close()
	}

	romsize = mdr.GetSize()
	mdr.Seek(0, io.SeekStart)
	buf := make([]byte, blocksize)
	for i := int64(0); i < romsize; i += blocksize {
		mdr.Read(buf)
		f.Write(buf)
		if f != os.Stdout {
			fmt.Printf(".")
		}
	}
	fmt.Println()
}

func ReadRam(mdc memcart.MemCart, ramfile string, autoname bool) {
	var (
		err error
		f   *os.File
		n   int
		mdr memcart.MemBank
	)

	err = mdc.SwitchBank(1)
	if err != nil {
		panic(err)
	}

	mdr = mdc.GetCurrentBank()
	if mdr == nil {
		panic("Current Bank is nil")
	}

	if ramfile == "" {
		ramfile = "ram.out"
	}
	if ramfile == "-" {
		f = os.Stdout
	} else {
		f, err = os.Create(ramfile)
		if err != nil {
			panic(err)
		}
	}

	if f != os.Stdout {
		fmt.Println("Opened", ramfile, "for writing")
		defer f.Close()
	}

	ramsize := mdr.GetSize()
	buf := make([]byte, ramsize)
	bytesread := 0
	for bytesread < int(ramsize) {
		n, err = mdr.Read(buf[bytesread:])
		bytesread += n
		if err != nil || bytesread == 0 {
			panic("short RAM read")
		}
	}

	f.Write(buf)

	fmt.Println()
}

func WriteRam(mdc memcart.MemCart, ramfile string) {
	var (
		f         *os.File
		n         int
		ram, ram2 []byte
		err       error
	)
	if mdc.NumBanks() < 2 {
		panic("RAM not detected on cartridge for writing")
	}
	mdc.SwitchBank(1)
	mdr := mdc.GetCurrentBank()

	if ramfile == "-" {
		f = os.Stdin
	} else {
		f, err = os.Open(ramfile)
		if err != nil {
			panic(err)
		}
	}
	if f != os.Stdin {
		fmt.Println("Opened", ramfile, "for reading")
		defer f.Close()
	}
	ram, err = ioutil.ReadAll(f)
	if err != nil {
		panic(err)
	}
	n, err = mdr.Write(ram)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Wrote %d bytes", n)
	if n < len(ram) {
		fmt.Printf("WARNING: wrote %d bytes, input is %d bytes.\n", n, len(ram))
	}
	if int64(n) < mdr.GetSize() {
		fmt.Printf("WARNING: wrote %d bytes, cartridge RAM is %d bytes.\n", n, len(ram))
	}
	fmt.Println("Verify...")
	mdr.Seek(0, io.SeekStart)
	for i := 0; i < n; i++ {
		if ram[i] != ram2[i] {
			panic(fmt.Sprintf("Failed verification at byte %d", i))
		}
	}
	fmt.Printf("Verified %d bytes", n)
}

func WriteRom(mdc memcart.MemCart, romfile string) error {
	var (
		romsize  int64
		blocklen int64 = 4096
		f        *os.File
		i        int64
		err      error
		filebuf  []byte
		fblen    int64
	)

	if romfile == "-" {
		f = os.Stdin
		romfile = "stdin"
	} else {
		f, err = os.Open(romfile)
		if err != nil {
			return err
		}
	}

	filebuf, err = ioutil.ReadAll(f)
	if err != nil {
		return err
	}

	if f != os.Stdin {
		f.Close()
	}

	romsize = int64(len(filebuf))

	fmt.Printf("Read %d bytes from %s\n", romsize, romfile)
	if romsize%2 == 1 {
		fmt.Printf("Warning: file size in bytes is odd\n", mdcart.MAX_ROM_SIZE, romsize)
		filebuf = append(filebuf, 0)
		romsize++
	}

	if romsize > mdcart.MAX_ROM_SIZE {
		fmt.Printf("Warning: Max ROM data size is %x, cropping input\n", mdcart.MAX_ROM_SIZE, romsize)
		romsize = mdcart.MAX_ROM_SIZE
	}

	fblen = romsize
	if romsize < 0x8000 {
		return errors.New("Error: file size < 32KiB, pad with 0xFF if required")
	}

	if romsize%0x10000 != 0 {
		romsize = (romsize/0x10000)*0x10000 + 0x10000
	}

	mdc.SwitchBank(0)
	mdr := mdc.GetCurrentBank()

	//Going to rely on Write() performing block erasure
	fmt.Println("Flash write...")
	for i = 0; i < fblen; i += blocklen {
		if i+blocklen > fblen {
			blocklen = fblen - i
		}
		mdr.Write(filebuf[i : i+blocklen])
		fmt.Printf("*")
	}
	fmt.Printf("\n")

	fmt.Println("Flash verify...")
	rom2 := make([]byte, romsize)

	mdr.Seek(0, io.SeekStart)
	for i = 0; i < fblen; i += blocklen {
		if i+blocklen > fblen {
			blocklen = fblen - i
		}
		mdr.Read(rom2[i : i+blocklen])
		fmt.Printf(".")
	}
	fmt.Printf("\n")

	for i = 0; i < fblen; i++ {
		if rom2[i] != filebuf[i] {
			return errors.New(fmt.Sprintf("Verify error at %x", i))
		}
	}

	fmt.Println("OK")
	return nil
}

func main() {
	var (
		err error
	)

	//options
	port := flag.String("port", "/dev/ttyUSB0", "serial port to use (/dev/ttyUSB0, etc)")

	//serial options, shouldn't be needed
	/*
		baud := flag.Uint("baud", 9600, "Baud rate")
		even := flag.Bool("even", false, "enable even parity")
		odd := flag.Bool("odd", false, "enable odd parity")
		rs485 := flag.Bool("rs485", false, "enable RS485 RTS for direction control")
		rs485HighDuringSend := flag.Bool("rs485_high_during_send", false, "RTS signal should be high during send")
		rs485HighAfterSend := flag.Bool("rs485_high_after_send", false, "RTS signal should be high after send")
		stopbits := flag.Uint("stopbits", 1, "Stop bits")
		databits := flag.Uint("databits", 8, "Data bits")
		chartimeout := flag.Uint("chartimeout", 200, "Inter Character timeout (ms)")
		minread := flag.Uint("minread", 0, "Minimum read count")
	*/

	baud := new(uint)
	*baud = 9600
	//even := new(bool); *even = false
	//odd := new(bool); *odd = false
	parity := serial.PARITY_NONE
	rs485 := new(bool)
	*rs485 = false
	rs485HighDuringSend := new(bool)
	*rs485HighDuringSend = false
	rs485HighAfterSend := new(bool)
	*rs485HighAfterSend = false
	stopbits := new(uint)
	*stopbits = 1
	databits := new(uint)
	*databits = 8
	chartimeout := new(uint)
	*chartimeout = 200
	minread := new(uint)
	*minread = 0

	//fkmd options
	rominfo := flag.Bool("rominfo", false, "Print ROM info")
	readrom := flag.Bool("readrom", false, "Read and output ROM")
	writerom := flag.Bool("writerom", false, "(Flash cart only) Write ROM data to flash")
	readram := flag.Bool("readram", false, "Read and output RAM")
	writeram := flag.Bool("writeram", false, "Write supplied RAM data to cartridge")
	autoname := flag.Bool("autoname", false, "Read ROM name and generate filenames to save ROM/RAM data")
	romfile := flag.String("romfile", "", "File to save or read ROM data")
	ramfile := flag.String("ramfile", "", "File to save or read RAM data")

	flag.Parse()

	if *port == "" {
		fmt.Println("Must specify port")
		usage()
	}

	if *readram && *writeram {
		fmt.Println("Can't read and write cartridge RAM in one invocation")
		usage()
	}

	if *readrom && *writerom {
		fmt.Println("Can't read and write cartridge ROM in one invocation")
		usage()
	}

	if (*romfile != "" || *ramfile != "") && *autoname {
		fmt.Println("Can't supply file names when autoname is used")
		usage()
	}

	if (*readrom || *writerom) && (*romfile == "" && !*autoname) {
		fmt.Println("No ROM file name supplied")
		usage()
	}

	if (*readram || *writeram) && (*ramfile == "" && !*autoname) {
		fmt.Println("No RAM file name supplied")
		usage()
	}

	if !*readrom && !*writerom && !*readram && !*writeram && !*rominfo {
		fmt.Println("No action specified")
		usage()
	}

	options := serial.OpenOptions{
		PortName:               *port,
		BaudRate:               *baud,
		DataBits:               *databits,
		StopBits:               *stopbits,
		MinimumReadSize:        *minread,
		InterCharacterTimeout:  *chartimeout,
		ParityMode:             parity,
		Rs485Enable:            *rs485,
		Rs485RtsHighDuringSend: *rs485HighDuringSend,
		Rs485RtsHighAfterSend:  *rs485HighAfterSend,
	}

	var d = &krikzz_fkmd.Fkmd{}
	d.SetOptions(options)
	var mdc memcart.MemCart
	mdc, err = d.MemCart()

	if err != nil {
		fmt.Println("Error opening serial port: ", err)
		os.Exit(-1)
	} else {
		defer d.Disconnect()
	}

	if *readram {
		ReadRam(mdc, *ramfile, *autoname)
	}

	if *writeram {
		WriteRam(mdc, *ramfile)
	}

	if *readrom {
		ReadRom(mdc, *romfile, *autoname)
	}
	if *writerom {
		WriteRom(mdc, *romfile)
	}

	if *rominfo {
		gotromname, _ := mdcart.GetRomName(mdc)
		fmt.Println(gotromname)
	}
}
<commit_msg>add better logging<commit_after>package main

import (
	//"encoding/hex"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strings"

	"github.com/grantek/fkmd/krikzz_fkmd"
	"github.com/grantek/fkmd/mdcart"
	"github.com/grantek/fkmd/memcart"
	"github.com/jacobsa/go-serial/serial"
)

var (
	elog *log.Logger //Always output to stderr
	ilog *log.Logger //Verbose output
	dlog *log.Logger //Debug output
)

func usage() {
	fmt.Println("fkmd usage:")
	flag.PrintDefaults()
	os.Exit(-1)
}

//md specific
func ReadRom(mdc memcart.MemCart, romfile string, autoname bool) {
	var (
		romname   string
		romsize   int64
		blocksize int64 = 32768
		f         *os.File
		n         int64 //counter for outer read in bytes
		m         int   //counter for inner read in bytes
		err       error
		mdr       memcart.MemBank
	)
	if autoname {
		romname, err = mdcart.GetRomName(mdc)
		if err != nil {
			panic(err)
		}
		re := regexp.MustCompile("  *")
		romname = re.ReplaceAllString(romname, " ")
		romname = strings.Title(strings.ToLower(strings.TrimSpace(romname)))
		romfile = fmt.Sprintf("%s.bin", romname)
	}

	err = mdc.SwitchBank(0)
	if err != nil {
		panic(err)
	}
	mdr = mdc.GetCurrentBank()
	if romfile == "-" {
		f = os.Stdout
	} else {
		f, err = os.Create(romfile)
		if err != nil {
			panic(err)
		}
		ilog.Println("Opened", romfile, "for writing")
		defer f.Close()
	}

	romsize = mdr.GetSize()
	mdr.Seek(0, io.SeekStart)
	buf := make([]byte, blocksize)
	for n := int64(0); n < romsize; n += blocksize {
		m, err = mdr.Read(buf)
		if err != nil {
			panic(err)
		}
		if int64(m) < blocksize {
			elog.Printf("Short read at %d, expected romsize %d", n+int64(m), romsize)
			break
		}
		f.Write(buf[0:n])
		dlog.Printf("Bytes read: %d", n)
	}
	ilog.Printf("Finished reading, bytes read: %d", n)
}

func ReadRam(mdc memcart.MemCart, ramfile string, autoname bool) {
	var (
		err  error
		f    *os.File
		n, m int
		mdr  memcart.MemBank
	)

	err = mdc.SwitchBank(1)
	if err != nil {
		panic(err)
	}

	mdr = mdc.GetCurrentBank()
	if mdr == nil {
		panic("Current Bank is nil")
	}

	if ramfile == "" {
		ramfile = "ram.out"
	}

	if ramfile == "-" {
		f = os.Stdout
	} else {
		f, err = os.Create(ramfile)
		if err != nil {
			panic(err)
		}
		ilog.Println("Opened ", ramfile, " for writing")
		defer f.Close()
	}

	ramsize := mdr.GetSize()
	buf := make([]byte, ramsize)

	for n < int(ramsize) {
		m, err = mdr.Read(buf[n:])
		n += m
		if err != nil || m == 0 {
			panic(fmt.Sprintf("Short RAM read, read %d bytes", n+m))
		}
	}
	ilog.Printf("Read %d bytes", n)
	f.Write(buf)
	ilog.Printf("Ok")
}

func WriteRam(mdc memcart.MemCart, ramfile string) {
	var (
		f         *os.File
		n         int
		ram, ram2 []byte
		err       error
	)
	if mdc.NumBanks() < 2 {
		panic("RAM not detected on cartridge for writing")
	}
	mdc.SwitchBank(1)
	mdr := mdc.GetCurrentBank()

	if ramfile == "-" {
		f = os.Stdin
	} else {
		f, err = os.Open(ramfile)
		if err != nil {
			panic(err)
		}
		ilog.Println("Opened", ramfile, "for reading")
		defer f.Close()
	}

	ram, err = ioutil.ReadAll(f)
	if err != nil {
		panic(err)
	}
	n, err = mdr.Write(ram)
	if err != nil {
		panic(err)
	}
	ilog.Printf("Wrote %d bytes", n)
	if n < len(ram) {
		elog.Printf("WARNING: wrote %d bytes, input is %d bytes.\n", n, len(ram))
	}
	if int64(n) < mdr.GetSize() {
		elog.Printf("WARNING: wrote %d bytes, cartridge RAM is %d bytes.\n", n, len(ram))
	}
	ilog.Println("Verify...")
	mdr.Seek(0, io.SeekStart)
	for i := 0; i < n; i++ {
		if ram[i] != ram2[i] {
			panic(fmt.Sprintf("Failed verification at byte %d", i))
		}
	}
	ilog.Printf("Verified %d bytes", n)
}

func WriteRom(mdc memcart.MemCart, romfile string) error {
	var (
		romsize  int64
		blocklen int64 = 4096
		f        *os.File
		i        int64
		err      error
		filebuf  []byte
		fblen    int64
	)

	if romfile == "-" {
		f = os.Stdin
		romfile = "stdin"
	} else {
		f, err = os.Open(romfile)
		if err != nil {
			return err
		}
		ilog.Println("Opened", romfile, "for reading")
		defer f.Close()
	}

	filebuf, err = ioutil.ReadAll(f)
	if err != nil {
		return err
	}

	if f != os.Stdin {
		f.Close()
	}

	romsize = int64(len(filebuf))
	ilog.Println("Read %d bytes from file", len(filebuf))

	if romsize%2 == 1 {
		elog.Printf("WARNING: file size in bytes is odd", mdcart.MAX_ROM_SIZE, romsize)
		filebuf = append(filebuf, 0)
		romsize++
	}

	if romsize > mdcart.MAX_ROM_SIZE {
		elog.Printf("WARNING: Max ROM data size is %x, cropping input\n", mdcart.MAX_ROM_SIZE, romsize)
		romsize = mdcart.MAX_ROM_SIZE
	}

	fblen = romsize
	if romsize < 0x8000 {
		return errors.New("File size < 32KiB, pad with 0xFF if required")
	}

	if romsize%0x10000 != 0 {
		romsize = (romsize/0x10000)*0x10000 + 0x10000
	}

	mdc.SwitchBank(0)
	mdr := mdc.GetCurrentBank()

	//Going to rely on Write() performing block erasure
	ilog.Println("Flash write...")
	for i = 0; i < fblen; i += blocklen {
		if i+blocklen > fblen {
			blocklen = fblen - i
		}
		//TODO: n, err
		mdr.Write(filebuf[i : i+blocklen])
		dlog.Printf("Bytes written: %d", i)
	}

	ilog.Println("Flash verify...")
	rom2 := make([]byte, romsize)

	mdr.Seek(0, io.SeekStart)
	for i = 0; i < fblen; i += blocklen {
		if i+blocklen > fblen {
			blocklen = fblen - i
		}
		mdr.Read(rom2[i : i+blocklen])
		dlog.Printf("Bytes read: %d", i)
	}

	for i = 0; i < fblen; i++ {
		if rom2[i] != filebuf[i] {
			return errors.New(fmt.Sprintf("Verify error at %x", i))
		}
	}

	ilog.Println("OK")
	return nil
}

func main() {
	var (
		err error
	)

	//options
	port := flag.String("port", "/dev/ttyUSB0", "serial port to use (/dev/ttyUSB0, etc)")

	//serial options, shouldn't be needed
	/*
		baud := flag.Uint("baud", 9600, "Baud rate")
		even := flag.Bool("even", false, "enable even parity")
		odd := flag.Bool("odd", false, "enable odd parity")
		rs485 := flag.Bool("rs485", false, "enable RS485 RTS for direction control")
		rs485HighDuringSend := flag.Bool("rs485_high_during_send", false, "RTS signal should be high during send")
		rs485HighAfterSend := flag.Bool("rs485_high_after_send", false, "RTS signal should be high after send")
		stopbits := flag.Uint("stopbits", 1, "Stop bits")
		databits := flag.Uint("databits", 8, "Data bits")
		chartimeout := flag.Uint("chartimeout", 200, "Inter Character timeout (ms)")
		minread := flag.Uint("minread", 0, "Minimum read count")
	*/

	baud := new(uint)
	*baud = 9600
	//even := new(bool); *even = false
	//odd := new(bool); *odd = false
	parity := serial.PARITY_NONE
	rs485 := new(bool)
	*rs485 = false
	rs485HighDuringSend := new(bool)
	*rs485HighDuringSend = false
	rs485HighAfterSend := new(bool)
	*rs485HighAfterSend = false
	stopbits := new(uint)
	*stopbits = 1
	databits := new(uint)
	*databits = 8
	chartimeout := new(uint)
	*chartimeout = 200
	minread := new(uint)
	*minread = 0

	//fkmd options
	rominfo := flag.Bool("rominfo", false, "Print ROM info")
	readrom := flag.Bool("readrom", false, "Read and output ROM")
	writerom := flag.Bool("writerom", false, "(Flash cart only) Write ROM data to flash")
	readram := flag.Bool("readram", false, "Read and output RAM")
	writeram := flag.Bool("writeram", false, "Write supplied RAM data to cartridge")
	autoname := flag.Bool("autoname", false, "Read ROM name and generate filenames to save ROM/RAM data")
	romfile := flag.String("romfile", "", "File to save or read ROM data")
	ramfile := flag.String("ramfile", "", "File to save or read RAM data")
	verbose := flag.Bool("verbose", false, "Output info logs to stderr")
	debug := flag.Bool("debug", false, "Output debug logs to stderr (implies verbose)")

	flag.Parse()

	elog = log.New(os.Stderr, "", log.Lshortfile)
	if *verbose || *debug {
		ilog = log.New(os.Stderr, "", log.Lshortfile)
	} else {
		ilog = log.New(ioutil.Discard, "", 0)
	}

	if *debug {
		dlog = log.New(os.Stderr, "", log.Lshortfile)
	} else {
		dlog = log.New(ioutil.Discard, "", 0)
	}
	if *port == "" {
		elog.Println("Must specify port")
		usage()
	}

	if *readram && *writeram {
		elog.Println("Can't read and write cartridge RAM in one invocation")
		usage()
	}

	if *readrom && *writerom {
		elog.Println("Can't read and write cartridge ROM in one invocation")
		usage()
	}

	if (*romfile != "" || *ramfile != "") && *autoname {
		elog.Println("Can't supply file names when autoname is used")
		usage()
	}

	if (*readrom || *writerom) && (*romfile == "" && !*autoname) {
		elog.Println("No ROM file name supplied")
		usage()
	}

	if (*readram || *writeram) && (*ramfile == "" && !*autoname) {
		elog.Println("No RAM file name supplied")
		usage()
	}

	if !*readrom && !*writerom && !*readram && !*writeram && !*rominfo {
		elog.Println("No action specified")
		usage()
	}

	options := serial.OpenOptions{
		PortName:               *port,
		BaudRate:               *baud,
		DataBits:               *databits,
		StopBits:               *stopbits,
		MinimumReadSize:        *minread,
		InterCharacterTimeout:  *chartimeout,
		ParityMode:             parity,
		Rs485Enable:            *rs485,
		Rs485RtsHighDuringSend: *rs485HighDuringSend,
		Rs485RtsHighAfterSend:  *rs485HighAfterSend,
	}

	var d = &krikzz_fkmd.Fkmd{}
	d.SetOptions(options)
	var mdc memcart.MemCart
	mdc, err = d.MemCart()

	if err != nil {
		fmt.Println("Error opening serial port: ", err)
		os.Exit(-1)
	} else {
		defer d.Disconnect()
	}

	if *readram {
		ReadRam(mdc, *ramfile, *autoname)
	}

	if *writeram {
		WriteRam(mdc, *ramfile)
	}

	if *readrom {
		ReadRom(mdc, *romfile, *autoname)
	}
	if *writerom {
		WriteRom(mdc, *romfile)
	}

	if *rominfo {
		gotromname, _ := mdcart.GetRomName(mdc)
		fmt.Println(gotromname)
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcec

import (
	"crypto/elliptic"
	"errors"
	"fmt"
	"math/big"
)

// Errors returned by canonicalPadding.
var (
	errNegativeValue          = errors.New("value may be interpreted as negative")
	errExcessivelyPaddedValue = errors.New("value is excessively padded")
)

// Signature is a type representing an ecdsa signature.
type Signature struct {
	R *big.Int
	S *big.Int
}

func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) {
	// Originally this code used encoding/asn1 in order to parse the
	// signature, but a number of problems were found with this approach.
	// Despite the fact that signatures are stored as DER, the difference
	// between go's idea of a bignum (and that they have sign) doesn't agree
	// with the openssl one (where they do not). The above is true as of
	// Go 1.1. In the end it was simpler to rewrite the code to explicitly
	// understand the format which is this:
	// 0x30 <length of whole message> <0x02> <length of R> <R> 0x2
	// <length of S> <S>.

	signature := &Signature{}

	// minimal message is when both numbers are 1 bytes. adding up to:
	// 0x30 + len + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
	if len(sigStr) < 8 {
		return nil, errors.New("malformed signature: too short")
	}
	// 0x30
	index := 0
	if sigStr[index] != 0x30 {
		return nil, errors.New("malformed signature: no header magic")
	}
	index++
	// length of remaining message
	siglen := sigStr[index]
	index++
	if int(siglen+2) > len(sigStr) {
		return nil, errors.New("malformed signature: bad length")
	}
	// trim the slice we're working on so we only look at what matters.
	sigStr = sigStr[:siglen+2]

	// 0x02
	if sigStr[index] != 0x02 {
		return nil,
			errors.New("malformed signature: no 1st int marker")
	}
	index++

	// Length of signature R.
	rLen := int(sigStr[index])
	// must be positive, must be able to fit in another 0x2, <len> <s>
	// hence the -3. We assume that the length must be at least one byte.
	index++
	if rLen <= 0 || rLen > len(sigStr)-index-3 {
		return nil, errors.New("malformed signature: bogus R length")
	}

	// Then R itself.
	rBytes := sigStr[index : index+rLen]
	if der {
		switch err := canonicalPadding(rBytes); err {
		case errNegativeValue:
			return nil, errors.New("signature R is negative")
		case errExcessivelyPaddedValue:
			return nil, errors.New("signature R is excessively padded")
		}
	}
	signature.R = new(big.Int).SetBytes(rBytes)
	index += rLen
	// 0x02. length already checked in previous if.
	if sigStr[index] != 0x02 {
		return nil, errors.New("malformed signature: no 2nd int marker")
	}
	index++

	// Length of signature S.
	sLen := int(sigStr[index])
	index++
	// S should be the rest of the string.
	if sLen <= 0 || sLen > len(sigStr)-index {
		return nil, errors.New("malformed signature: bogus S length")
	}

	// Then S itself.
	sBytes := sigStr[index : index+sLen]
	if der {
		switch err := canonicalPadding(sBytes); err {
		case errNegativeValue:
			return nil, errors.New("signature S is negative")
		case errExcessivelyPaddedValue:
			return nil, errors.New("signature S is excessively padded")
		}
	}
	signature.S = new(big.Int).SetBytes(sBytes)
	index += sLen

	// sanity check length parsing
	if index != len(sigStr) {
		return nil, fmt.Errorf("malformed signature: bad final length %v != %v",
			index, len(sigStr))
	}

	// Verify also checks this, but we can be more sure that we parsed
	// correctly if we verify here too.
	// FWIW the ecdsa spec states that R and S must be | 1, N - 1 |
	// but crypto/ecdsa only checks for Sign != 0. Mirror that.
	if signature.R.Sign() != 1 {
		return nil, errors.New("signature R isn't 1 or more")
	}
	if signature.S.Sign() != 1 {
		return nil, errors.New("signature S isn't 1 or more")
	}
	if signature.R.Cmp(curve.Params().N) >= 0 {
		return nil, errors.New("signature R is >= curve.N")
	}
	if signature.S.Cmp(curve.Params().N) >= 0 {
		return nil, errors.New("signature S is >= curve.N")
	}

	return signature, nil
}

// ParseSignature parses a signature in BER format for the curve type `curve'
// into a Signature type, perfoming some basic sanity checks.  If parsing
// according to the more strict DER format is needed, use ParseDERSignature.
func ParseSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
	return parseSig(sigStr, curve, false)
}

// ParseDERSignature parses a signature in DER format for the curve type
// `curve` into a Signature type.  If parsing according to the less strict
// BER format is needed, use ParseSignature.
func ParseDERSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
	return parseSig(sigStr, curve, true)
}

// canonicalPadding checks whether a big-endian encoded integer could
// possibly be misinterpreted as a negative number (even though OpenSSL
// treats all numbers as unsigned), or if there is any unnecessary
// leading zero padding.
func canonicalPadding(b []byte) error {
	switch {
	case b[0]&0x80 == 0x80:
		return errNegativeValue
	case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80:
		return errExcessivelyPaddedValue
	default:
		return nil
	}
}
<commit_msg>Expose a new Serialize function on Signature type.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcec

import (
	"crypto/elliptic"
	"errors"
	"fmt"
	"math/big"
)

// Errors returned by canonicalPadding.
var (
	errNegativeValue          = errors.New("value may be interpreted as negative")
	errExcessivelyPaddedValue = errors.New("value is excessively padded")
)

// Signature is a type representing an ecdsa signature.
type Signature struct {
	R *big.Int
	S *big.Int
}

// Serialize returns the ECDSA signature in the more strict DER format.  Note
// that the serialized bytes returned do not include the appended hash type
// used in Bitcoin signature scripts.
//
// encoding/asn1 is broken so we hand roll this output:
//
// 0x30 <length> 0x02 <length r> r 0x02 <length s> s
func (sig *Signature) Serialize() []byte {
	// Ensure the encoded bytes for the r and s values are canonical and
	// thus suitable for DER encoding.
	rb := canonicalizeInt(sig.R)
	sb := canonicalizeInt(sig.S)

	// total length of returned signature is 1 byte for each magic and
	// length (6 total), plus lengths of r and s
	length := 6 + len(rb) + len(sb)
	b := make([]byte, length, length)

	b[0] = 0x30
	b[1] = byte(length - 2)
	b[2] = 0x02
	b[3] = byte(len(rb))
	offset := copy(b[4:], rb) + 4
	b[offset] = 0x02
	b[offset+1] = byte(len(sb))
	copy(b[offset+2:], sb)
	return b
}

func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) {
	// Originally this code used encoding/asn1 in order to parse the
	// signature, but a number of problems were found with this approach.
	// Despite the fact that signatures are stored as DER, the difference
	// between go's idea of a bignum (and that they have sign) doesn't agree
	// with the openssl one (where they do not). The above is true as of
	// Go 1.1. In the end it was simpler to rewrite the code to explicitly
	// understand the format which is this:
	// 0x30 <length of whole message> <0x02> <length of R> <R> 0x2
	// <length of S> <S>.

	signature := &Signature{}

	// minimal message is when both numbers are 1 bytes. adding up to:
	// 0x30 + len + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
	if len(sigStr) < 8 {
		return nil, errors.New("malformed signature: too short")
	}
	// 0x30
	index := 0
	if sigStr[index] != 0x30 {
		return nil, errors.New("malformed signature: no header magic")
	}
	index++
	// length of remaining message
	siglen := sigStr[index]
	index++
	if int(siglen+2) > len(sigStr) {
		return nil, errors.New("malformed signature: bad length")
	}
	// trim the slice we're working on so we only look at what matters.
	sigStr = sigStr[:siglen+2]

	// 0x02
	if sigStr[index] != 0x02 {
		return nil,
			errors.New("malformed signature: no 1st int marker")
	}
	index++

	// Length of signature R.
	rLen := int(sigStr[index])
	// must be positive, must be able to fit in another 0x2, <len> <s>
	// hence the -3. We assume that the length must be at least one byte.
	index++
	if rLen <= 0 || rLen > len(sigStr)-index-3 {
		return nil, errors.New("malformed signature: bogus R length")
	}

	// Then R itself.
	rBytes := sigStr[index : index+rLen]
	if der {
		switch err := canonicalPadding(rBytes); err {
		case errNegativeValue:
			return nil, errors.New("signature R is negative")
		case errExcessivelyPaddedValue:
			return nil, errors.New("signature R is excessively padded")
		}
	}
	signature.R = new(big.Int).SetBytes(rBytes)
	index += rLen
	// 0x02. length already checked in previous if.
	if sigStr[index] != 0x02 {
		return nil, errors.New("malformed signature: no 2nd int marker")
	}
	index++

	// Length of signature S.
	sLen := int(sigStr[index])
	index++
	// S should be the rest of the string.
	if sLen <= 0 || sLen > len(sigStr)-index {
		return nil, errors.New("malformed signature: bogus S length")
	}

	// Then S itself.
	sBytes := sigStr[index : index+sLen]
	if der {
		switch err := canonicalPadding(sBytes); err {
		case errNegativeValue:
			return nil, errors.New("signature S is negative")
		case errExcessivelyPaddedValue:
			return nil, errors.New("signature S is excessively padded")
		}
	}
	signature.S = new(big.Int).SetBytes(sBytes)
	index += sLen

	// sanity check length parsing
	if index != len(sigStr) {
		return nil, fmt.Errorf("malformed signature: bad final length %v != %v",
			index, len(sigStr))
	}

	// Verify also checks this, but we can be more sure that we parsed
	// correctly if we verify here too.
	// FWIW the ecdsa spec states that R and S must be | 1, N - 1 |
	// but crypto/ecdsa only checks for Sign != 0. Mirror that.
	if signature.R.Sign() != 1 {
		return nil, errors.New("signature R isn't 1 or more")
	}
	if signature.S.Sign() != 1 {
		return nil, errors.New("signature S isn't 1 or more")
	}
	if signature.R.Cmp(curve.Params().N) >= 0 {
		return nil, errors.New("signature R is >= curve.N")
	}
	if signature.S.Cmp(curve.Params().N) >= 0 {
		return nil, errors.New("signature S is >= curve.N")
	}

	return signature, nil
}

// ParseSignature parses a signature in BER format for the curve type `curve'
// into a Signature type, perfoming some basic sanity checks.  If parsing
// according to the more strict DER format is needed, use ParseDERSignature.
func ParseSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
	return parseSig(sigStr, curve, false)
}

// ParseDERSignature parses a signature in DER format for the curve type
// `curve` into a Signature type.  If parsing according to the less strict
// BER format is needed, use ParseSignature.
func ParseDERSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
	return parseSig(sigStr, curve, true)
}

// canonicalizeInt returns the bytes for the passed big integer adjusted as
// necessary to ensure that a big-endian encoded integer can't possibly be
// misinterpreted as a negative number.  This can happen when the most
// significant bit is set, so it is padded by a leading zero byte in this case.
// Also, the returned bytes will have at least a single byte when the passed
// value is 0.  This is required for DER encoding.
func canonicalizeInt(val *big.Int) []byte {
	b := val.Bytes()
	if len(b) == 0 {
		b = []byte{0x00}
	}
	if b[0]&0x80 != 0 {
		paddedBytes := make([]byte, len(b)+1)
		copy(paddedBytes[1:], b)
		b = paddedBytes
	}
	return b
}

// canonicalPadding checks whether a big-endian encoded integer could
// possibly be misinterpreted as a negative number (even though OpenSSL
// treats all numbers as unsigned), or if there is any unnecessary
// leading zero padding.
func canonicalPadding(b []byte) error {
	switch {
	case b[0]&0x80 == 0x80:
		return errNegativeValue
	case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80:
		return errExcessivelyPaddedValue
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package sessions

import (
	"bytes"
	"encoding/gob"
	"github.com/garyburd/redigo/redis"
	"net/http"
)

var sessionExpire = 86400 * 30

type RedisStore struct {
	*http.Cookie
	*redis.Pool
	exitChannel   chan int
	queryChannel  chan *RedisQuery
	DefaultMaxAge int
}

func NewRedisStore(network, address, password string) *RedisStore {
	con := func() (redis.Conn, error) {
		c, err := redis.Dial(network, address)
		if err != nil {
			return nil, err
		}
		if password != "" {
			if _, err := c.Do("AUTH", password); err != nil {
				c.Close()
				return nil, err
			}
		}
		return c, err
	}
	return &RedisStore{
		Pool: redis.NewPool(con, 3),
		Cookie: &http.Cookie{
			Path:   "/",
			MaxAge: sessionExpire,
		},
		DefaultMaxAge: sessionExpire,
	}
}

type RedisQuery struct {
	Action        string
	Options       []interface{}
	resultChannel chan *QueryResult
}

type QueryResult struct {
	Err   error
	Value interface{}
}

func (q *RedisStore) Run() {
	con := q.Pool.Get()
	defer con.Close()
	for {
		select {
		case <-q.exitChannel:
			return
		case query := <-q.queryChannel:
			value, err := con.Do(query.Action, query.Options...)
			if err != nil && err != redis.ErrNil {
				con.Close()
				con = q.Pool.Get()
			}
			query.resultChannel <- &QueryResult{
				Err:   err,
				Value: value,
			}
		}
	}
}

func (q *RedisStore) Stop() {
	close(q.exitChannel)
	q.Pool.Close()
}

func (q *RedisStore) Get(r *http.Request, name string) (*Session, error) {
	c, err := r.Cookie(name)
	var s *Session
	if err != nil {
		return s, err
	}
	s = &Session{
		Cookie: c,
		Values: make(map[interface{}]interface{}),
	}
	query := &RedisQuery{
		Action:        "GET",
		Options:       []interface{}{"session_:" + c.Value},
		resultChannel: make(chan *QueryResult),
	}
	q.queryChannel <- query
	queryresult := <-query.resultChannel
	value, err := redis.Bytes(queryresult.Value, queryresult.Err)
	if err == nil {
		dec := gob.NewDecoder(bytes.NewBuffer(value))
		dec.Decode(&s.Values)
	}
	return s, err
}

func (q *RedisStore) Set(r *http.Request, w http.ResponseWriter, session *Session) error {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(session.Values)
	if err != nil {
		return err
	}
	b := buf.Bytes()
	age := session.MaxAge
	query := &RedisQuery{
		Action:        "SETEX",
		Options:       []interface{}{"session_:" + session.Value, age, b},
		resultChannel: make(chan *QueryResult),
	}
	q.queryChannel <- query
	queryresult := <-query.resultChannel
	if queryresult.Err == nil {
		http.SetCookie(w, session.Cookie)
	}
	return queryresult.Err
}
<commit_msg>init channel<commit_after>package sessions

import (
	"bytes"
	"encoding/gob"
	"github.com/garyburd/redigo/redis"
	"net/http"
)

var sessionExpire = 86400 * 30

type RedisStore struct {
	*http.Cookie
	*redis.Pool
	exitChannel   chan int
	queryChannel  chan *RedisQuery
	DefaultMaxAge int
}

func NewRedisStore(network, address, password string) *RedisStore {
	con := func() (redis.Conn, error) {
		c, err := redis.Dial(network, address)
		if err != nil {
			return nil, err
		}
		if password != "" {
			if _, err := c.Do("AUTH", password); err != nil {
				c.Close()
				return nil, err
			}
		}
		return c, err
	}
	return &RedisStore{
		Pool:         redis.NewPool(con, 3),
		exitChannel:  make(chan int),
		queryChannel: make(chan *RedisQuery),
		Cookie: &http.Cookie{
			Path:   "/",
			MaxAge: sessionExpire,
		},
		DefaultMaxAge: sessionExpire,
	}
}

type RedisQuery struct {
	Action        string
	Options       []interface{}
	resultChannel chan *QueryResult
}

type QueryResult struct {
	Err   error
	Value interface{}
}

func (q *RedisStore) Run() {
	con := q.Pool.Get()
	defer con.Close()
	for {
		select {
		case <-q.exitChannel:
			return
		case query := <-q.queryChannel:
			value, err := con.Do(query.Action, query.Options...)
			if err != nil && err != redis.ErrNil {
				con.Close()
				con = q.Pool.Get()
			}
			query.resultChannel <- &QueryResult{
				Err:   err,
				Value: value,
			}
		}
	}
}

func (q *RedisStore) Stop() {
	close(q.exitChannel)
	q.Pool.Close()
}

func (q *RedisStore) Get(r *http.Request, name string) (*Session, error) {
	c, err := r.Cookie(name)
	var s *Session
	if err != nil {
		return s, err
	}
	s = &Session{
		Cookie: c,
		Values: make(map[interface{}]interface{}),
	}
	query := &RedisQuery{
		Action:        "GET",
		Options:       []interface{}{"session_:" + c.Value},
		resultChannel: make(chan *QueryResult),
	}
	q.queryChannel <- query
	queryresult := <-query.resultChannel
	value, err := redis.Bytes(queryresult.Value, queryresult.Err)
	if err == nil {
		dec := gob.NewDecoder(bytes.NewBuffer(value))
		dec.Decode(&s.Values)
	}
	return s, err
}

func (q *RedisStore) Set(r *http.Request, w http.ResponseWriter, session *Session) error {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(session.Values)
	if err != nil {
		return err
	}
	b := buf.Bytes()
	age := session.MaxAge
	query := &RedisQuery{
		Action:        "SETEX",
		Options:       []interface{}{"session_:" + session.Value, age, b},
		resultChannel: make(chan *QueryResult),
	}
	q.queryChannel <- query
	queryresult := <-query.resultChannel
	if queryresult.Err == nil {
		http.SetCookie(w, session.Cookie)
	}
	return queryresult.Err
}
<|endoftext|>


<commit_before>// Copyright 2012 Brian "bojo" Jones. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package redistore

import (
	"encoding/base32"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"net/http"
	"strings"
	"time"
)

// Amount of time for cookies/redis keys to expire.
var sessionExpire int = 86400 * 30

// RediStore stores sessions in a redis backend.
type RediStore struct {
	Pool    *redis.Pool
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
}

// NewRediStore returns a new RediStore.
func NewRediStore(size int, network, address, password string, keyPairs ...[]byte) *RediStore {
	return &RediStore{
		// http://godoc.org/github.com/garyburd/redigo/redis#Pool
		Pool: &redis.Pool{
			MaxIdle:     size,
			IdleTimeout: 240 * time.Second,
			Dial: func() (redis.Conn, error) {
				c, err := redis.Dial(network, address)
				if err != nil {
					return nil, err
				}
				if password != "" {
					if _, err := c.Do("AUTH", password); err != nil {
						c.Close()
						return nil, err
					}
				}
				return c, err
			},
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				_, err := c.Do("PING")
				return err
			},
		},
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: sessionExpire,
		},
	}
}

// Close cleans up the redis connections.
func (s *RediStore) Close() {
	s.Pool.Close()
}

// Get returns a session for the given name after adding it to the registry.
//
// See gorilla/sessions FilesystemStore.Get().
func (s *RediStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See gorilla/sessions FilesystemStore.New().
func (s *RediStore) New(r *http.Request, name string) (*sessions.Session, error) {
	var err error
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	// Build an alphanumeric key for the redis store.
	session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=")
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.Values, s.Codecs...)
		if err == nil {
			err = s.load(session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *RediStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	encoded, err := securecookie.EncodeMulti(session.Name(), &session.Values, s.Codecs...)
	if err != nil {
		return err
	}
	if err := s.save(session, encoded); err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// Delete removes the session from redis, and sets the cookie to expire.
func (s *RediStore) Delete(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	conn := s.Pool.Get()
	defer conn.Close()
	if _, err := conn.Do("DEL", "session_"+session.ID); err != nil {
		return err
	}
	// Set cookie to expire.
	options := session.Options
	options.MaxAge = -1
	http.SetCookie(w, sessions.NewCookie(session.Name(), "", options))
	// Clear session values.
	for k := range session.Values {
		delete(session.Values, k)
	}
	return nil
}

// save stores the session in redis.
func (s *RediStore) save(session *sessions.Session, encoded string) error {
	conn := s.Pool.Get()
	defer conn.Close()
	conn.Send("SET", "session_"+session.ID, encoded)
	conn.Send("EXPIRE", "session_"+session.ID, sessionExpire)
	conn.Flush()
	if _, err := conn.Receive(); err != nil { // SET
		return err
	}
	if _, err := conn.Receive(); err != nil { // EXPIRE
		return err
	}
	return nil
}

// load reads the session from redis.
func (s *RediStore) load(session *sessions.Session) error {
	conn := s.Pool.Get()
	defer conn.Close()
	if err := conn.Err(); err != nil {
		return err
	}
	data, err := conn.Do("GET", "session_"+session.ID)
	if err != nil {
		return err
	}
	if data == nil {
		return nil // no data was associated with this key
	}
	str, err := redis.String(data, err)
	if err != nil {
		return err
	}
	if err = securecookie.DecodeMulti(session.Name(), str, &session.Values, s.Codecs...); err != nil {
		return err
	}
	return nil
}
<commit_msg>keys on save<commit_after>// Copyright 2012 Brian "bojo" Jones. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package redistore

import (
	"encoding/base32"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"net/http"
	"strings"
	"time"
)

// Amount of time for cookies/redis keys to expire.
var sessionExpire int = 86400 * 30

// RediStore stores sessions in a redis backend.
type RediStore struct {
	Pool    *redis.Pool
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
}

// NewRediStore returns a new RediStore.
func NewRediStore(size int, network, address, password string, keyPairs ...[]byte) *RediStore {
	return &RediStore{
		// http://godoc.org/github.com/garyburd/redigo/redis#Pool
		Pool: &redis.Pool{
			MaxIdle:     size,
			IdleTimeout: 240 * time.Second,
			Dial: func() (redis.Conn, error) {
				c, err := redis.Dial(network, address)
				if err != nil {
					return nil, err
				}
				if password != "" {
					if _, err := c.Do("AUTH", password); err != nil {
						c.Close()
						return nil, err
					}
				}
				return c, err
			},
			TestOnBorrow: func(c redis.Conn, t time.Time) error {
				_, err := c.Do("PING")
				return err
			},
		},
		Codecs: securecookie.CodecsFromPairs(keyPairs...),
		Options: &sessions.Options{
			Path:   "/",
			MaxAge: sessionExpire,
		},
	}
}

// Close cleans up the redis connections.
func (s *RediStore) Close() {
	s.Pool.Close()
}

// Get returns a session for the given name after adding it to the registry.
//
// See gorilla/sessions FilesystemStore.Get().
func (s *RediStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(s, name)
}

// New returns a session for the given name without adding it to the registry.
//
// See gorilla/sessions FilesystemStore.New().
func (s *RediStore) New(r *http.Request, name string) (*sessions.Session, error) {
	var err error
	session := sessions.NewSession(s, name)
	session.Options = &(*s.Options)
	session.IsNew = true
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.Values, s.Codecs...)
		if err == nil {
			err = s.load(session)
			if err == nil {
				session.IsNew = false
			}
		}
	}
	return session, err
}

// Save adds a single session to the response.
func (s *RediStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	// Build an alphanumeric key for the redis store.
	if session.ID == "" {
		session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=")
	}
	encoded, err := securecookie.EncodeMulti(session.Name(), &session.Values, s.Codecs...)
	if err != nil {
		return err
	}
	if err := s.save(session, encoded); err != nil {
		return err
	}
	http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
	return nil
}

// Delete removes the session from redis, and sets the cookie to expire.
func (s *RediStore) Delete(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	conn := s.Pool.Get()
	defer conn.Close()
	if _, err := conn.Do("DEL", "session_"+session.ID); err != nil {
		return err
	}
	// Set cookie to expire.
	options := session.Options
	options.MaxAge = -1
	http.SetCookie(w, sessions.NewCookie(session.Name(), "", options))
	// Clear session values.
	for k := range session.Values {
		delete(session.Values, k)
	}
	return nil
}

// save stores the session in redis.
func (s *RediStore) save(session *sessions.Session, encoded string) error {
	conn := s.Pool.Get()
	defer conn.Close()
	conn.Send("SET", "session_"+session.ID, encoded)
	conn.Send("EXPIRE", "session_"+session.ID, sessionExpire)
	conn.Flush()
	if _, err := conn.Receive(); err != nil { // SET
		return err
	}
	if _, err := conn.Receive(); err != nil { // EXPIRE
		return err
	}
	return nil
}

// load reads the session from redis.
func (s *RediStore) load(session *sessions.Session) error {
	conn := s.Pool.Get()
	defer conn.Close()
	if err := conn.Err(); err != nil {
		return err
	}
	data, err := conn.Do("GET", "session_"+session.ID)
	if err != nil {
		return err
	}
	if data == nil {
		return nil // no data was associated with this key
	}
	str, err := redis.String(data, err)
	if err != nil {
		return err
	}
	if err = securecookie.DecodeMulti(session.Name(), str, &session.Values, s.Codecs...); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package nessie

// Editor resources.

// Template is used to create scans or policies with predefined parameters.
type Template struct {
	// The uuid for the template.
	UUID string `json:"uuid"`
	// The short name of the template.
	Name string `json:"name"`
	// The long name of the template.
	Title string `json:"title"`
	// The description of the template.
	Desc string `json:"description"`
	// If true, template is only available on the cloud.
	CloudOnly bool `json:"cloud_only"`
	// If true, the template is only available for subscribers.
	SubscriptionOnly bool `json:"subscription_only"`
	// An external URL to link the template to.
	MoreInfo string `json:"more_info"`
}

type TemplateFormInput struct {
	ID      string   `json:"id"`
	Type    string   `json:"type"`
	Label   string   `json:"label"`
	Default string   `json:"default"`
	Options []string `json:"options"`
}

type TemplateDisplayGroup struct {
	Name     string   `json:"name"`
	Title    string   `json:"title"`
	Inputs   []string `json:"inputs"`
	Sections []string `json:"sections"`
}

type TemplateSection struct {
	Name   string   `json:"name"`
	Title  string   `json:"title"`
	Inputs []string `json:"inputs"`
}

type TemplateMode struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Desc string `json:"desc"`
}

type TemplatePluginFamily struct {
	ID     int64  `json:"id"`
	Count  int64  `json:"count"`
	Status string `json:"status"`
}

type Filter struct {
	Name         string           `json:"name"`
	ReadableName string           `json:"readable_name"`
	Operators    []string         `json:"operators"`
	Controls     []FilterControls `json:"controls"`
}

type FilterControls struct {
	Type          string   `json:"type"`
	ReadableRegex string   `json:"readable_regest"`
	Regex         string   `json:"regex"`
	Ooptions      []string `json:"options"`
}

// Folders resources.

type Folder struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Type        string `json:"type"`
	DefaultTag  int64  `json:"default_tag"`
	Custom      int64  `json:"custom"`
	UnreadCount int64  `json:"unread_count"`
}

// Groups resources.

type Group struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Permissions int64  `json:"permissions"`
	UserCount   int64  `json:"user_count"`
}

// Permissions resources.

type Permission struct {
	Owner       int64  `json:"owner"`
	Type        string `json:"type"`
	Permissions int64  `json:"permissions"`
	ID          int64  `json:"id"`
	Name        string `json:"name"`
}

// Plugins resources.

type PluginAttr struct {
	Name string `json:"attribute_name"`
	Val  string `json:"attribute_value"`
}

type PluginFamily struct {
	ID    int64  `json:"id"`
	Name  string `json:"name"`
	Count int64  `json:"count"`
}

type Plugin struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

// Plugin-rules resources.

type Rule struct {
	ID       int64  `json:"id"`
	PluginID int64  `json:"plugin_id"`
	Date     string `json:"date"`
	Host     string `json:"host"`
	Type     string `json:"type"`
	Owner    string `json:"owner"`
	OwnerID  int64  `json:"owner_id"`
}

// Policies resources.

type Policy struct {
	ID                   int64  `json:"id"`
	TemplateUUID         string `json:"template_uuid"`
	Name                 string `json:"uuid"`
	Desc                 string `json:"description"`
	OwnerID              int64  `json:"owner_id"`
	Owner                string `json:"owner"`
	Shared               int64  `json:"shared"`
	UserPerms            int64  `json:"user_permissions"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
	Visibility           int64  `json:"visibility"`
	NoTarget             bool   `json:"no_target"`
}

// Scanners resources.

type Scanner struct {
	ID               int64  `json:"id"`
	UUID             string `json:"uuid"`
	Name             string `json:"name"`
	Type             string `json:"type"`
	Status           string `json:"status"`
	ScanCount        int64  `json:"scan_count"`
	EngineVersion    string `json:"engine_version"`
	Platform         string `json:"platform"`
	LoadedPluginSet  string `json:"loaded_plugin_set"`
	RegistrationCode string `json:"registration_code"`
	Owner            string `json:"owner"`
}

// Scans resources.

type Scan struct {
	ID                   int64  `json:"id"`
	UUID                 string `json:"uuid"`
	Name                 string `json:"name"`
	Owner                string `json:"owner"`
	FolderID             int64  `json:"folder_id"`
	Read                 bool   `json:"read"`
	Status               string `json:"status"`
	Shared               bool   `json:"shared"`
	UserPerms            int64  `json:"user_permissions"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
	Control              bool   `json:"control"`
	StartTime            string `json:"starttime"`
	TimeZone             string `json:"timezone"`
	RRules               string `json:"rrules"`
}

type Host struct {
	HostID                int64  `json:"host_id"`
	HostIdx               int64  `json:"host_index"`
	Hostname              string `json:"hostname"`
	Progress              string `json:"progress"`
	Critical              int64  `json:"critical"`
	High                  int64  `json:"high"`
	Medium                int64  `json:"medium"`
	Low                   int64  `json:"low"`
	Info                  int64  `json:"info"`
	TotalChecksConsidered int64  `json:"totalchecksconsidered"`
	NumChecksConsidered   int64  `json:"numchecksconsidered"`
	ScanProgressTotal     int64  `json:"scanprogresstotal"`
	ScanProgressCurrent   int64  `json:"scanprogresscurrent"`
	Score                 int64  `json:"score"`
}

type Note struct {
	Title    string `json:"title"`
	Message  string `json:"message"`
	Severity int64  `json:"severity"`
}

type Remediation struct {
	Value       string `json:"value"`
	Remediation string `json:"remediation"`
	NumHosts    int64  `json:"hosts"`
	NumVulns    string `json:"vulns"`
}

type History struct {
	HistoryID            int64  `json:"history_id"`
	UUID                 string `json:"uuid"`
	OwnerID              int64  `json:"owner_id"`
	Status               string `json:"status"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
}

type Vulnerability struct {
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	VulnIdx      int64  `json:"vuln_index"`
	SeverityIdx  int64  `json:"severity_index"`
}

type HostVulnerability struct {
	HostID       int64  `json:"host_id"`
	Hostname     string `json:"hostname"`
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	VulnIdx      int64  `json:"vuln_index"`
	SeverityIdx  int64  `json:"severity_index"`
	Severity     int64  `json:"severity"`
}

type HostCompliance struct {
	HostID       int64  `json:"host_id"`
	Hostname     string `json:"hostname"`
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	SeverityIdx  int64  `json:"severity_index"`
	Severity     int64  `json:"severity"`
}

type PluginOutput struct {
	PluginOutput string   `json:"plugin_output"`
	Hosts        string   `json:"hosts"`
	Severity     int64    `json:"severity"`
	Ports        []string `json:"ports"`
}

type TimeZone struct {
	Name string `json:"name"`
	Val  string `json:"value"`
}

// Sessions resources.

type Session struct {
	ID          int64    `json:"id"`
	Username    string   `json:"username"`
	Email       string   `json:"email"`
	Name        string   `json:"name"`
	Type        string   `json:"type"`
	Perms       int64    `json:"permissions"`
	LastLogin   int64    `json:"last_login"`
	ContainerID int64    `json:"container_id"`
	Groups      []string `json:"groups"`
}

type User struct {
	ID          int    `json:"id"`
	Username    string `json:"username"`
	Name        string `json:"name"`
	Email       string `json:"email"`
	Permissions int    `json:"permissions"`
	LastLogin   int    `json:"lastlogin"`
	Type        string `json:"type"`
}
<commit_msg>Adding a new PluginFamilies resource to match the new API definition<commit_after>package nessie

// Editor resources.

// Template is used to create scans or policies with predefined parameters.
type Template struct {
	// The uuid for the template.
	UUID string `json:"uuid"`
	// The short name of the template.
	Name string `json:"name"`
	// The long name of the template.
	Title string `json:"title"`
	// The description of the template.
	Desc string `json:"description"`
	// If true, template is only available on the cloud.
	CloudOnly bool `json:"cloud_only"`
	// If true, the template is only available for subscribers.
	SubscriptionOnly bool `json:"subscription_only"`
	// An external URL to link the template to.
	MoreInfo string `json:"more_info"`
}

type TemplateFormInput struct {
	ID      string   `json:"id"`
	Type    string   `json:"type"`
	Label   string   `json:"label"`
	Default string   `json:"default"`
	Options []string `json:"options"`
}

type TemplateDisplayGroup struct {
	Name     string   `json:"name"`
	Title    string   `json:"title"`
	Inputs   []string `json:"inputs"`
	Sections []string `json:"sections"`
}

type TemplateSection struct {
	Name   string   `json:"name"`
	Title  string   `json:"title"`
	Inputs []string `json:"inputs"`
}

type TemplateMode struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Desc string `json:"desc"`
}

type TemplatePluginFamily struct {
	ID     int64  `json:"id"`
	Count  int64  `json:"count"`
	Status string `json:"status"`
}

type Filter struct {
	Name         string           `json:"name"`
	ReadableName string           `json:"readable_name"`
	Operators    []string         `json:"operators"`
	Controls     []FilterControls `json:"controls"`
}

type FilterControls struct {
	Type          string   `json:"type"`
	ReadableRegex string   `json:"readable_regest"`
	Regex         string   `json:"regex"`
	Ooptions      []string `json:"options"`
}

// Folders resources.

type Folder struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Type        string `json:"type"`
	DefaultTag  int64  `json:"default_tag"`
	Custom      int64  `json:"custom"`
	UnreadCount int64  `json:"unread_count"`
}

// Groups resources.

type Group struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Permissions int64  `json:"permissions"`
	UserCount   int64  `json:"user_count"`
}

// Permissions resources.

type Permission struct {
	Owner       int64  `json:"owner"`
	Type        string `json:"type"`
	Permissions int64  `json:"permissions"`
	ID          int64  `json:"id"`
	Name        string `json:"name"`
}

// Plugins resources.

type PluginAttr struct {
	Name string `json:"attribute_name"`
	Val  string `json:"attribute_value"`
}

type PluginFamily struct {
	ID    int64  `json:"id"`
	Name  string `json:"name"`
	Count int64  `json:"count"`
}

type PluginFamilies struct {
	Families []PluginFamily  `json:"families"`
}

type Plugin struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
}

// Plugin-rules resources.

type Rule struct {
	ID       int64  `json:"id"`
	PluginID int64  `json:"plugin_id"`
	Date     string `json:"date"`
	Host     string `json:"host"`
	Type     string `json:"type"`
	Owner    string `json:"owner"`
	OwnerID  int64  `json:"owner_id"`
}

// Policies resources.

type Policy struct {
	ID                   int64  `json:"id"`
	TemplateUUID         string `json:"template_uuid"`
	Name                 string `json:"uuid"`
	Desc                 string `json:"description"`
	OwnerID              int64  `json:"owner_id"`
	Owner                string `json:"owner"`
	Shared               int64  `json:"shared"`
	UserPerms            int64  `json:"user_permissions"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
	Visibility           int64  `json:"visibility"`
	NoTarget             bool   `json:"no_target"`
}

// Scanners resources.

type Scanner struct {
	ID               int64  `json:"id"`
	UUID             string `json:"uuid"`
	Name             string `json:"name"`
	Type             string `json:"type"`
	Status           string `json:"status"`
	ScanCount        int64  `json:"scan_count"`
	EngineVersion    string `json:"engine_version"`
	Platform         string `json:"platform"`
	LoadedPluginSet  string `json:"loaded_plugin_set"`
	RegistrationCode string `json:"registration_code"`
	Owner            string `json:"owner"`
}

// Scans resources.

type Scan struct {
	ID                   int64  `json:"id"`
	UUID                 string `json:"uuid"`
	Name                 string `json:"name"`
	Owner                string `json:"owner"`
	FolderID             int64  `json:"folder_id"`
	Read                 bool   `json:"read"`
	Status               string `json:"status"`
	Shared               bool   `json:"shared"`
	UserPerms            int64  `json:"user_permissions"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
	Control              bool   `json:"control"`
	StartTime            string `json:"starttime"`
	TimeZone             string `json:"timezone"`
	RRules               string `json:"rrules"`
}

type Host struct {
	HostID                int64  `json:"host_id"`
	HostIdx               int64  `json:"host_index"`
	Hostname              string `json:"hostname"`
	Progress              string `json:"progress"`
	Critical              int64  `json:"critical"`
	High                  int64  `json:"high"`
	Medium                int64  `json:"medium"`
	Low                   int64  `json:"low"`
	Info                  int64  `json:"info"`
	TotalChecksConsidered int64  `json:"totalchecksconsidered"`
	NumChecksConsidered   int64  `json:"numchecksconsidered"`
	ScanProgressTotal     int64  `json:"scanprogresstotal"`
	ScanProgressCurrent   int64  `json:"scanprogresscurrent"`
	Score                 int64  `json:"score"`
}

type Note struct {
	Title    string `json:"title"`
	Message  string `json:"message"`
	Severity int64  `json:"severity"`
}

type Remediation struct {
	Value       string `json:"value"`
	Remediation string `json:"remediation"`
	NumHosts    int64  `json:"hosts"`
	NumVulns    string `json:"vulns"`
}

type History struct {
	HistoryID            int64  `json:"history_id"`
	UUID                 string `json:"uuid"`
	OwnerID              int64  `json:"owner_id"`
	Status               string `json:"status"`
	CreationDate         int64  `json:"creation_date"`
	LastModificationDate int64  `json:"last_modification_date"`
}

type Vulnerability struct {
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	VulnIdx      int64  `json:"vuln_index"`
	SeverityIdx  int64  `json:"severity_index"`
}

type HostVulnerability struct {
	HostID       int64  `json:"host_id"`
	Hostname     string `json:"hostname"`
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	VulnIdx      int64  `json:"vuln_index"`
	SeverityIdx  int64  `json:"severity_index"`
	Severity     int64  `json:"severity"`
}

type HostCompliance struct {
	HostID       int64  `json:"host_id"`
	Hostname     string `json:"hostname"`
	PluginID     int64  `json:"plugin_id"`
	PluginName   string `json:"plugin_name"`
	PluginFamily string `json:"plugin_family"`
	Count        int64  `json:"count"`
	SeverityIdx  int64  `json:"severity_index"`
	Severity     int64  `json:"severity"`
}

type PluginOutput struct {
	PluginOutput string   `json:"plugin_output"`
	Hosts        string   `json:"hosts"`
	Severity     int64    `json:"severity"`
	Ports        []string `json:"ports"`
}

type TimeZone struct {
	Name string `json:"name"`
	Val  string `json:"value"`
}

// Sessions resources.

type Session struct {
	ID          int64    `json:"id"`
	Username    string   `json:"username"`
	Email       string   `json:"email"`
	Name        string   `json:"name"`
	Type        string   `json:"type"`
	Perms       int64    `json:"permissions"`
	LastLogin   int64    `json:"last_login"`
	ContainerID int64    `json:"container_id"`
	Groups      []string `json:"groups"`
}

type User struct {
	ID          int    `json:"id"`
	Username    string `json:"username"`
	Name        string `json:"name"`
	Email       string `json:"email"`
	Permissions int    `json:"permissions"`
	LastLogin   int    `json:"lastlogin"`
	Type        string `json:"type"`
}
<|endoftext|>