<commit_before>package diff

import (
	"bytes"
	"io"
	"reflect"

	"github.com/deckarep/golang-set"
	"github.com/schemalex/schemalex"
	"github.com/schemalex/schemalex/internal/errors"
	"github.com/schemalex/schemalex/model"
)

type Option interface {
	Name() string
	Value() interface{}
}

type option struct {
	name  string
	value interface{}
}

func (o option) Name() string       { return o.name }
func (o option) Value() interface{} { return o.value }

func WithParser(p *schemalex.Parser) Option {
	return &option{
		name:  "parser",
		value: p,
	}
}

func WithTransaction(b bool) Option {
	return &option{
		name:  "transaction",
		value: b,
	}
}

type diffCtx struct {
	fromSet mapset.Set
	toSet   mapset.Set
	from    model.Stmts
	to      model.Stmts
}

func newDiffCtx(from, to model.Stmts) *diffCtx {
	fromSet := mapset.NewSet()
	for _, stmt := range from {
		if cs, ok := stmt.(model.Table); ok {
			fromSet.Add(cs.ID())
		}
	}
	toSet := mapset.NewSet()
	for _, stmt := range to {
		if cs, ok := stmt.(model.Table); ok {
			toSet.Add(cs.ID())
		}
	}

	return &diffCtx{
		fromSet: fromSet,
		toSet:   toSet,
		from:    from,
		to:      to,
	}
}

func Statements(dst io.Writer, from, to model.Stmts, options ...Option) error {
	var txn bool
	for _, o := range options {
		switch o.Name() {
		case "transaction":
			txn = o.Value().(bool)
		}
	}

	ctx := newDiffCtx(from, to)

	var procs = []func(*diffCtx, io.Writer) (int64, error){
		dropTables,
		createTables,
		alterTables,
	}

	var buf bytes.Buffer
	if txn {
		buf.WriteString("\nBEGIN;\n\nSET FOREIGN_KEY_CHECKS = 0;")
	}

	for _, p := range procs {
		var pbuf bytes.Buffer
		n, err := p(ctx, &pbuf)
		if err != nil {
			return errors.Wrap(err, `failed to produce diff`)
		}
		if txn && n > 0 || !txn && buf.Len() > 0 && n > 0 {
			buf.WriteString("\n\n")
		}
		pbuf.WriteTo(&buf)
	}
	if txn {
		buf.WriteString("\n\nSET FOREIGN_KEY_CHECKS = 1;\n\nCOMMIT;")
	}

	if _, err := buf.WriteTo(dst); err != nil {
		return errors.Wrap(err, `failed to write diff`)
	}
	return nil
}

func Strings(dst io.Writer, from, to string, options ...Option) error {
	var p *schemalex.Parser
	for _, o := range options {
		switch o.Name() {
		case "parser":
			p = o.Value().(*schemalex.Parser)
		}
	}
	if p == nil {
		p = schemalex.New()
	}

	stmts1, err := p.ParseString(from)
	if err != nil {
		return errors.Wrapf(err, `failed to parse "from" %s`, from)
	}

	stmts2, err := p.ParseString(to)
	if err != nil {
		return errors.Wrapf(err, `failed to parse "to" %s`, to)
	}

	return Statements(dst, stmts1, stmts2, options...)
}

func Files(dst io.Writer, from, to string, options ...Option) error {
	var p *schemalex.Parser
	for _, o := range options {
		switch o.Name() {
		case "parser":
			p = o.Value().(*schemalex.Parser)
		}
	}
	if p == nil {
		p = schemalex.New()
	}
	stmts1, err := p.ParseFile(from)
	if err != nil {
		return errors.Wrapf(err, `failed to open "from" file %s`, from)
	}

	stmts2, err := p.ParseFile(to)
	if err != nil {
		return errors.Wrapf(err, `failed to open "to" file %s`, to)
	}

	return Statements(dst, stmts1, stmts2, options...)
}

func dropTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	ids := ctx.fromSet.Difference(ctx.toSet)
	for i, id := range ids.ToSlice() {
		if i > 0 {
			buf.WriteByte('\n')
		}

		stmt, ok := ctx.from.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`failed to lookup table %s`, id)
		}

		table, ok := stmt.(model.Table)
		if !ok {
			return 0, errors.Errorf(`lookup failed: %s is not a model.Table`, id)
		}
		buf.WriteString("DROP TABLE `")
		buf.WriteString(table.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func createTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer

	names := ctx.toSet.Difference(ctx.fromSet)
	for _, name := range names.ToSlice() {
		// Lookup the corresponding statement, and add its SQL
		stmt, ok := ctx.to.Lookup(name.(string))
		if !ok {
			continue
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		_, err := stmt.WriteTo(&buf)
		if err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}
	return buf.WriteTo(dst)
}

type alterCtx struct {
	fromColumns mapset.Set
	toColumns   mapset.Set
	fromIndexes mapset.Set
	toIndexes   mapset.Set
	from        model.Table
	to          model.Table
}

func newAlterCtx(from, to model.Table) *alterCtx {
	fromColumns := mapset.NewSet()
	for col := range from.Columns() {
		fromColumns.Add(col.ID())
	}

	toColumns := mapset.NewSet()
	for col := range to.Columns() {
		toColumns.Add(col.ID())
	}

	fromIndexes := mapset.NewSet()
	for idx := range from.Indexes() {
		fromIndexes.Add(idx.ID())
	}

	toIndexes := mapset.NewSet()
	for idx := range to.Indexes() {
		toIndexes.Add(idx.ID())
	}

	return &alterCtx{
		fromColumns: fromColumns,
		toColumns:   toColumns,
		fromIndexes: fromIndexes,
		toIndexes:   toIndexes,
		from:        from,
		to:          to,
	}
}

func alterTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	procs := []func(*alterCtx, io.Writer) (int64, error){
		dropTableColumns,
		addTableColumns,
		alterTableColumns,
		dropTableIndexes,
		addTableIndexes,
	}

	ids := ctx.toSet.Intersect(ctx.fromSet)
	var buf bytes.Buffer
	for _, id := range ids.ToSlice() {
		var stmt model.Stmt
		var ok bool

		stmt, ok = ctx.from.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`table '%s' not found in old schema (alter table)`, id)
		}
		beforeStmt := stmt.(model.Table)

		stmt, ok = ctx.to.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`table '%s' not found in new schema (alter table)`, id)
		}
		afterStmt := stmt.(model.Table)

		var pbuf bytes.Buffer
		alterCtx := newAlterCtx(beforeStmt, afterStmt)
		for _, p := range procs {
			n, err := p(alterCtx, &pbuf)
			if err != nil {
				return 0, errors.Wrap(err, `failed to generate alter table`)
			}

			if buf.Len() > 0 && n > 0 {
				buf.WriteByte('\n')
			}
			pbuf.WriteTo(&buf)
		}
	}

	return buf.WriteTo(dst)
}

func dropTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	columnNames := ctx.fromColumns.Difference(ctx.toColumns)

	var buf bytes.Buffer
	for _, columnName := range columnNames.ToSlice() {
		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` DROP COLUMN `")
		col, ok := ctx.from.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`failed to lookup column %s`, columnName)
		}

		buf.WriteString(col.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func addTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer

	columnNames := ctx.toColumns.Difference(ctx.fromColumns)
	for _, columnName := range columnNames.ToSlice() {
		stmt, ok := ctx.to.LookupColumn(columnName.(string))
		if !ok {
			continue
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` ADD COLUMN ")
		if _, err := stmt.WriteTo(&buf); err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}

func alterTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	columnNames := ctx.toColumns.Intersect(ctx.fromColumns)
	for _, columnName := range columnNames.ToSlice() {
		beforeColumnStmt, ok := ctx.from.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`column %s not found in old schema`, columnName)
		}

		afterColumnStmt, ok := ctx.to.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`column %s not found in new schema`, columnName)
		}

		if reflect.DeepEqual(beforeColumnStmt, afterColumnStmt) {
			continue
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` CHANGE COLUMN `")
		buf.WriteString(afterColumnStmt.Name())
		buf.WriteString("` ")
		if _, err := afterColumnStmt.WriteTo(&buf); err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}

func dropTableIndexes(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	indexes := ctx.fromIndexes.Difference(ctx.toIndexes)
	for _, index := range indexes.ToSlice() {
		indexStmt, ok := ctx.from.LookupIndex(index.(string))
		if !ok {
			return 0, errors.Errorf(`index '%s' not found in old schema (drop index)`, index)
		}

		if indexStmt.IsPrimaryKey() {
			if buf.Len() > 0 {
				buf.WriteByte('\n')
			}
			buf.WriteString("ALTER TABLE `")
			buf.WriteString(ctx.from.Name())
			buf.WriteString("` DROP INDEX PRIMARY KEY;")
			continue
		}

		if !indexStmt.HasName() {
			return 0, errors.Errorf("can not drop index without name: %s", indexStmt.String())
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` DROP INDEX `")
		buf.WriteString(indexStmt.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func addTableIndexes(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	indexes := ctx.toIndexes.Difference(ctx.fromIndexes)
	for _, index := range indexes.ToSlice() {
		indexStmt, ok := ctx.to.LookupIndex(index.(string))
		if !ok {
			return 0, errors.Errorf(`index '%s' not found in old schema (add index)`, index)
		}
		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` ADD ")
		buf.WriteString(indexStmt.String())
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}
<commit_msg>be explicit about errors<commit_after>package diff

import (
	"bytes"
	"io"
	"reflect"

	"github.com/deckarep/golang-set"
	"github.com/schemalex/schemalex"
	"github.com/schemalex/schemalex/internal/errors"
	"github.com/schemalex/schemalex/model"
)

type Option interface {
	Name() string
	Value() interface{}
}

type option struct {
	name  string
	value interface{}
}

func (o option) Name() string       { return o.name }
func (o option) Value() interface{} { return o.value }

func WithParser(p *schemalex.Parser) Option {
	return &option{
		name:  "parser",
		value: p,
	}
}

func WithTransaction(b bool) Option {
	return &option{
		name:  "transaction",
		value: b,
	}
}

type diffCtx struct {
	fromSet mapset.Set
	toSet   mapset.Set
	from    model.Stmts
	to      model.Stmts
}

func newDiffCtx(from, to model.Stmts) *diffCtx {
	fromSet := mapset.NewSet()
	for _, stmt := range from {
		if cs, ok := stmt.(model.Table); ok {
			fromSet.Add(cs.ID())
		}
	}
	toSet := mapset.NewSet()
	for _, stmt := range to {
		if cs, ok := stmt.(model.Table); ok {
			toSet.Add(cs.ID())
		}
	}

	return &diffCtx{
		fromSet: fromSet,
		toSet:   toSet,
		from:    from,
		to:      to,
	}
}

func Statements(dst io.Writer, from, to model.Stmts, options ...Option) error {
	var txn bool
	for _, o := range options {
		switch o.Name() {
		case "transaction":
			txn = o.Value().(bool)
		}
	}

	ctx := newDiffCtx(from, to)

	var procs = []func(*diffCtx, io.Writer) (int64, error){
		dropTables,
		createTables,
		alterTables,
	}

	var buf bytes.Buffer
	if txn {
		buf.WriteString("\nBEGIN;\n\nSET FOREIGN_KEY_CHECKS = 0;")
	}

	for _, p := range procs {
		var pbuf bytes.Buffer
		n, err := p(ctx, &pbuf)
		if err != nil {
			return errors.Wrap(err, `failed to produce diff`)
		}
		if txn && n > 0 || !txn && buf.Len() > 0 && n > 0 {
			buf.WriteString("\n\n")
		}
		pbuf.WriteTo(&buf)
	}
	if txn {
		buf.WriteString("\n\nSET FOREIGN_KEY_CHECKS = 1;\n\nCOMMIT;")
	}

	if _, err := buf.WriteTo(dst); err != nil {
		return errors.Wrap(err, `failed to write diff`)
	}
	return nil
}

func Strings(dst io.Writer, from, to string, options ...Option) error {
	var p *schemalex.Parser
	for _, o := range options {
		switch o.Name() {
		case "parser":
			p = o.Value().(*schemalex.Parser)
		}
	}
	if p == nil {
		p = schemalex.New()
	}

	stmts1, err := p.ParseString(from)
	if err != nil {
		return errors.Wrapf(err, `failed to parse "from" %s`, from)
	}

	stmts2, err := p.ParseString(to)
	if err != nil {
		return errors.Wrapf(err, `failed to parse "to" %s`, to)
	}

	return Statements(dst, stmts1, stmts2, options...)
}

func Files(dst io.Writer, from, to string, options ...Option) error {
	var p *schemalex.Parser
	for _, o := range options {
		switch o.Name() {
		case "parser":
			p = o.Value().(*schemalex.Parser)
		}
	}
	if p == nil {
		p = schemalex.New()
	}
	stmts1, err := p.ParseFile(from)
	if err != nil {
		return errors.Wrapf(err, `failed to open "from" file %s`, from)
	}

	stmts2, err := p.ParseFile(to)
	if err != nil {
		return errors.Wrapf(err, `failed to open "to" file %s`, to)
	}

	return Statements(dst, stmts1, stmts2, options...)
}

func dropTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	ids := ctx.fromSet.Difference(ctx.toSet)
	for i, id := range ids.ToSlice() {
		if i > 0 {
			buf.WriteByte('\n')
		}

		stmt, ok := ctx.from.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`failed to lookup table %s`, id)
		}

		table, ok := stmt.(model.Table)
		if !ok {
			return 0, errors.Errorf(`lookup failed: %s is not a model.Table`, id)
		}
		buf.WriteString("DROP TABLE `")
		buf.WriteString(table.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func createTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer

	ids := ctx.toSet.Difference(ctx.fromSet)
	for _, id := range ids.ToSlice() {
		// Lookup the corresponding statement, and add its SQL
		stmt, ok := ctx.to.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`failed to lookup table %s`, id)
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		_, err := stmt.WriteTo(&buf)
		if err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}
	return buf.WriteTo(dst)
}

type alterCtx struct {
	fromColumns mapset.Set
	toColumns   mapset.Set
	fromIndexes mapset.Set
	toIndexes   mapset.Set
	from        model.Table
	to          model.Table
}

func newAlterCtx(from, to model.Table) *alterCtx {
	fromColumns := mapset.NewSet()
	for col := range from.Columns() {
		fromColumns.Add(col.ID())
	}

	toColumns := mapset.NewSet()
	for col := range to.Columns() {
		toColumns.Add(col.ID())
	}

	fromIndexes := mapset.NewSet()
	for idx := range from.Indexes() {
		fromIndexes.Add(idx.ID())
	}

	toIndexes := mapset.NewSet()
	for idx := range to.Indexes() {
		toIndexes.Add(idx.ID())
	}

	return &alterCtx{
		fromColumns: fromColumns,
		toColumns:   toColumns,
		fromIndexes: fromIndexes,
		toIndexes:   toIndexes,
		from:        from,
		to:          to,
	}
}

func alterTables(ctx *diffCtx, dst io.Writer) (int64, error) {
	procs := []func(*alterCtx, io.Writer) (int64, error){
		dropTableColumns,
		addTableColumns,
		alterTableColumns,
		dropTableIndexes,
		addTableIndexes,
	}

	ids := ctx.toSet.Intersect(ctx.fromSet)
	var buf bytes.Buffer
	for _, id := range ids.ToSlice() {
		var stmt model.Stmt
		var ok bool

		stmt, ok = ctx.from.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`table '%s' not found in old schema (alter table)`, id)
		}
		beforeStmt := stmt.(model.Table)

		stmt, ok = ctx.to.Lookup(id.(string))
		if !ok {
			return 0, errors.Errorf(`table '%s' not found in new schema (alter table)`, id)
		}
		afterStmt := stmt.(model.Table)

		var pbuf bytes.Buffer
		alterCtx := newAlterCtx(beforeStmt, afterStmt)
		for _, p := range procs {
			n, err := p(alterCtx, &pbuf)
			if err != nil {
				return 0, errors.Wrap(err, `failed to generate alter table`)
			}

			if buf.Len() > 0 && n > 0 {
				buf.WriteByte('\n')
			}
			pbuf.WriteTo(&buf)
		}
	}

	return buf.WriteTo(dst)
}

func dropTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	columnNames := ctx.fromColumns.Difference(ctx.toColumns)

	var buf bytes.Buffer
	for _, columnName := range columnNames.ToSlice() {
		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` DROP COLUMN `")
		col, ok := ctx.from.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`failed to lookup column %s`, columnName)
		}

		buf.WriteString(col.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func addTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer

	columnNames := ctx.toColumns.Difference(ctx.fromColumns)
	for _, columnName := range columnNames.ToSlice() {
		stmt, ok := ctx.to.LookupColumn(columnName.(string))
		if !ok {
			continue
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` ADD COLUMN ")
		if _, err := stmt.WriteTo(&buf); err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}

func alterTableColumns(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	columnNames := ctx.toColumns.Intersect(ctx.fromColumns)
	for _, columnName := range columnNames.ToSlice() {
		beforeColumnStmt, ok := ctx.from.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`column %s not found in old schema`, columnName)
		}

		afterColumnStmt, ok := ctx.to.LookupColumn(columnName.(string))
		if !ok {
			return 0, errors.Errorf(`column %s not found in new schema`, columnName)
		}

		if reflect.DeepEqual(beforeColumnStmt, afterColumnStmt) {
			continue
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` CHANGE COLUMN `")
		buf.WriteString(afterColumnStmt.Name())
		buf.WriteString("` ")
		if _, err := afterColumnStmt.WriteTo(&buf); err != nil {
			return 0, err
		}
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}

func dropTableIndexes(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	indexes := ctx.fromIndexes.Difference(ctx.toIndexes)
	for _, index := range indexes.ToSlice() {
		indexStmt, ok := ctx.from.LookupIndex(index.(string))
		if !ok {
			return 0, errors.Errorf(`index '%s' not found in old schema (drop index)`, index)
		}

		if indexStmt.IsPrimaryKey() {
			if buf.Len() > 0 {
				buf.WriteByte('\n')
			}
			buf.WriteString("ALTER TABLE `")
			buf.WriteString(ctx.from.Name())
			buf.WriteString("` DROP INDEX PRIMARY KEY;")
			continue
		}

		if !indexStmt.HasName() {
			return 0, errors.Errorf("can not drop index without name: %s", indexStmt.String())
		}

		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` DROP INDEX `")
		buf.WriteString(indexStmt.Name())
		buf.WriteString("`;")
	}

	return buf.WriteTo(dst)
}

func addTableIndexes(ctx *alterCtx, dst io.Writer) (int64, error) {
	var buf bytes.Buffer
	indexes := ctx.toIndexes.Difference(ctx.fromIndexes)
	for _, index := range indexes.ToSlice() {
		indexStmt, ok := ctx.to.LookupIndex(index.(string))
		if !ok {
			return 0, errors.Errorf(`index '%s' not found in old schema (add index)`, index)
		}
		if buf.Len() > 0 {
			buf.WriteByte('\n')
		}
		buf.WriteString("ALTER TABLE `")
		buf.WriteString(ctx.from.Name())
		buf.WriteString("` ADD ")
		buf.WriteString(indexStmt.String())
		buf.WriteByte(';')
	}

	return buf.WriteTo(dst)
}
<|endoftext|>


<commit_before>package vue

import "github.com/gopherjs/gopherjs/js"
import "github.com/oskca/gopherjs-dom"

type DirectiveBinding struct {
	*js.Object
	// name: the name of the directive, without the prefix.
	Name string `js:"name"`
	// value: The value passed to the directive. For example in v-my-directive="1 + 1", the value would be 2.
	Value string `js:"value"`
	// oldValue: The previous value, only available in update and componentUpdated. It is available whether or not the value has changed.
	OldValue string `js:"oldValue"`
	// expression: the expression of the binding, excluding arguments and filters.
	Expression string `js:"expression"`
	// arg: the argument, if present.
	Arg string `js:"arg"`
	// modifiers: an object containing modifiers, if any.
	Modifiers *js.Object `js:"modifiers"`
}

// DirectiveCallback can be used in every directive callback functions
type DirectiveCallback func(el *dom.Element, b *DirectiveBinding, vNode, oldVnode *js.Object)

type Directive struct {
	*js.Object
	// // Name string
	// // advanced options
	// // Custom directive can provide a params array,
	// // and the Vue compiler will automatically extract
	// // these attributes on the element that the directive is bound to.
	// Params []string `js:"params"`
	// // If your custom directive is expected to be used on an Object,
	// // and it needs to trigger update when a nested property inside
	// // the object changes, you need to pass in deep: true in your directive definition.
	// Deep bool `js:"deep"`
	// // If your directive expects to write data back to
	// // the Vue instance, you need to pass in twoWay: true.
	// // This option allows the use of this.set(value) inside
	// // the directive:If your directive expects to write data back to
	// // the Vue instance, you need to pass in twoWay: true.
	// // This option allows the use of this.set(value) inside the directive
	// TwoWay bool `js:"twoWay"`
	// // Passing in acceptStatement:true enables
	// // your custom directive to accept inline statements like v-on does
	// AcceptStatement bool `js:"acceptStatement"`
	// // Vue compiles templates by recursively walking the DOM tree.
	// // However when it encounters a terminal directive,
	// // it will stop walking that element’s children.
	// // The terminal directive takes over the job of compiling the element and
	// // its children. For example, v-if and v-for are both terminal directives.
	// Terminal bool `js:"terminal"`
	// // You can optionally provide a priority number for your directive.
	// // If no priority is specified, a default priority will be used
	// //  - 1000 for normal directives and 2000 for terminal directives.
	// // A directive with a higher priority will be processed earlier than
	// // other directives on the same element. Directives with
	// // the same priority will be processed in the order they appear in
	// // the element’s attribute list, although that order is not
	// // guaranteed to be consistent in different browsers.
	// Priority int `js:"priority"`
}

func NewDirective(updaterCallBack ...interface{}) *Directive {
	d := &Directive{
		Object: js.Global.Get("Object").New(),
	}
	if len(updaterCallBack) > 0 {
		d.SetUpdater(updaterCallBack[0])
	}
	return d
}

func (d *Directive) SetBinder(fnCallback interface{}) *Directive {
	d.Set("bind", fnCallback)
	return d
}

func (d *Directive) SetUnBinder(fnCallback interface{}) *Directive {
	d.Set("unbind", fnCallback)
	return d
}

func (d *Directive) SetUpdater(fnCallback interface{}) *Directive {
	d.Set("update", fnCallback)
	return d
}

func (d *Directive) Register(name string) {
	js.Global.Get("Vue").Call("directive", name, d.Object)
}

// In some cases, we may want our directive to be used in the form of
// a custom element rather than as an attribute.
// This is very similar to Angular’s notion of “E” mode directives.
// Element directives provide a lighter-weight alternative to
// full-blown components (which are explained later in the guide).
//
// Element directives cannot accept arguments or
// expressions, but it can read the element’s attributes to
// determine its behavior.
//
// A big difference from normal directives is that
// element directives are terminal, which means once Vue encounters
// an element directive, it will completely skip that element
// - only the element directive itself will be
// able to manipulate that element and its children.
type ElementDirective struct {
	*Directive
}

func NewElementDirective(updaterCallBack ...interface{}) *ElementDirective {
	d := &ElementDirective{
		Directive: NewDirective(updaterCallBack...),
	}
	if len(updaterCallBack) > 0 {
		d.SetUpdater(updaterCallBack[0])
	}
	return d
}

func (d *ElementDirective) Register(name string) {
	js.Global.Get("Vue").Call("elementDirective", name, d.Object)
}
<commit_msg>remove ElementDirective to upgrade to V2<commit_after>package vue

import "github.com/gopherjs/gopherjs/js"
import "github.com/oskca/gopherjs-dom"

type DirectiveBinding struct {
	*js.Object
	// name: the name of the directive, without the prefix.
	Name string `js:"name"`
	// value: The value passed to the directive. For example in v-my-directive="1 + 1", the value would be 2.
	Value string `js:"value"`
	// oldValue: The previous value, only available in update and componentUpdated. It is available whether or not the value has changed.
	OldValue string `js:"oldValue"`
	// expression: the expression of the binding, excluding arguments and filters.
	Expression string `js:"expression"`
	// arg: the argument, if present.
	Arg string `js:"arg"`
	// modifiers: an object containing modifiers, if any.
	Modifiers *js.Object `js:"modifiers"`
}

// DirectiveCallback can be used in every directive callback functions
type DirectiveCallback func(el *dom.Element, b *DirectiveBinding, vNode, oldVnode *js.Object)

type Directive struct {
	*js.Object
	// // Name string
	// // advanced options
	// // Custom directive can provide a params array,
	// // and the Vue compiler will automatically extract
	// // these attributes on the element that the directive is bound to.
	// Params []string `js:"params"`
	// // If your custom directive is expected to be used on an Object,
	// // and it needs to trigger update when a nested property inside
	// // the object changes, you need to pass in deep: true in your directive definition.
	// Deep bool `js:"deep"`
	// // If your directive expects to write data back to
	// // the Vue instance, you need to pass in twoWay: true.
	// // This option allows the use of this.set(value) inside
	// // the directive:If your directive expects to write data back to
	// // the Vue instance, you need to pass in twoWay: true.
	// // This option allows the use of this.set(value) inside the directive
	// TwoWay bool `js:"twoWay"`
	// // Passing in acceptStatement:true enables
	// // your custom directive to accept inline statements like v-on does
	// AcceptStatement bool `js:"acceptStatement"`
	// // Vue compiles templates by recursively walking the DOM tree.
	// // However when it encounters a terminal directive,
	// // it will stop walking that element’s children.
	// // The terminal directive takes over the job of compiling the element and
	// // its children. For example, v-if and v-for are both terminal directives.
	// Terminal bool `js:"terminal"`
	// // You can optionally provide a priority number for your directive.
	// // If no priority is specified, a default priority will be used
	// //  - 1000 for normal directives and 2000 for terminal directives.
	// // A directive with a higher priority will be processed earlier than
	// // other directives on the same element. Directives with
	// // the same priority will be processed in the order they appear in
	// // the element’s attribute list, although that order is not
	// // guaranteed to be consistent in different browsers.
	// Priority int `js:"priority"`
}

func NewDirective(updaterCallBack ...interface{}) *Directive {
	d := &Directive{
		Object: js.Global.Get("Object").New(),
	}
	if len(updaterCallBack) > 0 {
		d.SetUpdater(updaterCallBack[0])
	}
	return d
}

func (d *Directive) SetBinder(fnCallback interface{}) *Directive {
	d.Set("bind", fnCallback)
	return d
}

func (d *Directive) SetUnBinder(fnCallback interface{}) *Directive {
	d.Set("unbind", fnCallback)
	return d
}

func (d *Directive) SetUpdater(fnCallback interface{}) *Directive {
	d.Set("update", fnCallback)
	return d
}

func (d *Directive) Register(name string) {
	js.Global.Get("Vue").Call("directive", name, d.Object)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"github.com/42wim/matterbridge/matterhook"
	"io"
	"os"
	"os/user"
	"strings"
	"time"
)

var (
	flagUserName, flagChannel, flagIconURL, flagMatterURL string
	flagPlainText, flagNoBuffer, flagExtra                bool
)

func init() {
	flag.StringVar(&flagUserName, "u", "mattertee", "This username is used for posting.")
	flag.StringVar(&flagChannel, "c", "", " Post input values to specified channel or user.")
	flag.StringVar(&flagIconURL, "i", "", "This url is used as icon for posting.")
	flag.StringVar(&flagMatterURL, "m", "", "Mattermost incoming webhooks URL.")
	flag.BoolVar(&flagPlainText, "p", false, "Don't surround the post with triple backticks.")
	flag.BoolVar(&flagNoBuffer, "n", false, "Post input values without buffering.")
	flag.BoolVar(&flagExtra, "x", false, "Add extra info (user/hostname/timestamp).")
	flag.Parse()
}

func md(text string) string {
	return "```\n" + text + "```"
}

func extraInfo() string {
	u, _ := user.Current()
	hname, _ := os.Hostname()
	return "\n" + u.Username + "@" + hname + " (_" + time.Now().Format(time.RFC3339) + "_)\n"
}

func main() {
	url := os.Getenv("MM_HOOK")
	if flagMatterURL != "" {
		url = flagMatterURL
	}
	m := matterhook.New(url, matterhook.Config{DisableServer: true})
	msg := matterhook.OMessage{}
	msg.UserName = flagUserName
	msg.Channel = flagChannel
	msg.IconURL = flagIconURL
	buf := new(bytes.Buffer)
	io.Copy(buf, os.Stdin)
	msg.Text = md(buf.String())
	if flagPlainText {
		msg.Text = buf.String()
	}
	if flagNoBuffer {
		texts := strings.Split(buf.String(), "\n")
		for _, text := range texts {
			msg.Text = md(text)
			if flagPlainText {
				msg.Text = text
			}
			m.Send(msg)
		}
		if flagExtra {
			msg.Text = extraInfo()
			m.Send(msg)
		}
	} else {
		if flagExtra {
			msg.Text += extraInfo()
		}
		m.Send(msg)
	}
}
<commit_msg>Refactor<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"github.com/42wim/matterbridge/matterhook"
	"io"
	"os"
	"os/user"
	"time"
)

var (
	flagUserName, flagChannel, flagIconURL, flagMatterURL string
	flagPlainText, flagNoBuffer, flagExtra                bool
)

func init() {
	flag.StringVar(&flagUserName, "u", "mattertee", "This username is used for posting.")
	flag.StringVar(&flagChannel, "c", "", " Post input values to specified channel or user.")
	flag.StringVar(&flagIconURL, "i", "", "This url is used as icon for posting.")
	flag.StringVar(&flagMatterURL, "m", "", "Mattermost incoming webhooks URL.")
	flag.BoolVar(&flagPlainText, "p", false, "Don't surround the post with triple backticks.")
	flag.BoolVar(&flagNoBuffer, "n", false, "Post input values without buffering.")
	flag.BoolVar(&flagExtra, "x", false, "Add extra info (user/hostname/timestamp).")
	flag.Parse()
}

func md(text string) string {
	return "```\n" + text + "```"
}

func extraInfo() string {
	u, _ := user.Current()
	hname, _ := os.Hostname()
	return "\n" + u.Username + "@" + hname + " (_" + time.Now().Format(time.RFC3339) + "_)\n"
}

func main() {
	url := os.Getenv("MM_HOOK")
	if flagMatterURL != "" {
		url = flagMatterURL
	}
	m := matterhook.New(url, matterhook.Config{DisableServer: true})
	msg := matterhook.OMessage{}
	msg.UserName = flagUserName
	msg.Channel = flagChannel
	msg.IconURL = flagIconURL
	if flagNoBuffer {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			line := scanner.Text()
			fmt.Println(line)
			msg.Text = md(line)
			if flagPlainText {
				msg.Text = line
			}
			m.Send(msg)
		}
	} else {
		buf := new(bytes.Buffer)
		io.Copy(buf, os.Stdin)
		text := buf.String()
		fmt.Print(text)
		msg.Text = md(text)
		if flagPlainText {
			msg.Text = text
		}
		if flagExtra {
			msg.Text += extraInfo()
		}
		m.Send(msg)
	}
}
<|endoftext|>


<commit_before>package daikin

import (
	"log"
	"net"
	"os/exec"
	"strings"
	"time"

	"github.com/mostlygeek/arp"
)

var maxDatagramSize = 8192
var udpHost = "224.0.0.1:30050"
var udpClient = "224.0.0.1:30000"

func Discover(discoverInterval time.Duration) (chan AC, error) {

	seen := map[string]*wirelessAC{}

	found := make(chan AC)

	clientAddr, err := net.ResolveUDPAddr("udp", udpClient)
	if err != nil {
		log.Fatal(err)
	}
	l, err := net.ListenUDP("udp", clientAddr)
	if err != nil {
		return nil, err
	}

	hostAddr, err := net.ResolveUDPAddr("udp", udpHost)
	if err != nil {
		log.Fatal(err)
	}

	ping := func() error {
		_, err = l.WriteToUDP([]byte("DAIKIN_UDP/common/basic_info\n"), hostAddr)
		return err
	}

	arp := func() error {
		// We send out a broadcast pings first...

		ips, err := broadcastAddresses()
		if err != nil {
			return err
		}

		for _, ip := range ips {
			//log.Printf("Broadcast pinging %s", ip)
			cmd := exec.Command("ping", "-w", "5s", "-b", ip)
			err := cmd.Run()
			if err != nil {
				log.Printf("Failed to broadcast ping %s: %s", ip, err)
			}
		}

		for ip := range arp.Table() {
			mac := arp.Search(ip)

			if strings.HasPrefix(strings.ToUpper(mac), "90:B6:86") { // Murata Manufacturing Co., Ltd.
				log.Printf("Found a potential daikin AC: %s (mac: %s)", ip, mac)

				ac := NewWirelessAC(ip)
				info, err := ac.RefreshBasicInfo()

				if err == nil && info != nil && info.Ret == "OK" && info.Type == "aircon" {
					if existing, ok := seen[info.Id]; ok {
						existing.host = ip
					} else {
						seen[info.Id] = ac
						found <- ac
					}
				}

			} else {
				//log.Printf("Fail: %s %s", mac, ip)
			}

		}

		return nil
	}

	go func() {
		var t *time.Timer
		t = time.AfterFunc(0, func() {

			//log.Printf("Searching using ARP table...")
			if err := arp(); err != nil {
				log.Printf("Failed to discover daikin ACs using arp table: %s", err)
			}

			time.Sleep(time.Second * 5)

			//log.Printf("Searching using UDP...")
			if err := ping(); err != nil {
				log.Printf("Failed to discover daikin ACs: %s", err)
			}

			t.Reset(discoverInterval)
		})
	}()

	l.SetReadBuffer(maxDatagramSize)

	go func() {

		for {
			b := make([]byte, maxDatagramSize)
			n, src, err := l.ReadFromUDP(b)
			if err != nil {
				log.Printf("Daikin Discovery Error: ReadFromUDP failed: %s", err)
				continue
			}

			//log.Printf("Received response: %s", string(b[0:n]))

			info := &BasicInfo{}

			mapBytes(info, b[0:n])

			if existing, ok := seen[info.Id]; ok {
				existing.host = src.IP.String() + ":80"
			} else {
				ac := NewWirelessAC(src.IP.String() + ":80")
				ac.info = info

				seen[info.Id] = ac

				found <- ac
			}

		}
	}()

	if err := ping(); err != nil {
		return nil, err
	}

	return found, nil
}

func broadcastAddresses() ([]string, error) {

	ips := []string{}

	ifaces, err := net.Interfaces()
	if err != nil {
		return ips, err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return ips, err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}

			ip[3] = 255 // Make it a broadcast address. ES: Is this ok?
			ips = append(ips, ip.String())
		}
	}
	return ips, nil
}
<commit_msg>Disable UDP discovery, in favour of arp cache (for now)<commit_after>package daikin

import (
	"log"
	"net"
	"os/exec"
	"time"

	"github.com/mostlygeek/arp"
)

var maxDatagramSize = 8192
var udpHost = "224.0.0.1:30050"
var udpClient = "224.0.0.1:30000"

func Discover(discoverInterval time.Duration) (chan AC, error) {

	seen := map[string]*wirelessAC{}

	found := make(chan AC)

	/*clientAddr, err := net.ResolveUDPAddr("udp", udpClient)
	if err != nil {
		log.Fatal(err)
	}
	l, err := net.ListenUDP("udp", clientAddr)
	if err != nil {
		return nil, err
	}

	hostAddr, err := net.ResolveUDPAddr("udp", udpHost)
	if err != nil {
		log.Fatal(err)
	}

	ping := func() error {
		_, err = l.WriteToUDP([]byte("DAIKIN_UDP/common/basic_info\n"), hostAddr)
		return err
	}*/

	arp := func() error {
		// We send out a broadcast pings first...

		ips, err := broadcastAddresses()
		if err != nil {
			return err
		}

		for _, ip := range ips {
			//log.Printf("Broadcast pinging %s", ip)
			cmd := exec.Command("ping", "-w", "5s", "-b", ip)
			err := cmd.Run()
			if err != nil {
				log.Printf("Failed to broadcast ping %s: %s", ip, err)
			}
		}

		for ip := range arp.Table() {
			mac := arp.Search(ip)

			//if strings.HasPrefix(strings.ToUpper(mac), "90:B6:86") { // Murata Manufacturing Co., Ltd.
			log.Printf("Found a potential daikin AC: %s (mac: %s)", ip, mac)

			ac := NewWirelessAC(ip)
			info, err := ac.RefreshBasicInfo()

			if err == nil && info != nil && info.Ret == "OK" && info.Type == "aircon" {
				if existing, ok := seen[info.Id]; ok {
					existing.host = ip
				} else {
					seen[info.Id] = ac
					found <- ac
				}
			}

			//} else {
			//log.Printf("Fail: %s %s", mac, ip)
			//}

		}

		return nil
	}

	go func() {
		var t *time.Timer
		t = time.AfterFunc(0, func() {

			//log.Printf("Searching using ARP table...")
			if err := arp(); err != nil {
				log.Printf("Failed to discover daikin ACs using arp table: %s", err)
			}

			//time.Sleep(time.Second * 5)

			//log.Printf("Searching using UDP...")
			//if err := ping(); err != nil {
			//log.Printf("Failed to discover daikin ACs using udp: %s", err)
			//}

			t.Reset(discoverInterval)
		})
	}()

	/*l.SetReadBuffer(maxDatagramSize)

	go func() {

		for {
			b := make([]byte, maxDatagramSize)
			n, src, err := l.ReadFromUDP(b)
			if err != nil {
				log.Printf("Daikin Discovery Error: ReadFromUDP failed: %s", err)
				continue
			}

			//log.Printf("Received response: %s", string(b[0:n]))

			info := &BasicInfo{}

			mapBytes(info, b[0:n])

			if existing, ok := seen[info.Id]; ok {
				existing.host = src.IP.String() + ":80"
			} else {
				ac := NewWirelessAC(src.IP.String() + ":80")
				ac.info = info

				seen[info.Id] = ac

				found <- ac
			}

		}
	}()

	if err := ping(); err != nil {
		return nil, err
	}*/

	return found, nil
}

func broadcastAddresses() ([]string, error) {

	ips := []string{}

	ifaces, err := net.Interfaces()
	if err != nil {
		return ips, err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return ips, err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}

			ip[3] = 255 // Make it a broadcast address. ES: Is this ok?
			ips = append(ips, ip.String())
		}
	}
	return ips, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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 metrics

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
)

const (
	DomainEnv        = "METRICS_DOMAIN"
	ConfigMapNameEnv = "CONFIG_OBSERVABILITY_NAME"
)

// metricsBackend specifies the backend to use for metrics
type metricsBackend string

const (
	// The following keys are used to configure metrics reporting.
	// See https://github.com/knative/serving/blob/master/config/config-observability.yaml
	// for details.
	AllowStackdriverCustomMetricsKey    = "metrics.allow-stackdriver-custom-metrics"
	BackendDestinationKey               = "metrics.backend-destination"
	ReportingPeriodKey                  = "metrics.reporting-period-seconds"
	StackdriverProjectIDKey             = "metrics.stackdriver-project-id"
	StackdriverCustomMetricSubDomainKey = "metrics.stackdriver-custom-metrics-subdomain"

	// Stackdriver is used for Stackdriver backend
	Stackdriver metricsBackend = "stackdriver"
	// Prometheus is used for Prometheus backend
	Prometheus metricsBackend = "prometheus"

	defaultBackendEnvName = "DEFAULT_METRICS_BACKEND"

	defaultPrometheusPort = 9090
	maxPrometheusPort     = 65535
	minPrometheusPort     = 1024
)

// ExporterOptions contains options for configuring the exporter.
type ExporterOptions struct {
	// Domain is the metrics domain. e.g. "knative.dev". Must be present.
	Domain string

	// Component is the name of the component that emits the metrics. e.g.
	// "activator", "queue_proxy". Should only contains alphabets and underscore.
	// Must be present.
	Component string

	// PrometheusPort is the port to expose metrics if metrics backend is Prometheus.
	// It should be between maxPrometheusPort and maxPrometheusPort. 0 value means
	// using the default 9090 value. If is ignored if metrics backend is not
	// Prometheus.
	PrometheusPort int

	// ConfigMap is the data from config map config-observability. Must be present.
	// See https://github.com/knative/serving/blob/master/config/config-observability.yaml
	// for details.
	ConfigMap map[string]string
}

type metricsConfig struct {
	// The metrics domain. e.g. "serving.knative.dev" or "build.knative.dev".
	domain string
	// The component that emits the metrics. e.g. "activator", "autoscaler".
	component string
	// The metrics backend destination.
	backendDestination metricsBackend
	// reportingPeriod specifies the interval between reporting aggregated views.
	// If duration is less than or equal to zero, it enables the default behavior.
	reportingPeriod time.Duration

	// ---- Prometheus specific below ----
	// prometheusPort is the port where metrics are exposed in Prometheus
	// format. It defaults to 9090.
	prometheusPort int

	// ---- Stackdriver specific below ----
	// stackdriverProjectID is the stackdriver project ID where the stats data are
	// uploaded to. This is not the GCP project ID.
	stackdriverProjectID string
	// allowStackdriverCustomMetrics indicates whether it is allowed to send metrics to
	// Stackdriver using "global" resource type and custom metric type if the
	// metrics are not supported by the registered monitored resource types. Setting this
	// flag to "true" could cause extra Stackdriver charge.
	// If backendDestination is not Stackdriver, this is ignored.
	allowStackdriverCustomMetrics bool
	// stackdriverCustomMetricsSubDomain is the subdomain to use when sending custom metrics to StackDriver.
	// If not specified, the default is `knative.dev`.
	// If backendDestination is not Stackdriver, this is ignored.
	stackdriverCustomMetricsSubDomain string
	// True if backendDestination equals to "stackdriver". Store this in a variable
	// to reduce string comparison operations.
	isStackdriverBackend bool
	// stackdriverMetricTypePrefix is the metric domain joins component, e.g.
	// "knative.dev/serving/activator". Store this in a variable to reduce string
	// join operations.
	stackdriverMetricTypePrefix string
	// stackdriverCustomMetricTypePrefix is "custom.googleapis.com" joined with the subdomain and component.
	// E.g., "custom.googleapis.com/<subdomain>/<component>".
	// Store this in a variable to reduce string join operations.
	stackdriverCustomMetricTypePrefix string
}

func getMetricsConfig(ops ExporterOptions, logger *zap.SugaredLogger) (*metricsConfig, error) {
	var mc metricsConfig

	if ops.Domain == "" {
		return nil, errors.New("metrics domain cannot be empty")
	}
	mc.domain = ops.Domain

	if ops.Component == "" {
		return nil, errors.New("metrics component name cannot be empty")
	}
	mc.component = ops.Component

	if ops.ConfigMap == nil {
		return nil, errors.New("metrics config map cannot be empty")
	}
	m := ops.ConfigMap
	// Read backend setting from environment variable first
	backend := os.Getenv(defaultBackendEnvName)
	if backend == "" {
		// Use Prometheus if DEFAULT_METRICS_BACKEND does not exist or is empty
		backend = string(Prometheus)
	}
	// Override backend if it is setting in config map.
	if backendFromConfig, ok := m[BackendDestinationKey]; ok {
		backend = backendFromConfig
	}
	lb := metricsBackend(strings.ToLower(backend))
	switch lb {
	case Stackdriver, Prometheus:
		mc.backendDestination = lb
	default:
		return nil, fmt.Errorf("unsupported metrics backend value %q", backend)
	}

	if mc.backendDestination == Prometheus {
		pp := ops.PrometheusPort
		if pp == 0 {
			pp = defaultPrometheusPort
		}
		if pp < minPrometheusPort || pp > maxPrometheusPort {
			return nil, fmt.Errorf("invalid port %v, should between %v and %v", pp, minPrometheusPort, maxPrometheusPort)
		}
		mc.prometheusPort = pp
	}

	// If stackdriverProjectIDKey is not provided for stackdriver backend destination, OpenCensus will try to
	// use the application default credentials. If that is not available, Opencensus would fail to create the
	// metrics exporter.
	if mc.backendDestination == Stackdriver {
		mc.stackdriverProjectID = m[StackdriverProjectIDKey]
		mc.isStackdriverBackend = true
		mc.stackdriverMetricTypePrefix = path.Join(mc.domain, mc.component)

		mc.stackdriverCustomMetricsSubDomain = defaultCustomMetricSubDomain
		if sdcmd, ok := m[StackdriverCustomMetricSubDomainKey]; ok && sdcmd != "" {
			mc.stackdriverCustomMetricsSubDomain = sdcmd
		}
		mc.stackdriverCustomMetricTypePrefix = path.Join(customMetricTypePrefix, mc.stackdriverCustomMetricsSubDomain, mc.component)
		if ascmStr, ok := m[AllowStackdriverCustomMetricsKey]; ok && ascmStr != "" {
			ascmBool, err := strconv.ParseBool(ascmStr)
			if err != nil {
				return nil, fmt.Errorf("invalid %s value %q", AllowStackdriverCustomMetricsKey, ascmStr)
			}
			mc.allowStackdriverCustomMetrics = ascmBool
		}
	}

	// If reporting period is specified, use the value from the configuration.
	// If not, set a default value based on the selected backend.
	// Each exporter makes different promises about what the lowest supported
	// reporting period is. For Stackdriver, this value is 1 minute.
	// For Prometheus, we will use a lower value since the exporter doesn't
	// push anything but just responds to pull requests, and shorter durations
	// do not really hurt the performance and we rely on the scraping configuration.
	if repStr, ok := m[ReportingPeriodKey]; ok && repStr != "" {
		repInt, err := strconv.Atoi(repStr)
		if err != nil {
			return nil, fmt.Errorf("invalid %s value %q", ReportingPeriodKey, repStr)
		}
		mc.reportingPeriod = time.Duration(repInt) * time.Second
	} else if mc.backendDestination == Stackdriver {
		mc.reportingPeriod = 60 * time.Second
	} else if mc.backendDestination == Prometheus {
		mc.reportingPeriod = 5 * time.Second
	}

	return &mc, nil
}

// UpdateExporterFromConfigMap returns a helper func that can be used to update the exporter
// when a config map is updated.
func UpdateExporterFromConfigMap(component string, logger *zap.SugaredLogger) func(configMap *corev1.ConfigMap) {
	domain := Domain()
	return func(configMap *corev1.ConfigMap) {
		UpdateExporter(ExporterOptions{
			Domain:    domain,
			Component: component,
			ConfigMap: configMap.Data,
		}, logger)
	}
}

// UpdateExporter updates the exporter based on the given ExporterOptions.
func UpdateExporter(ops ExporterOptions, logger *zap.SugaredLogger) error {
	newConfig, err := getMetricsConfig(ops, logger)
	if err != nil {
		if ce := getCurMetricsExporter(); ce == nil {
			// Fail the process if there doesn't exist an exporter.
			logger.Errorw("Failed to get a valid metrics config", zap.Error(err))
		} else {
			logger.Errorw("Failed to get a valid metrics config; Skip updating the metrics exporter", zap.Error(err))
		}
		return err
	}

	if isNewExporterRequired(newConfig) {
		logger.Info("Flushing the existing exporter before setting up the new exporter.")
		FlushExporter()
		e, err := newMetricsExporter(newConfig, logger)
		if err != nil {
			logger.Errorf("Failed to update a new metrics exporter based on metric config %v. error: %v", newConfig, err)
			return err
		}
		existingConfig := getCurMetricsConfig()
		setCurMetricsExporter(e)
		logger.Infof("Successfully updated the metrics exporter; old config: %v; new config %v", existingConfig, newConfig)
	}

	setCurMetricsConfig(newConfig)
	return nil
}

// isNewExporterRequired compares the non-nil newConfig against curMetricsConfig. When backend changes,
// or stackdriver project ID changes for stackdriver backend, we need to update the metrics exporter.
func isNewExporterRequired(newConfig *metricsConfig) bool {
	cc := getCurMetricsConfig()
	if cc == nil || newConfig.backendDestination != cc.backendDestination {
		return true
	} else if newConfig.backendDestination == Stackdriver && newConfig.stackdriverProjectID != cc.stackdriverProjectID {
		return true
	}

	return false
}

// ConfigMapName gets the name of the metrics ConfigMap
func ConfigMapName() string {
	cm := os.Getenv(ConfigMapNameEnv)
	if cm == "" {
		return "config-observability"
	}
	return cm
}

// Domain holds the metrics domain to use for surfacing metrics.
func Domain() string {
	if domain := os.Getenv(DomainEnv); domain != "" {
		return domain
	}

	panic(fmt.Sprintf(`The environment variable %q is not set

If this is a process running on Kubernetes, then it should be specifying
this via:

  env:
  - name: %s
    value: knative.dev/some-repository

If this is a Go unit test consuming metric.Domain() then it should add the
following import:

import (
	_ "knative.dev/pkg/metrics/testing"
)`, DomainEnv, DomainEnv))
}

// JsonToMetricsOptions converts a json string of a
// ExporterOptions. Returns a non-nil ExporterOptions always.
func JsonToMetricsOptions(jsonOpts string) (*ExporterOptions, error) {
	var opts ExporterOptions
	if jsonOpts == "" {
		return nil, errors.New("json options string is empty")
	}

	if err := json.Unmarshal([]byte(jsonOpts), &opts); err != nil {
		return nil, err
	}

	return &opts, nil
}

// MetricsOptionsToJson converts a ExporterOptions to a json string.
func MetricsOptionsToJson(opts *ExporterOptions) (string, error) {
	if opts == nil {
		return "", nil
	}

	jsonOpts, err := json.Marshal(opts)
	if err != nil {
		return "", err
	}

	return string(jsonOpts), nil
}
<commit_msg>add comment (#761)<commit_after>/*
Copyright 2018 The Knative Authors

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 metrics

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"go.uber.org/zap"
	corev1 "k8s.io/api/core/v1"
)

const (
	DomainEnv        = "METRICS_DOMAIN"
	ConfigMapNameEnv = "CONFIG_OBSERVABILITY_NAME"
)

// metricsBackend specifies the backend to use for metrics
type metricsBackend string

const (
	// The following keys are used to configure metrics reporting.
	// See https://github.com/knative/serving/blob/master/config/config-observability.yaml
	// for details.
	AllowStackdriverCustomMetricsKey    = "metrics.allow-stackdriver-custom-metrics"
	BackendDestinationKey               = "metrics.backend-destination"
	ReportingPeriodKey                  = "metrics.reporting-period-seconds"
	StackdriverProjectIDKey             = "metrics.stackdriver-project-id"
	StackdriverCustomMetricSubDomainKey = "metrics.stackdriver-custom-metrics-subdomain"

	// Stackdriver is used for Stackdriver backend
	Stackdriver metricsBackend = "stackdriver"
	// Prometheus is used for Prometheus backend
	Prometheus metricsBackend = "prometheus"

	defaultBackendEnvName = "DEFAULT_METRICS_BACKEND"

	defaultPrometheusPort = 9090
	maxPrometheusPort     = 65535
	minPrometheusPort     = 1024
)

// ExporterOptions contains options for configuring the exporter.
type ExporterOptions struct {
	// Domain is the metrics domain. e.g. "knative.dev". Must be present.
	//
	// Stackdriver uses the following format to construct full metric name:
	//    <domain>/<component>/<metric name from View>
	// Prometheus uses the following format to construct full metric name:
	//    <component>_<metric name from View>
	// Domain is actually not used if metrics backend is Prometheus.
	Domain string

	// Component is the name of the component that emits the metrics. e.g.
	// "activator", "queue_proxy". Should only contains alphabets and underscore.
	// Must be present.
	Component string

	// PrometheusPort is the port to expose metrics if metrics backend is Prometheus.
	// It should be between maxPrometheusPort and maxPrometheusPort. 0 value means
	// using the default 9090 value. If is ignored if metrics backend is not
	// Prometheus.
	PrometheusPort int

	// ConfigMap is the data from config map config-observability. Must be present.
	// See https://github.com/knative/serving/blob/master/config/config-observability.yaml
	// for details.
	ConfigMap map[string]string
}

type metricsConfig struct {
	// The metrics domain. e.g. "serving.knative.dev" or "build.knative.dev".
	domain string
	// The component that emits the metrics. e.g. "activator", "autoscaler".
	component string
	// The metrics backend destination.
	backendDestination metricsBackend
	// reportingPeriod specifies the interval between reporting aggregated views.
	// If duration is less than or equal to zero, it enables the default behavior.
	reportingPeriod time.Duration

	// ---- Prometheus specific below ----
	// prometheusPort is the port where metrics are exposed in Prometheus
	// format. It defaults to 9090.
	prometheusPort int

	// ---- Stackdriver specific below ----
	// stackdriverProjectID is the stackdriver project ID where the stats data are
	// uploaded to. This is not the GCP project ID.
	stackdriverProjectID string
	// allowStackdriverCustomMetrics indicates whether it is allowed to send metrics to
	// Stackdriver using "global" resource type and custom metric type if the
	// metrics are not supported by the registered monitored resource types. Setting this
	// flag to "true" could cause extra Stackdriver charge.
	// If backendDestination is not Stackdriver, this is ignored.
	allowStackdriverCustomMetrics bool
	// stackdriverCustomMetricsSubDomain is the subdomain to use when sending custom metrics to StackDriver.
	// If not specified, the default is `knative.dev`.
	// If backendDestination is not Stackdriver, this is ignored.
	stackdriverCustomMetricsSubDomain string
	// True if backendDestination equals to "stackdriver". Store this in a variable
	// to reduce string comparison operations.
	isStackdriverBackend bool
	// stackdriverMetricTypePrefix is the metric domain joins component, e.g.
	// "knative.dev/serving/activator". Store this in a variable to reduce string
	// join operations.
	stackdriverMetricTypePrefix string
	// stackdriverCustomMetricTypePrefix is "custom.googleapis.com" joined with the subdomain and component.
	// E.g., "custom.googleapis.com/<subdomain>/<component>".
	// Store this in a variable to reduce string join operations.
	stackdriverCustomMetricTypePrefix string
}

func getMetricsConfig(ops ExporterOptions, logger *zap.SugaredLogger) (*metricsConfig, error) {
	var mc metricsConfig

	if ops.Domain == "" {
		return nil, errors.New("metrics domain cannot be empty")
	}
	mc.domain = ops.Domain

	if ops.Component == "" {
		return nil, errors.New("metrics component name cannot be empty")
	}
	mc.component = ops.Component

	if ops.ConfigMap == nil {
		return nil, errors.New("metrics config map cannot be empty")
	}
	m := ops.ConfigMap
	// Read backend setting from environment variable first
	backend := os.Getenv(defaultBackendEnvName)
	if backend == "" {
		// Use Prometheus if DEFAULT_METRICS_BACKEND does not exist or is empty
		backend = string(Prometheus)
	}
	// Override backend if it is setting in config map.
	if backendFromConfig, ok := m[BackendDestinationKey]; ok {
		backend = backendFromConfig
	}
	lb := metricsBackend(strings.ToLower(backend))
	switch lb {
	case Stackdriver, Prometheus:
		mc.backendDestination = lb
	default:
		return nil, fmt.Errorf("unsupported metrics backend value %q", backend)
	}

	if mc.backendDestination == Prometheus {
		pp := ops.PrometheusPort
		if pp == 0 {
			pp = defaultPrometheusPort
		}
		if pp < minPrometheusPort || pp > maxPrometheusPort {
			return nil, fmt.Errorf("invalid port %v, should between %v and %v", pp, minPrometheusPort, maxPrometheusPort)
		}
		mc.prometheusPort = pp
	}

	// If stackdriverProjectIDKey is not provided for stackdriver backend destination, OpenCensus will try to
	// use the application default credentials. If that is not available, Opencensus would fail to create the
	// metrics exporter.
	if mc.backendDestination == Stackdriver {
		mc.stackdriverProjectID = m[StackdriverProjectIDKey]
		mc.isStackdriverBackend = true
		mc.stackdriverMetricTypePrefix = path.Join(mc.domain, mc.component)

		mc.stackdriverCustomMetricsSubDomain = defaultCustomMetricSubDomain
		if sdcmd, ok := m[StackdriverCustomMetricSubDomainKey]; ok && sdcmd != "" {
			mc.stackdriverCustomMetricsSubDomain = sdcmd
		}
		mc.stackdriverCustomMetricTypePrefix = path.Join(customMetricTypePrefix, mc.stackdriverCustomMetricsSubDomain, mc.component)
		if ascmStr, ok := m[AllowStackdriverCustomMetricsKey]; ok && ascmStr != "" {
			ascmBool, err := strconv.ParseBool(ascmStr)
			if err != nil {
				return nil, fmt.Errorf("invalid %s value %q", AllowStackdriverCustomMetricsKey, ascmStr)
			}
			mc.allowStackdriverCustomMetrics = ascmBool
		}
	}

	// If reporting period is specified, use the value from the configuration.
	// If not, set a default value based on the selected backend.
	// Each exporter makes different promises about what the lowest supported
	// reporting period is. For Stackdriver, this value is 1 minute.
	// For Prometheus, we will use a lower value since the exporter doesn't
	// push anything but just responds to pull requests, and shorter durations
	// do not really hurt the performance and we rely on the scraping configuration.
	if repStr, ok := m[ReportingPeriodKey]; ok && repStr != "" {
		repInt, err := strconv.Atoi(repStr)
		if err != nil {
			return nil, fmt.Errorf("invalid %s value %q", ReportingPeriodKey, repStr)
		}
		mc.reportingPeriod = time.Duration(repInt) * time.Second
	} else if mc.backendDestination == Stackdriver {
		mc.reportingPeriod = 60 * time.Second
	} else if mc.backendDestination == Prometheus {
		mc.reportingPeriod = 5 * time.Second
	}

	return &mc, nil
}

// UpdateExporterFromConfigMap returns a helper func that can be used to update the exporter
// when a config map is updated.
func UpdateExporterFromConfigMap(component string, logger *zap.SugaredLogger) func(configMap *corev1.ConfigMap) {
	domain := Domain()
	return func(configMap *corev1.ConfigMap) {
		UpdateExporter(ExporterOptions{
			Domain:    domain,
			Component: component,
			ConfigMap: configMap.Data,
		}, logger)
	}
}

// UpdateExporter updates the exporter based on the given ExporterOptions.
func UpdateExporter(ops ExporterOptions, logger *zap.SugaredLogger) error {
	newConfig, err := getMetricsConfig(ops, logger)
	if err != nil {
		if ce := getCurMetricsExporter(); ce == nil {
			// Fail the process if there doesn't exist an exporter.
			logger.Errorw("Failed to get a valid metrics config", zap.Error(err))
		} else {
			logger.Errorw("Failed to get a valid metrics config; Skip updating the metrics exporter", zap.Error(err))
		}
		return err
	}

	if isNewExporterRequired(newConfig) {
		logger.Info("Flushing the existing exporter before setting up the new exporter.")
		FlushExporter()
		e, err := newMetricsExporter(newConfig, logger)
		if err != nil {
			logger.Errorf("Failed to update a new metrics exporter based on metric config %v. error: %v", newConfig, err)
			return err
		}
		existingConfig := getCurMetricsConfig()
		setCurMetricsExporter(e)
		logger.Infof("Successfully updated the metrics exporter; old config: %v; new config %v", existingConfig, newConfig)
	}

	setCurMetricsConfig(newConfig)
	return nil
}

// isNewExporterRequired compares the non-nil newConfig against curMetricsConfig. When backend changes,
// or stackdriver project ID changes for stackdriver backend, we need to update the metrics exporter.
func isNewExporterRequired(newConfig *metricsConfig) bool {
	cc := getCurMetricsConfig()
	if cc == nil || newConfig.backendDestination != cc.backendDestination {
		return true
	} else if newConfig.backendDestination == Stackdriver && newConfig.stackdriverProjectID != cc.stackdriverProjectID {
		return true
	}

	return false
}

// ConfigMapName gets the name of the metrics ConfigMap
func ConfigMapName() string {
	cm := os.Getenv(ConfigMapNameEnv)
	if cm == "" {
		return "config-observability"
	}
	return cm
}

// Domain holds the metrics domain to use for surfacing metrics.
func Domain() string {
	if domain := os.Getenv(DomainEnv); domain != "" {
		return domain
	}

	panic(fmt.Sprintf(`The environment variable %q is not set

If this is a process running on Kubernetes, then it should be specifying
this via:

  env:
  - name: %s
    value: knative.dev/some-repository

If this is a Go unit test consuming metric.Domain() then it should add the
following import:

import (
	_ "knative.dev/pkg/metrics/testing"
)`, DomainEnv, DomainEnv))
}

// JsonToMetricsOptions converts a json string of a
// ExporterOptions. Returns a non-nil ExporterOptions always.
func JsonToMetricsOptions(jsonOpts string) (*ExporterOptions, error) {
	var opts ExporterOptions
	if jsonOpts == "" {
		return nil, errors.New("json options string is empty")
	}

	if err := json.Unmarshal([]byte(jsonOpts), &opts); err != nil {
		return nil, err
	}

	return &opts, nil
}

// MetricsOptionsToJson converts a ExporterOptions to a json string.
func MetricsOptionsToJson(opts *ExporterOptions) (string, error) {
	if opts == nil {
		return "", nil
	}

	jsonOpts, err := json.Marshal(opts)
	if err != nil {
		return "", err
	}

	return string(jsonOpts), nil
}
<|endoftext|>


<commit_before>package main

import (
  "sodium"
  "os"
  "log"
  "flag"
)

var output = flag.String("output", "nacl", "The output prefix to use. This will generate 'nacl.secret' and 'nacl.public' for the secret and public keys, respectively, where 'nacl' is the flag value you set.")

func main() {
  flag.Parse()

  pk, sk := sodium.CryptoBoxKeypair()

  write(*output + ".public", pk[:])
  write(*output + ".secret", sk[:])
} /* main */

func write(path string, value []byte) {
  file, err := os.OpenFile(path, os.O_WRONLY | os.O_CREATE, 0600)
  if err != nil {
    log.Fatalf("Failed to open file (%s) for writing: %s\n",
               path, err)
    return
  }

  n, err := file.Write(value)
  if err != nil {
    log.Fatalf("Failed to write to file (%s): %s\n",
               path, err)
    return
  }
  if n < len(value) {
    log.Fatalf("Failed write to file (%s). Wrote %d of %d bytes.\n",
               path, n, len(value))
    return
  }

  err = file.Close()
  if err != nil {
    log.Fatalf("Failure closing file (%s): %s\n", path, err);
    return
  }
}
<commit_msg>be verbose<commit_after>package main

import (
  "sodium"
  "os"
  "log"
  "flag"
)

var output = flag.String("output", "nacl", "The output prefix to use. This will generate 'nacl.secret' and 'nacl.public' for the secret and public keys, respectively, where 'nacl' is the flag value you set.")

func main() {
  flag.Parse()

  pk, sk := sodium.CryptoBoxKeypair()

  write(*output + ".public", pk[:])
  write(*output + ".secret", sk[:])
} /* main */

func write(path string, value []byte) {
  log.Printf("Writing %s", path)
  file, err := os.OpenFile(path, os.O_WRONLY | os.O_CREATE, 0600)
  if err != nil {
    log.Fatalf("Failed to open file (%s) for writing: %s\n",
               path, err)
    return
  }

  n, err := file.Write(value)
  if err != nil {
    log.Fatalf("Failed to write to file (%s): %s\n",
               path, err)
    return
  }
  if n < len(value) {
    log.Fatalf("Failed write to file (%s). Wrote %d of %d bytes.\n",
               path, n, len(value))
    return
  }

  err = file.Close()
  if err != nil {
    log.Fatalf("Failure closing file (%s): %s\n", path, err);
    return
  }
}
<|endoftext|>


<commit_before>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx context.Context) []{{$typeName}}
	Get(ctx context.Context, id int) ({{$typeName}}, error)
	Add(ctx context.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx context.Context, o {{$typeName}}) (error)
	Delete(ctx context.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx context.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx context.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx context.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx context.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return err
}
func (m *{{$typeName}}DB) Delete(ctx context.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx context.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx context.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx context.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	err := m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return  list
	}
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<commit_msg>decouple contexts<commit_after>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	{{ if ne $belongsto "" }} m.{{ $belongsto }}ID=int(ctx.{{ demodel $belongsto }}ID){{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx context.Context) []{{$typeName}}
	Get(ctx context.Context, id int) ({{$typeName}}, error)
	Add(ctx context.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx context.Context, o {{$typeName}}) (error)
	Delete(ctx context.Context, id int) (error)
	{{ storagedef . }}
}

type {{$typeName}}DB struct {
	DB gorm.DB
}
/*{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}Filter(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}{{end}}{{end}}
*/
func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx context.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx context.Context, id int) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx context.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx context.Context, model {{$typeName}}) error {
	obj, err := m.Get(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	return err
}
func (m *{{$typeName}}DB) Delete(ctx context.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		return  err
	}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx context.Context, {{$lower}}ID int)  error {
	var obj {{$typeName}}

	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx context.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx context.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list)
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<|endoftext|>


<commit_before>package gateway

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/hexablock/fidias"
	"github.com/hexablock/hexatype"
	"github.com/hexablock/phi"
)

const (
	headerBallotTime     = "Ballot-Time"
	headerBlockSize      = "Block-Size"
	headerBlockWriteTime = "Block-Write-Time"
	headerBlockReadTime  = "Block-Read-Time"
	headerBlockCount     = "Block-Count"
	headerFsmTime        = "Fsm-Time"
	headerGroup          = "Group-Index"
	headerLookupTime     = "Lookup-Time"
	headerNodeHBeat      = "Node-Heartbeats"
	headerNodeRTT        = "Node-Rtt"
	headerNodePriority   = "Node-Priority"
	headerParticipants   = "Participants"
	headerRespTime       = "Response-Time"
	headerRuntime        = "Runtime"
)

var accessControlHeaders = map[string]string{
	"Access-Control-Allow-Origin": "*",
}

type HTTPServer struct {
	DHT    phi.DHT
	Device *phi.BlockDevice
	KVS    *fidias.KVS
}

func (server *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	reqpath := r.URL.Path[1:]
	if reqpath == "" {
		w.WriteHeader(404)
		return
	}

	endpoint, resource := parseDirBase(reqpath)

	switch endpoint {
	case "dht":
		if resource == "" {
			w.WriteHeader(404)
			return
		}
		server.handleDHT(w, r, resource)

	case "blox":
		server.handleBlox(w, r, resource)

	case "kv":
		if resource == "" {
			w.WriteHeader(404)
			return
		}
		server.handleKV(w, r, resource)

	default:
		w.WriteHeader(404)
	}

}

func setWriteHeaderStats(w http.ResponseWriter, stats *phi.WriteStats) {
	w.Header().Set(headerBallotTime, fmt.Sprintf("%v", stats.BallotTime))
	w.Header().Set(headerFsmTime, fmt.Sprintf("%v", stats.ApplyTime))

	hosts := make([]string, 0, len(stats.Participants))
	for _, p := range stats.Participants {
		hosts = append(hosts, fmt.Sprintf("%s/%x", p.Host, p.ID))
	}
	w.Header().Set(headerParticipants, strings.Join(hosts, ","))
}

// setReadHeader sets common read headers.
func setReadHeader(w http.ResponseWriter, stats *fidias.ReadStats) {
	var nodes string
	for _, n := range stats.Nodes {
		nodes += fmt.Sprintf("%s/%x,", n.Host(), n.ID)
	}
	w.Header().Set(headerParticipants, nodes[:len(nodes)-1])
	w.Header().Set(headerRespTime, time.Duration(stats.RespTime).String())
}

func setNodeGroupHeaders(w http.ResponseWriter, g, p int, node hexatype.Node) {
	w.Header().Set(headerGroup, fmt.Sprintf("%d", g))
	w.Header().Set(headerNodeHBeat, fmt.Sprintf("%d", node.Heartbeats))
	w.Header().Set(headerNodePriority, fmt.Sprintf("%d", p))
}

// writeJSONResponse writes a json response.  It first sets the headers, then the code and
// finally the data.  It manages serializing the data.  It data is a byte slice then it simply
// writes the data without setting any content type headers
func writeJSONResponse(w http.ResponseWriter, code int, headers map[string]string, data interface{}, err error) {

	w.Header().Set("Content-Type", "application/json")

	var (
		b []byte
		c = code
	)

	// Make sure the code is > 400 if it is an error otherwise set it to 400
	if err != nil {
		if code < 400 {
			c = 400
		}
		// Error data
		b = []byte(`{"error":"` + err.Error() + `"}`)

	} else {
		if data != nil {
			// Write byte slice directly
			if t, ok := data.([]byte); ok {
				b = t
			} else {
				b, _ = json.Marshal(data)
			}
		}

	}

	// Set headers supplied as input
	if headers != nil {
		for k, v := range headers {
			w.Header().Set(k, v)
		}
	}

	// Set ACL headers after so they are not overwritten by the caller
	for k, v := range accessControlHeaders {
		w.Header().Set(k, v)
	}

	// Write code
	w.WriteHeader(c)
	// Write data
	w.Write(b)
}
<commit_msg>JSON marshal check<commit_after>package gateway

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/hexablock/fidias"
	"github.com/hexablock/hexatype"
	"github.com/hexablock/phi"
)

const (
	headerBallotTime     = "Ballot-Time"
	headerBlockSize      = "Block-Size"
	headerBlockWriteTime = "Block-Write-Time"
	headerBlockReadTime  = "Block-Read-Time"
	headerBlockCount     = "Block-Count"
	headerFsmTime        = "Fsm-Time"
	headerGroup          = "Group-Index"
	headerLookupTime     = "Lookup-Time"
	headerNodeHBeat      = "Node-Heartbeats"
	headerNodeRTT        = "Node-Rtt"
	headerNodePriority   = "Node-Priority"
	headerParticipants   = "Participants"
	headerRespTime       = "Response-Time"
	headerRuntime        = "Runtime"
)

var accessControlHeaders = map[string]string{
	"Access-Control-Allow-Origin": "*",
}

type HTTPServer struct {
	DHT    phi.DHT
	Device *phi.BlockDevice
	KVS    *fidias.KVS
}

func (server *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	reqpath := r.URL.Path[1:]
	if reqpath == "" {
		w.WriteHeader(404)
		return
	}

	endpoint, resource := parseDirBase(reqpath)

	switch endpoint {
	case "dht":
		if resource == "" {
			w.WriteHeader(404)
			return
		}
		server.handleDHT(w, r, resource)

	case "blox":
		server.handleBlox(w, r, resource)

	case "kv":
		if resource == "" {
			w.WriteHeader(404)
			return
		}
		server.handleKV(w, r, resource)

	default:
		w.WriteHeader(404)
	}

}

func setWriteHeaderStats(w http.ResponseWriter, stats *phi.WriteStats) {
	w.Header().Set(headerBallotTime, fmt.Sprintf("%v", stats.BallotTime))
	w.Header().Set(headerFsmTime, fmt.Sprintf("%v", stats.ApplyTime))

	hosts := make([]string, 0, len(stats.Participants))
	for _, p := range stats.Participants {
		hosts = append(hosts, fmt.Sprintf("%s/%x", p.Host, p.ID))
	}
	w.Header().Set(headerParticipants, strings.Join(hosts, ","))
}

// setReadHeader sets common read headers.
func setReadHeader(w http.ResponseWriter, stats *fidias.ReadStats) {
	var nodes string
	for _, n := range stats.Nodes {
		nodes += fmt.Sprintf("%s/%x,", n.Host(), n.ID)
	}
	w.Header().Set(headerParticipants, nodes[:len(nodes)-1])
	w.Header().Set(headerRespTime, time.Duration(stats.RespTime).String())
}

func setNodeGroupHeaders(w http.ResponseWriter, g, p int, node hexatype.Node) {
	w.Header().Set(headerGroup, fmt.Sprintf("%d", g))
	w.Header().Set(headerNodeHBeat, fmt.Sprintf("%d", node.Heartbeats))
	w.Header().Set(headerNodePriority, fmt.Sprintf("%d", p))
}

// writeJSONResponse writes a json response.  It first sets the headers, then the code and
// finally the data.  It manages serializing the data.  It data is a byte slice then it simply
// writes the data without setting any content type headers
func writeJSONResponse(w http.ResponseWriter, code int, headers map[string]string, data interface{}, err error) {

	w.Header().Set("Content-Type", "application/json")

	var (
		b []byte
		c = code
	)

	// Make sure the code is > 400 if it is an error otherwise set it to 400
	if err != nil {
		if code < 400 {
			c = 400
		}
		// Error data
		b = []byte(`{"error":"` + err.Error() + `"}`)

	} else {
		if data != nil {
			// Write byte slice directly
			if t, ok := data.([]byte); ok {
				b = t
			} else {
				if b, err = json.Marshal(data); err != nil {

					c = 500
					b = []byte(`{"error":"` + err.Error() + `"}`)

				}
			}
		}

	}

	// Set headers supplied as input
	if headers != nil {
		for k, v := range headers {
			w.Header().Set(k, v)
		}
	}

	// Set ACL headers after so they are not overwritten by the caller
	for k, v := range accessControlHeaders {
		w.Header().Set(k, v)
	}

	// Write code
	w.WriteHeader(c)
	// Write data
	w.Write(b)
}
<|endoftext|>


<commit_before>package midi

import (
	"github.com/boomlinde/acidforth/collection"
	"github.com/boomlinde/acidforth/machine"
	"github.com/rakyll/portmidi"
)

type Hook struct {
	Value uint8
}

type Midi struct {
	KeyHooks       []*Hook
	ControlHooks   []*Hook
	MomentaryHooks []*Hook
	VelocityHooks  []*Hook
	ch             <-chan portmidi.Event
	patch          Hook
}

func NewMidi(ch <-chan portmidi.Event) *Midi {
	keyHooks := make([]*Hook, 128)
	controlHooks := make([]*Hook, 128)
	momentaryHooks := make([]*Hook, 128)
	velocityHooks := make([]*Hook, 128)
	for i := 0; i < 128; i++ {
		keyHooks[i] = &Hook{}
		controlHooks[i] = &Hook{}
		momentaryHooks[i] = &Hook{}
		velocityHooks[i] = &Hook{}
	}

	return &Midi{
		KeyHooks:       keyHooks,
		ControlHooks:   controlHooks,
		MomentaryHooks: momentaryHooks,
		VelocityHooks:  velocityHooks,
		ch:             ch,
		patch:          Hook{},
	}
}

func (m *Midi) Listen() {
	for event := range m.ch {
		msg := event.Status >> 4
		switch {
		case msg == 9:
			h := m.KeyHooks[event.Data1&0x7f]
			if h.Value == 0 {
				h.Value = 1
			} else {
				h.Value = 0
			}
			h = m.MomentaryHooks[event.Data1&0x7f]
			h.Value = 1
			h = m.VelocityHooks[event.Data1&0x7f]
			h.Value = uint8(event.Data2 & 0x7f)
		case msg == 11:
			h := m.ControlHooks[event.Data1]
			h.Value = uint8(event.Data2 & 0x7f)
		case msg == 8:
			h := m.MomentaryHooks[event.Data1&0x7f]
			h.Value = 0
		case msg == 12:
			m.patch.Value = uint8(event.Data2 & 0x7f)
		}
	}
}

func (m *Midi) Register(c *collection.Collection) {
	c.Machine.Register("patch", func(s *machine.Stack) {
		s.Push(float64(m.patch.Value))
	})
	c.Machine.Register("cc", func(s *machine.Stack) {
		h := m.ControlHooks[int(s.Pop())]
		s.Push(float64(h.Value) / 127)
	})
	c.Machine.Register("key", func(s *machine.Stack) {
		h := m.KeyHooks[int(s.Pop())]
		s.Push(float64(h.Value))
	})
	c.Machine.Register("mom", func(s *machine.Stack) {
		h := m.MomentaryHooks[int(s.Pop())]
		s.Push(float64(h.Value))
	})
	c.Machine.Register("vel", func(s *machine.Stack) {
		h := m.VelocityHooks[int(s.Pop())]
		s.Push(float64(h.Value) / 127)
	})
}
<commit_msg>arrays, not slices<commit_after>package midi

import (
	"github.com/boomlinde/acidforth/collection"
	"github.com/boomlinde/acidforth/machine"
	"github.com/rakyll/portmidi"
)

type Hook struct {
	Value uint8
}

type Midi struct {
	KeyHooks       [128]*Hook
	ControlHooks   [128]*Hook
	MomentaryHooks [128]*Hook
	VelocityHooks  [128]*Hook
	ch             <-chan portmidi.Event
	patch          Hook
}

func NewMidi(ch <-chan portmidi.Event) *Midi {
	keyHooks := [128]*Hook{}
	controlHooks := [128]*Hook{}
	momentaryHooks := [128]*Hook{}
	velocityHooks := [128]*Hook{}
	for i := 0; i < 128; i++ {
		keyHooks[i] = &Hook{}
		controlHooks[i] = &Hook{}
		momentaryHooks[i] = &Hook{}
		velocityHooks[i] = &Hook{}
	}

	return &Midi{
		KeyHooks:       keyHooks,
		ControlHooks:   controlHooks,
		MomentaryHooks: momentaryHooks,
		VelocityHooks:  velocityHooks,
		ch:             ch,
		patch:          Hook{},
	}
}

func (m *Midi) Listen() {
	for event := range m.ch {
		msg := event.Status >> 4
		switch {
		case msg == 9:
			h := m.KeyHooks[event.Data1&0x7f]
			if h.Value == 0 {
				h.Value = 1
			} else {
				h.Value = 0
			}
			h = m.MomentaryHooks[event.Data1&0x7f]
			h.Value = 1
			h = m.VelocityHooks[event.Data1&0x7f]
			h.Value = uint8(event.Data2 & 0x7f)
		case msg == 11:
			h := m.ControlHooks[event.Data1]
			h.Value = uint8(event.Data2 & 0x7f)
		case msg == 8:
			h := m.MomentaryHooks[event.Data1&0x7f]
			h.Value = 0
		case msg == 12:
			m.patch.Value = uint8(event.Data2 & 0x7f)
		}
	}
}

func (m *Midi) Register(c *collection.Collection) {
	c.Machine.Register("patch", func(s *machine.Stack) {
		s.Push(float64(m.patch.Value))
	})
	c.Machine.Register("cc", func(s *machine.Stack) {
		h := m.ControlHooks[int(s.Pop())]
		s.Push(float64(h.Value) / 127)
	})
	c.Machine.Register("key", func(s *machine.Stack) {
		h := m.KeyHooks[int(s.Pop())]
		s.Push(float64(h.Value))
	})
	c.Machine.Register("mom", func(s *machine.Stack) {
		h := m.MomentaryHooks[int(s.Pop())]
		s.Push(float64(h.Value))
	})
	c.Machine.Register("vel", func(s *machine.Stack) {
		h := m.VelocityHooks[int(s.Pop())]
		s.Push(float64(h.Value) / 127)
	})
}
<|endoftext|>


<commit_before>package gochecks

import (
	"fmt"
	"strings"
	"log"

	"encoding/json"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/jsoriano/goryman"
)

const (
	riemannDescriptionMaxLength = 250
)

// CheckPublisher define the check result Publisher
type CheckPublisher interface {
	PublishCheckResult(Event)
}

// LogPublisher object to log each check result
type LogPublisher struct{}

// NewLogPublisher return a new LogPublisher
func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

// PublishCheckResult log the event
func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

// ChannelPublisher object to publish to a channel each check result
type ChannelPublisher struct {
	Channel chan Event
}

// NewChannelPublisher return a new ChannelPublisher
func NewChannelPublisher(c chan Event) ChannelPublisher {
	return ChannelPublisher{c}
}

// PublishCheckResult send the event to the publisher channel
func (p ChannelPublisher) PublishCheckResult(event Event) {
	p.Channel <- event
}

// RabbitMqPublisher object to publish the event to a rabbitmq exchange
type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

// NewRabbitMqPublisher return a publisher to send to RabbitMq exchange
func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

// PublishCheckResult publish the event to a configured rabbitmq exchange
func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	service := strings.Replace(event.Service, " ", ".", -1)
	topic := fmt.Sprintf("check.%s.%s", event.Host, service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

// RiemannPublisher object to publish events to a riemann server
type RiemannPublisher struct {
	client *goryman.GorymanClient
}

// NewRiemannPublisher return a publisher to send directly to a riemann instance
func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

// PublishCheckResult return a publisher to send directly to a riemann instance
func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Println("[error] publishing check", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: p.normalizeDescriptionLength(event.Description),
		Host: event.Host,
		Service: event.Service,
		State: event.State,
		Metric: event.Metric,
		Tags: event.Tags,
		Attributes: event.Attributes,
		Ttl: event.TTL}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Println("[error] sending check", event)
		return
	}
}

func (p RiemannPublisher) normalizeDescriptionLength(description string) string {
	if len(description) < riemannDescriptionMaxLength {
		return description
	}
	return description[0:riemannDescriptionMaxLength]
}
<commit_msg>new riemann client path changed<commit_after>package gochecks

import (
	"fmt"
	"log"
	"strings"

	"encoding/json"

	"github.com/aleasoluciones/goryman"
	"github.com/aleasoluciones/simpleamqp"
)

const (
	riemannDescriptionMaxLength = 250
)

// CheckPublisher define the check result Publisher
type CheckPublisher interface {
	PublishCheckResult(Event)
}

// LogPublisher object to log each check result
type LogPublisher struct{}

// NewLogPublisher return a new LogPublisher
func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

// PublishCheckResult log the event
func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

// ChannelPublisher object to publish to a channel each check result
type ChannelPublisher struct {
	Channel chan Event
}

// NewChannelPublisher return a new ChannelPublisher
func NewChannelPublisher(c chan Event) ChannelPublisher {
	return ChannelPublisher{c}
}

// PublishCheckResult send the event to the publisher channel
func (p ChannelPublisher) PublishCheckResult(event Event) {
	p.Channel <- event
}

// RabbitMqPublisher object to publish the event to a rabbitmq exchange
type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

// NewRabbitMqPublisher return a publisher to send to RabbitMq exchange
func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

// PublishCheckResult publish the event to a configured rabbitmq exchange
func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	service := strings.Replace(event.Service, " ", ".", -1)
	topic := fmt.Sprintf("check.%s.%s", event.Host, service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

// RiemannPublisher object to publish events to a riemann server
type RiemannPublisher struct {
	client *goryman.GorymanClient
}

// NewRiemannPublisher return a publisher to send directly to a riemann instance
func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

// PublishCheckResult return a publisher to send directly to a riemann instance
func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Println("[error] publishing check", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: p.normalizeDescriptionLength(event.Description),
		Host:       event.Host,
		Service:    event.Service,
		State:      event.State,
		Metric:     event.Metric,
		Tags:       event.Tags,
		Attributes: event.Attributes,
		Ttl:        event.TTL}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Println("[error] sending check", event)
		return
	}
}

func (p RiemannPublisher) normalizeDescriptionLength(description string) string {
	if len(description) < riemannDescriptionMaxLength {
		return description
	}
	return description[0:riemannDescriptionMaxLength]
}
<|endoftext|>