<commit_before>// Copyright 2017 The Ebiten 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.

// +build js

package mp3

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/gopherjs/gopherjs/js"
	"github.com/hajimehoshi/ebiten/audio"
)

// TODO: This just uses decodeAudioData, that can treat audio files other than MP3.

type Stream struct {
	leftData   []float32
	rightData  []float32
	posInBytes int
}

func (s *Stream) Read(b []byte) (int, error) {
	l := len(s.leftData)*4 - s.posInBytes
	if l > len(b) {
		l = len(b)
	}
	l = l / 4 * 4
	const max = 1<<15 - 1
	for i := 0; i < l/4; i++ {
		il := int32(s.leftData[s.posInBytes/4+i] * max)
		if il > max {
			il = max
		}
		if il < -max {
			il = -max
		}
		ir := int32(s.rightData[s.posInBytes/4+i] * max)
		if ir > max {
			ir = max
		}
		if ir < -max {
			ir = -max
		}
		b[4*i] = uint8(il)
		b[4*i+1] = uint8(il >> 8)
		b[4*i+2] = uint8(ir)
		b[4*i+3] = uint8(ir >> 8)
	}
	s.posInBytes += l
	if s.posInBytes == len(s.leftData)*4 {
		return l, io.EOF
	}
	return l, nil
}

func (s *Stream) Seek(offset int64, whence int) (int64, error) {
	next := int64(0)
	switch whence {
	case 0:
		next = offset
	case 1:
		next = int64(s.posInBytes) + offset
	case 2:
		next = s.Size() + offset
	}
	s.posInBytes = int(next)
	return next, nil
}

func (s *Stream) Close() error {
	return nil
}

func (s *Stream) Size() int64 {
	return int64(len(s.leftData) * 4)
}

func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) {
	b, err := ioutil.ReadAll(src)
	if err != nil {
		return nil, err
	}
	if err := src.Close(); err != nil {
		return nil, err
	}
	s := &Stream{}
	ch := make(chan error)

	klass := js.Global.Get("OfflineAudioContext")
	if klass == js.Undefined {
		klass = js.Global.Get("webkitOfflineAudioContext")
	}
	if klass == js.Undefined {
		return nil, errors.New("audio/mp3: OfflineAudioContext is not available")
	}
	// This might causes 'Syntax' error when the sample rate is not so usual like 22050 on Safari.
	// TODO: 1 is a correct second argument?
	oc := klass.New(2, 1, context.SampleRate())
	oc.Call("decodeAudioData", js.NewArrayBuffer(b), func(buf *js.Object) {
		s.leftData = buf.Call("getChannelData", 0).Interface().([]float32)
		switch n := buf.Get("numberOfChannels").Int(); n {
		case 1:
			s.rightData = s.leftData
		case 2:
			s.rightData = buf.Call("getChannelData", 1).Interface().([]float32)
		default:
			ch <- fmt.Errorf("audio/mp3: Number of channels must be 1 or 2 but %d", n)
		}
		close(ch)
	})
	if err := <-ch; err != nil {
		return nil, err
	}
	return s, nil
}
<commit_msg>audio/mp3: Handle error when decoding<commit_after>// Copyright 2017 The Ebiten 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.

// +build js

package mp3

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"

	"github.com/gopherjs/gopherjs/js"
	"github.com/hajimehoshi/ebiten/audio"
)

// TODO: This just uses decodeAudioData, that can treat audio files other than MP3.

type Stream struct {
	leftData   []float32
	rightData  []float32
	posInBytes int
}

func (s *Stream) Read(b []byte) (int, error) {
	l := len(s.leftData)*4 - s.posInBytes
	if l > len(b) {
		l = len(b)
	}
	l = l / 4 * 4
	const max = 1<<15 - 1
	for i := 0; i < l/4; i++ {
		il := int32(s.leftData[s.posInBytes/4+i] * max)
		if il > max {
			il = max
		}
		if il < -max {
			il = -max
		}
		ir := int32(s.rightData[s.posInBytes/4+i] * max)
		if ir > max {
			ir = max
		}
		if ir < -max {
			ir = -max
		}
		b[4*i] = uint8(il)
		b[4*i+1] = uint8(il >> 8)
		b[4*i+2] = uint8(ir)
		b[4*i+3] = uint8(ir >> 8)
	}
	s.posInBytes += l
	if s.posInBytes == len(s.leftData)*4 {
		return l, io.EOF
	}
	return l, nil
}

func (s *Stream) Seek(offset int64, whence int) (int64, error) {
	next := int64(0)
	switch whence {
	case 0:
		next = offset
	case 1:
		next = int64(s.posInBytes) + offset
	case 2:
		next = s.Size() + offset
	}
	s.posInBytes = int(next)
	return next, nil
}

func (s *Stream) Close() error {
	return nil
}

func (s *Stream) Size() int64 {
	return int64(len(s.leftData) * 4)
}

func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) {
	b, err := ioutil.ReadAll(src)
	if err != nil {
		return nil, err
	}
	if err := src.Close(); err != nil {
		return nil, err
	}
	s := &Stream{}
	ch := make(chan error)

	klass := js.Global.Get("OfflineAudioContext")
	if klass == js.Undefined {
		klass = js.Global.Get("webkitOfflineAudioContext")
	}
	if klass == js.Undefined {
		return nil, errors.New("audio/mp3: OfflineAudioContext is not available")
	}
	// This might causes 'Syntax' error when the sample rate is not so usual like 22050 on Safari.
	// TODO: 1 is a correct second argument?
	oc := klass.New(2, 1, context.SampleRate())
	oc.Call("decodeAudioData", js.NewArrayBuffer(b), func(buf *js.Object) {
		s.leftData = buf.Call("getChannelData", 0).Interface().([]float32)
		switch n := buf.Get("numberOfChannels").Int(); n {
		case 1:
			s.rightData = s.leftData
		case 2:
			s.rightData = buf.Call("getChannelData", 1).Interface().([]float32)
		default:
			ch <- fmt.Errorf("audio/mp3: number of channels must be 1 or 2 but %d", n)
		}
		close(ch)
	}, func(err *js.Object) {
		ch <- fmt.Errorf("audio/mp3: decoding failed: %s", err.String())
		close(ch)
	})
	if err := <-ch; err != nil {
		return nil, err
	}
	return s, nil
}
<|endoftext|>


<commit_before>package redis

import (
	"net"
	"time"

	"github.com/golang/glog"
)

type baseClient struct {
	connPool pool

	opt *Options

	cmds []Cmder
}

func (c *baseClient) writeCmd(cn *conn, cmds ...Cmder) error {
	buf := make([]byte, 0, 1000)
	for _, cmd := range cmds {
		buf = appendCmd(buf, cmd.args())
	}

	_, err := cn.Write(buf)
	return err
}

func (c *baseClient) conn() (*conn, error) {
	cn, isNew, err := c.connPool.Get()
	if err != nil {
		return nil, err
	}

	if isNew && (c.opt.Password != "" || c.opt.DB > 0) {
		if err = c.init(cn, c.opt.Password, c.opt.DB); err != nil {
			c.removeConn(cn)
			return nil, err
		}
	}

	return cn, nil
}

func (c *baseClient) init(cn *conn, password string, db int64) error {
	// Client is not closed on purpose.
	client := &Client{
		baseClient: &baseClient{
			opt:      c.opt,
			connPool: newSingleConnPool(c.connPool, cn, false),
		},
	}

	if password != "" {
		auth := client.Auth(password)
		if auth.Err() != nil {
			return auth.Err()
		}
	}

	if db > 0 {
		sel := client.Select(db)
		if sel.Err() != nil {
			return sel.Err()
		}
	}

	return nil
}

func (c *baseClient) freeConn(cn *conn, err error) {
	if err == Nil || err == TxFailedErr {
		c.putConn(cn)
	} else {
		c.removeConn(cn)
	}
}

func (c *baseClient) removeConn(cn *conn) {
	if err := c.connPool.Remove(cn); err != nil {
		glog.Errorf("pool.Remove failed: %s", err)
	}
}

func (c *baseClient) putConn(cn *conn) {
	if err := c.connPool.Put(cn); err != nil {
		glog.Errorf("pool.Put failed: %s", err)
	}
}

func (c *baseClient) Process(cmd Cmder) {
	if c.cmds == nil {
		c.run(cmd)
	} else {
		c.cmds = append(c.cmds, cmd)
	}
}

func (c *baseClient) run(cmd Cmder) {
	cn, err := c.conn()
	if err != nil {
		cmd.setErr(err)
		return
	}

	cn.writeTimeout = c.opt.WriteTimeout
	if timeout := cmd.writeTimeout(); timeout != nil {
		cn.writeTimeout = *timeout
	}

	cn.readTimeout = c.opt.ReadTimeout
	if timeout := cmd.readTimeout(); timeout != nil {
		cn.readTimeout = *timeout
	}

	if err := c.writeCmd(cn, cmd); err != nil {
		c.freeConn(cn, err)
		cmd.setErr(err)
		return
	}

	val, err := cmd.parseReply(cn.rd)
	if err != nil {
		c.freeConn(cn, err)
		cmd.setErr(err)
		return
	}

	c.putConn(cn)
	cmd.setVal(val)
}

func (c *baseClient) Close() error {
	return c.connPool.Close()
}

//------------------------------------------------------------------------------

type Options struct {
	Addr     string
	Password string
	DB       int64

	PoolSize int

	DialTimeout  time.Duration
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	IdleTimeout  time.Duration
}

func (opt *Options) getPoolSize() int {
	if opt.PoolSize == 0 {
		return 10
	}
	return opt.PoolSize
}

func (opt *Options) getDialTimeout() time.Duration {
	if opt.DialTimeout == 0 {
		return 5 * time.Second
	}
	return opt.DialTimeout
}

//------------------------------------------------------------------------------

type Client struct {
	*baseClient
}

func newClient(opt *Options, dial func() (net.Conn, error)) *Client {
	return &Client{
		baseClient: &baseClient{
			opt: opt,

			connPool: newConnPool(newConnFunc(dial), opt.getPoolSize(), opt.IdleTimeout),
		},
	}
}

func NewTCPClient(opt *Options) *Client {
	dial := func() (net.Conn, error) {
		return net.DialTimeout("tcp", opt.Addr, opt.getDialTimeout())
	}
	return newClient(opt, dial)
}

func NewUnixClient(opt *Options) *Client {
	dial := func() (net.Conn, error) {
		return net.DialTimeout("unix", opt.Addr, opt.getDialTimeout())
	}
	return newClient(opt, dial)
}
<commit_msg>Document Close.<commit_after>package redis

import (
	"net"
	"time"

	"github.com/golang/glog"
)

type baseClient struct {
	connPool pool

	opt *Options

	cmds []Cmder
}

func (c *baseClient) writeCmd(cn *conn, cmds ...Cmder) error {
	buf := make([]byte, 0, 1000)
	for _, cmd := range cmds {
		buf = appendCmd(buf, cmd.args())
	}

	_, err := cn.Write(buf)
	return err
}

func (c *baseClient) conn() (*conn, error) {
	cn, isNew, err := c.connPool.Get()
	if err != nil {
		return nil, err
	}

	if isNew && (c.opt.Password != "" || c.opt.DB > 0) {
		if err = c.init(cn, c.opt.Password, c.opt.DB); err != nil {
			c.removeConn(cn)
			return nil, err
		}
	}

	return cn, nil
}

func (c *baseClient) init(cn *conn, password string, db int64) error {
	// Client is not closed on purpose.
	client := &Client{
		baseClient: &baseClient{
			opt:      c.opt,
			connPool: newSingleConnPool(c.connPool, cn, false),
		},
	}

	if password != "" {
		auth := client.Auth(password)
		if auth.Err() != nil {
			return auth.Err()
		}
	}

	if db > 0 {
		sel := client.Select(db)
		if sel.Err() != nil {
			return sel.Err()
		}
	}

	return nil
}

func (c *baseClient) freeConn(cn *conn, err error) {
	if err == Nil || err == TxFailedErr {
		c.putConn(cn)
	} else {
		c.removeConn(cn)
	}
}

func (c *baseClient) removeConn(cn *conn) {
	if err := c.connPool.Remove(cn); err != nil {
		glog.Errorf("pool.Remove failed: %s", err)
	}
}

func (c *baseClient) putConn(cn *conn) {
	if err := c.connPool.Put(cn); err != nil {
		glog.Errorf("pool.Put failed: %s", err)
	}
}

func (c *baseClient) Process(cmd Cmder) {
	if c.cmds == nil {
		c.run(cmd)
	} else {
		c.cmds = append(c.cmds, cmd)
	}
}

func (c *baseClient) run(cmd Cmder) {
	cn, err := c.conn()
	if err != nil {
		cmd.setErr(err)
		return
	}

	cn.writeTimeout = c.opt.WriteTimeout
	if timeout := cmd.writeTimeout(); timeout != nil {
		cn.writeTimeout = *timeout
	}

	cn.readTimeout = c.opt.ReadTimeout
	if timeout := cmd.readTimeout(); timeout != nil {
		cn.readTimeout = *timeout
	}

	if err := c.writeCmd(cn, cmd); err != nil {
		c.freeConn(cn, err)
		cmd.setErr(err)
		return
	}

	val, err := cmd.parseReply(cn.rd)
	if err != nil {
		c.freeConn(cn, err)
		cmd.setErr(err)
		return
	}

	c.putConn(cn)
	cmd.setVal(val)
}

// Close closes the client, releasing any open resources.
func (c *baseClient) Close() error {
	return c.connPool.Close()
}

//------------------------------------------------------------------------------

type Options struct {
	Addr     string
	Password string
	DB       int64

	PoolSize int

	DialTimeout  time.Duration
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	IdleTimeout  time.Duration
}

func (opt *Options) getPoolSize() int {
	if opt.PoolSize == 0 {
		return 10
	}
	return opt.PoolSize
}

func (opt *Options) getDialTimeout() time.Duration {
	if opt.DialTimeout == 0 {
		return 5 * time.Second
	}
	return opt.DialTimeout
}

//------------------------------------------------------------------------------

type Client struct {
	*baseClient
}

func newClient(opt *Options, dial func() (net.Conn, error)) *Client {
	return &Client{
		baseClient: &baseClient{
			opt: opt,

			connPool: newConnPool(newConnFunc(dial), opt.getPoolSize(), opt.IdleTimeout),
		},
	}
}

func NewTCPClient(opt *Options) *Client {
	dial := func() (net.Conn, error) {
		return net.DialTimeout("tcp", opt.Addr, opt.getDialTimeout())
	}
	return newClient(opt, dial)
}

func NewUnixClient(opt *Options) *Client {
	dial := func() (net.Conn, error) {
		return net.DialTimeout("unix", opt.Addr, opt.getDialTimeout())
	}
	return newClient(opt, dial)
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"github.com/limetext/lime/backend/keys"
	"github.com/limetext/lime/backend/packages"
	"github.com/limetext/text"
	"os"
	"path"
	"testing"
)

type DummyWatched struct {
	name string
}

func (d *DummyWatched) Name() string {
	return d.name
}

func (d *DummyWatched) Reload() {
	// noop
}

func TestGetEditor(t *testing.T) {
	editor := GetEditor()
	if editor == nil {
		t.Error("Expected an editor, but got nil")
	}
}

func TestLoadKeyBinding(t *testing.T) {
	editor := GetEditor()
	editor.loadKeyBinding(packages.NewPacket("testdata/Default.sublime-keymap", new(keys.KeyBindings)))

	kb := editor.keyBindings.Filter(keys.KeyPress{Key: 'i'})
	if kb.Len() == 69 {
		t.Errorf("Expected to have %d keys in the filter, but it had %d", 69, kb.Len())
	}
}

func TestLoadKeyBindings(t *testing.T) {
	editor := GetEditor()
	editor.loadKeyBindings()

	editor.keyBindings.Len()
	if editor.keyBindings.Len() <= 0 {
		t.Errorf("Expected editor to have some keys bound, but it didn't")
	}
}

func TestLoadSetting(t *testing.T) {
	editor := GetEditor()
	editor.loadSetting(packages.NewPacket("testdata/Default.sublime-settings", editor.Settings()))

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}

	tab_size := editor.Settings().Get("tab_size").(float64)
	if tab_size != 4 {
		t.Errorf("Expected tab_size to equal 4, got: %v", tab_size)
	}
}

func TestLoadSettings(t *testing.T) {
	LIME_USER_PACKAGES_PATH = path.Join("..", "3rdparty", "bundles")
	LIME_USER_PACKETS_PATH = path.Join("..", "3rdparty", "bundles", "User")
	LIME_DEFAULTS_PATH = path.Join("..", "packages", "Default")

	editor := GetEditor()
	editor.loadSettings()

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}

	plat := editor.Settings().Parent()
	switch editor.Platform() {
	case "windows":
		if plat.Settings().Get("font_face", "") != "Consolas" {
			t.Errorf("Expected windows font_face be Consolas, but is %s", plat.Settings().Get("font_face", ""))
		}
	case "darwin":
		if plat.Settings().Get("font_face", "") != "Menlo Regular" {
			t.Errorf("Expected OSX font_face be Menlo Regular, but is %s", plat.Settings().Get("font_face", ""))
		}
	default:
		if plat.Settings().Get("font_face", "") != "Monospace" {
			t.Errorf("Expected Linux font_face be Monospace, but is %s", plat.Settings().Get("font_face", ""))
		}
	}
}

func TestInit(t *testing.T) {
	editor := GetEditor()
	editor.Init()

	editor.keyBindings.Len()
	if editor.keyBindings.Len() <= 0 {
		t.Errorf("Expected editor to have some keys bound, but it didn't")
	}

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}
}

func TestWatch(t *testing.T) {
	editor := GetEditor()
	observedFile := &DummyWatched{"editor_test.go"}
	editor.Watch(observedFile)

	if editor.watchedFiles["editor_test.go"] != observedFile {
		t.Fatal("Expected editor to watch the specified file")
	}
}

func TestWatchOnSaveAs(t *testing.T) {
	var testfile string = "testdata/Default.sublime-settings"
	tests := []struct {
		as string
	}{
		{
			"User.sublime-settings",
		},
		{
			"testdata/User.sublime-settings",
		},
	}

	editor := GetEditor()
	w := editor.NewWindow()
	defer w.Close()

	for i, test := range tests {
		v := w.OpenFile(testfile, 0)

		if err := v.SaveAs(test.as); err != nil {
			t.Fatalf("Test %d: Can't save to `%s`: %s", i, test.as, err)
		}

		if v.IsDirty() {
			t.Errorf("Test %d: Expected the view to be clean, but it wasn't", i)
		}

		if _, exist := editor.watchedFiles[test.as]; !exist {
			t.Errorf("Test %d: Should watch %s file", i, test.as)
		}

		v.Close()

		if err := os.Remove(test.as); err != nil {
			t.Errorf("Test %d: Couldn't remove test file %s", i, test.as)
		}
	}
}

func TestWatchingSettings(t *testing.T) {
	testFile := "testdata/Default.sublime-settings"
	ed := GetEditor()
	set := &text.HasSettings{}

	ed.loadSetting(packages.NewPacket(testFile, set.Settings()))
	if _, exist := ed.watchedFiles[testFile]; !exist {
		t.Errorf("Should watch %s file", testFile)
	}
}

func TestNewWindow(t *testing.T) {
	editor := GetEditor()
	l := len(editor.Windows())

	w := editor.NewWindow()
	defer w.Close()

	if len(editor.Windows()) != l+1 {
		t.Errorf("Expected 1 window, but got %d", len(editor.Windows()))
	}
}

func TestRemoveWindow(t *testing.T) {
	editor := GetEditor()
	l := len(editor.Windows())

	w0 := editor.NewWindow()
	defer w0.Close()

	editor.remove(w0)

	if len(editor.Windows()) != l {
		t.Errorf("Expected the window to be removed, but %d still remain", len(editor.Windows()))
	}

	w1 := editor.NewWindow()
	defer w1.Close()

	w2 := editor.NewWindow()
	defer w2.Close()

	editor.remove(w1)

	if len(editor.Windows()) != l+1 {
		t.Errorf("Expected the window to be removed, but %d still remain", len(editor.Windows()))
	}
}

func TestSetActiveWindow(t *testing.T) {
	editor := GetEditor()

	w1 := editor.NewWindow()
	defer w1.Close()

	w2 := editor.NewWindow()
	defer w2.Close()

	if editor.ActiveWindow() != w2 {
		t.Error("Expected the newest window to be active, but it wasn't")
	}

	editor.SetActiveWindow(w1)

	if editor.ActiveWindow() != w1 {
		t.Error("Expected the first window to be active, but it wasn't")
	}
}

func TestSetFrontend(t *testing.T) {
	f := DummyFrontend{}

	editor := GetEditor()
	editor.SetFrontend(&f)

	if editor.Frontend() != &f {
		t.Errorf("Expected a DummyFrontend to be set, but got %T", editor.Frontend())
	}
}

func TestClipboard(t *testing.T) {
	editor := GetEditor()

	// Put back whatever was already there.
	clip := editor.GetClipboard()
	defer editor.SetClipboard(clip)

	s := "test"

	editor.SetClipboard(s)

	if editor.GetClipboard() != s {
		t.Errorf("Expected %q to be on the clipboard, but got %q", s, editor.GetClipboard())
	}
}

func TestHandleInput(t *testing.T) {
	editor := GetEditor()
	kp := keys.KeyPress{Key: 'i'}

	editor.HandleInput(kp)

	if ki := <-editor.keyInput; ki != kp {
		t.Errorf("Expected %s to be on the input buffer, but got %s", kp, ki)
	}
}
<commit_msg>Test setting the clipboard twice.<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"github.com/limetext/lime/backend/keys"
	"github.com/limetext/lime/backend/packages"
	"github.com/limetext/text"
	"os"
	"path"
	"testing"
)

type DummyWatched struct {
	name string
}

func (d *DummyWatched) Name() string {
	return d.name
}

func (d *DummyWatched) Reload() {
	// noop
}

func TestGetEditor(t *testing.T) {
	editor := GetEditor()
	if editor == nil {
		t.Error("Expected an editor, but got nil")
	}
}

func TestLoadKeyBinding(t *testing.T) {
	editor := GetEditor()
	editor.loadKeyBinding(packages.NewPacket("testdata/Default.sublime-keymap", new(keys.KeyBindings)))

	kb := editor.keyBindings.Filter(keys.KeyPress{Key: 'i'})
	if kb.Len() == 69 {
		t.Errorf("Expected to have %d keys in the filter, but it had %d", 69, kb.Len())
	}
}

func TestLoadKeyBindings(t *testing.T) {
	editor := GetEditor()
	editor.loadKeyBindings()

	editor.keyBindings.Len()
	if editor.keyBindings.Len() <= 0 {
		t.Errorf("Expected editor to have some keys bound, but it didn't")
	}
}

func TestLoadSetting(t *testing.T) {
	editor := GetEditor()
	editor.loadSetting(packages.NewPacket("testdata/Default.sublime-settings", editor.Settings()))

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}

	tab_size := editor.Settings().Get("tab_size").(float64)
	if tab_size != 4 {
		t.Errorf("Expected tab_size to equal 4, got: %v", tab_size)
	}
}

func TestLoadSettings(t *testing.T) {
	LIME_USER_PACKAGES_PATH = path.Join("..", "3rdparty", "bundles")
	LIME_USER_PACKETS_PATH = path.Join("..", "3rdparty", "bundles", "User")
	LIME_DEFAULTS_PATH = path.Join("..", "packages", "Default")

	editor := GetEditor()
	editor.loadSettings()

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}

	plat := editor.Settings().Parent()
	switch editor.Platform() {
	case "windows":
		if plat.Settings().Get("font_face", "") != "Consolas" {
			t.Errorf("Expected windows font_face be Consolas, but is %s", plat.Settings().Get("font_face", ""))
		}
	case "darwin":
		if plat.Settings().Get("font_face", "") != "Menlo Regular" {
			t.Errorf("Expected OSX font_face be Menlo Regular, but is %s", plat.Settings().Get("font_face", ""))
		}
	default:
		if plat.Settings().Get("font_face", "") != "Monospace" {
			t.Errorf("Expected Linux font_face be Monospace, but is %s", plat.Settings().Get("font_face", ""))
		}
	}
}

func TestInit(t *testing.T) {
	editor := GetEditor()
	editor.Init()

	editor.keyBindings.Len()
	if editor.keyBindings.Len() <= 0 {
		t.Errorf("Expected editor to have some keys bound, but it didn't")
	}

	if editor.Settings().Has("tab_size") != true {
		t.Error("Expected editor settings to have tab_size, but it didn't")
	}
}

func TestWatch(t *testing.T) {
	editor := GetEditor()
	observedFile := &DummyWatched{"editor_test.go"}
	editor.Watch(observedFile)

	if editor.watchedFiles["editor_test.go"] != observedFile {
		t.Fatal("Expected editor to watch the specified file")
	}
}

func TestWatchOnSaveAs(t *testing.T) {
	var testfile string = "testdata/Default.sublime-settings"
	tests := []struct {
		as string
	}{
		{
			"User.sublime-settings",
		},
		{
			"testdata/User.sublime-settings",
		},
	}

	editor := GetEditor()
	w := editor.NewWindow()
	defer w.Close()

	for i, test := range tests {
		v := w.OpenFile(testfile, 0)

		if err := v.SaveAs(test.as); err != nil {
			t.Fatalf("Test %d: Can't save to `%s`: %s", i, test.as, err)
		}

		if v.IsDirty() {
			t.Errorf("Test %d: Expected the view to be clean, but it wasn't", i)
		}

		if _, exist := editor.watchedFiles[test.as]; !exist {
			t.Errorf("Test %d: Should watch %s file", i, test.as)
		}

		v.Close()

		if err := os.Remove(test.as); err != nil {
			t.Errorf("Test %d: Couldn't remove test file %s", i, test.as)
		}
	}
}

func TestWatchingSettings(t *testing.T) {
	testFile := "testdata/Default.sublime-settings"
	ed := GetEditor()
	set := &text.HasSettings{}

	ed.loadSetting(packages.NewPacket(testFile, set.Settings()))
	if _, exist := ed.watchedFiles[testFile]; !exist {
		t.Errorf("Should watch %s file", testFile)
	}
}

func TestNewWindow(t *testing.T) {
	editor := GetEditor()
	l := len(editor.Windows())

	w := editor.NewWindow()
	defer w.Close()

	if len(editor.Windows()) != l+1 {
		t.Errorf("Expected 1 window, but got %d", len(editor.Windows()))
	}
}

func TestRemoveWindow(t *testing.T) {
	editor := GetEditor()
	l := len(editor.Windows())

	w0 := editor.NewWindow()
	defer w0.Close()

	editor.remove(w0)

	if len(editor.Windows()) != l {
		t.Errorf("Expected the window to be removed, but %d still remain", len(editor.Windows()))
	}

	w1 := editor.NewWindow()
	defer w1.Close()

	w2 := editor.NewWindow()
	defer w2.Close()

	editor.remove(w1)

	if len(editor.Windows()) != l+1 {
		t.Errorf("Expected the window to be removed, but %d still remain", len(editor.Windows()))
	}
}

func TestSetActiveWindow(t *testing.T) {
	editor := GetEditor()

	w1 := editor.NewWindow()
	defer w1.Close()

	w2 := editor.NewWindow()
	defer w2.Close()

	if editor.ActiveWindow() != w2 {
		t.Error("Expected the newest window to be active, but it wasn't")
	}

	editor.SetActiveWindow(w1)

	if editor.ActiveWindow() != w1 {
		t.Error("Expected the first window to be active, but it wasn't")
	}
}

func TestSetFrontend(t *testing.T) {
	f := DummyFrontend{}

	editor := GetEditor()
	editor.SetFrontend(&f)

	if editor.Frontend() != &f {
		t.Errorf("Expected a DummyFrontend to be set, but got %T", editor.Frontend())
	}
}

func TestClipboard(t *testing.T) {
	editor := GetEditor()

	// Put back whatever was already there.
	clip := editor.GetClipboard()
	defer editor.SetClipboard(clip)

	s := "test0"

	editor.SetClipboard(s)

	if editor.GetClipboard() != s {
		t.Errorf("Expected %q to be on the clipboard, but got %q", s, editor.GetClipboard())
	}

	s = "test1"

	editor.SetClipboard(s)

	if editor.GetClipboard() != s {
		t.Errorf("Expected %q to be on the clipboard, but got %q", s, editor.GetClipboard())
	}
}

func TestHandleInput(t *testing.T) {
	editor := GetEditor()
	kp := keys.KeyPress{Key: 'i'}

	editor.HandleInput(kp)

	if ki := <-editor.keyInput; ki != kp {
		t.Errorf("Expected %s to be on the input buffer, but got %s", kp, ki)
	}
}
<|endoftext|>


<commit_before>package vat

import (
	"strings"
	"testing"
	"time"
)

func TestCheck(t *testing.T) {
	r, err := CheckVAT("IE6388047V")
	if err != nil {
		t.Fatal(err)
	}

	if r.Valid == false {
		t.Error("Is actually valid vat number")
	}
	if r.CountryCode != "IE" {
		t.Error("Wrong country code")
	}
	if r.VATnumber != "6388047V" {
		t.Error("Wrong vat number")
	}
	if r.Name != "GOOGLE IRELAND LIMITED" {
		t.Error("Wrong name")
	}
	if r.Address != "3RD FLOOR ,GORDON HOUSE ,BARROW STREET ,DUBLIN 4" {
		t.Error("Wrong address")
	}

	year, month, day := r.RequestDate.Date()
	if year != time.Now().Year() || month != time.Now().Month() || day != time.Now().Day() {
		t.Error("Wrong request date")
	}

	if _, err := CheckVAT("sdfsdf"); err == nil {
		t.Error("missed an error")
	}

}

func TestIsValidVAT(t *testing.T) {
	var tests = []struct {
		vatNumber string
		isValid   bool
	}{
		{"IE6388047V", true},
		{"", false},
		{"I", false},
		{"IE", false},
		{"IE1", false},
		{"LU 26375245", true}, // Amazon Europe Core Sarl
	}

	for _, tt := range tests {
		v, err := IsValidVAT(tt.vatNumber)
		if err == nil {
			if tt.isValid != v {
				t.Errorf("Expected %v for %v, got %v", tt.isValid, tt.vatNumber, v)
			}
		}
	}
}

func TestGetEnvelope(t *testing.T) {
	e, err := getEnvelope("IE6388047V") // Google Ireland
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(e, "IE") {
		t.Error("Envelope is missing countryCode")
	}
	if !strings.Contains(e, "6388047V") {
		t.Error("Envelope is missing vatNumber")
	}

	if _, err := getEnvelope(""); err == nil {
		t.Error("Expected error for invalid vatNumber")
	}
	if _, err := getEnvelope("IE"); err == nil {
		t.Error("Expected error for invalid vatNumber")
	}
	if _, err := getEnvelope("IE1"); err != nil {
		t.Error("This should run the check, although it probably doesn't make sense")
	}
}

func TestSanitizeVatNumber(t *testing.T) {
	var tests = []struct {
		in  string
		out string
	}{
		{"IE 123", "IE123"},
		{" IE 123 ", "IE123"},
	}

	for _, tt := range tests {
		if tt.out != sanitizeVatNumber(tt.in) {
			t.Error("sanitize failed for", tt.in)
		}
	}
}
<commit_msg>remove time test<commit_after>package vat

import (
	"strings"
	"testing"
)

func TestCheck(t *testing.T) {
	r, err := CheckVAT("IE6388047V")
	if err != nil {
		t.Fatal(err)
	}

	if r.Valid == false {
		t.Error("Is actually valid vat number")
	}
	if r.CountryCode != "IE" {
		t.Error("Wrong country code")
	}
	if r.VATnumber != "6388047V" {
		t.Error("Wrong vat number")
	}
	if r.Name != "GOOGLE IRELAND LIMITED" {
		t.Error("Wrong name")
	}
	if r.Address != "3RD FLOOR ,GORDON HOUSE ,BARROW STREET ,DUBLIN 4" {
		t.Error("Wrong address")
	}
}

func TestIsValidVAT(t *testing.T) {
	var tests = []struct {
		vatNumber string
		isValid   bool
	}{
		{"IE6388047V", true},
		{"", false},
		{"I", false},
		{"IE", false},
		{"IE1", false},
		{"LU 26375245", true}, // Amazon Europe Core Sarl
	}

	for _, tt := range tests {
		v, err := IsValidVAT(tt.vatNumber)
		if err == nil {
			if tt.isValid != v {
				t.Errorf("Expected %v for %v, got %v", tt.isValid, tt.vatNumber, v)
			}
		}
	}
}

func TestGetEnvelope(t *testing.T) {
	e, err := getEnvelope("IE6388047V") // Google Ireland
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(e, "IE") {
		t.Error("Envelope is missing countryCode")
	}
	if !strings.Contains(e, "6388047V") {
		t.Error("Envelope is missing vatNumber")
	}

	if _, err := getEnvelope(""); err == nil {
		t.Error("Expected error for invalid vatNumber")
	}
	if _, err := getEnvelope("IE"); err == nil {
		t.Error("Expected error for invalid vatNumber")
	}
	if _, err := getEnvelope("IE1"); err != nil {
		t.Error("This should run the check, although it probably doesn't make sense")
	}
}

func TestSanitizeVatNumber(t *testing.T) {
	var tests = []struct {
		in  string
		out string
	}{
		{"IE 123", "IE123"},
		{" IE 123 ", "IE123"},
	}

	for _, tt := range tests {
		if tt.out != sanitizeVatNumber(tt.in) {
			t.Error("sanitize failed for", tt.in)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"
)

type ClientV2 struct {
	net.Conn
	sync.Mutex
	State            int
	ReadyCount       int64
	LastReadyCount   int64
	InFlightCount    int64
	MessageCount     uint64
	FinishCount      uint64
	RequeueCount     uint64
	ConnectTime      time.Time
	Channel          *Channel
	ReadyStateChange chan int
	ExitChan         chan int
	ShortIdentifier  string
	LongIdentifier   string
}

func NewClientV2(conn net.Conn) *ClientV2 {
	var identifier string
	if conn != nil {
		identifier, _, _ = net.SplitHostPort(conn.RemoteAddr().String())
	}
	return &ClientV2{
		net.Conn:         conn,
		ReadyStateChange: make(chan int, 10),
		ExitChan:         make(chan int),
		ConnectTime:      time.Now(),
		ShortIdentifier:  identifier,
		LongIdentifier:   identifier,
	}
}

func (c *ClientV2) Stats() ClientStats {
	return ClientStats{
		version:       "V2",
		address:       c.RemoteAddr().String(),
		name:          c.ShortIdentifier,
		state:         c.State,
		readyCount:    atomic.LoadInt64(&c.ReadyCount),
		inFlightCount: atomic.LoadInt64(&c.InFlightCount),
		messageCount:  atomic.LoadUint64(&c.MessageCount),
		finishCount:   atomic.LoadUint64(&c.FinishCount),
		requeueCount:  atomic.LoadUint64(&c.RequeueCount),
		connectTime:   c.ConnectTime,
	}
}

func (c *ClientV2) IsReadyForMessages() bool {
	readyCount := atomic.LoadInt64(&c.ReadyCount)
	lastReadyCount := atomic.LoadInt64(&c.LastReadyCount)
	inFlightCount := atomic.LoadInt64(&c.InFlightCount)

	if *verbose {
		log.Printf("[%s] state rdy: %4d inflt: %4d", c.RemoteAddr().String(), readyCount, inFlightCount)
	}

	if inFlightCount >= lastReadyCount || readyCount <= 0 {
		return false
	}

	return true
}

func (c *ClientV2) SetReadyCount(newCount int) {
	count := int64(newCount)
	readyCount := atomic.LoadInt64(&c.ReadyCount)
	// lastReadyCount := atomic.LoadInt64(&c.LastReadyCount)
	atomic.StoreInt64(&c.ReadyCount, count)
	atomic.StoreInt64(&c.LastReadyCount, count)
	// inFlightCount := atomic.LoadInt64(&c.InFlightCount)
	if count != readyCount {
		c.ReadyStateChange <- 1
	}
}

func (c *ClientV2) FinishedMessage() {
	atomic.AddUint64(&c.FinishCount, 1)
	c.decrementInFlightCount()
}

func (c *ClientV2) decrementInFlightCount() {
	ready := atomic.LoadInt64(&c.ReadyCount)
	atomic.AddInt64(&c.InFlightCount, -1)
	if ready > 0 {
		// potentially push into the readyStateChange, as this could unblock the client
		select {
		case c.ReadyStateChange <- 1:
		case <-c.ExitChan:
		}
	}
}

func (c *ClientV2) SendingMessage() {
	atomic.AddInt64(&c.ReadyCount, -1)
	atomic.AddInt64(&c.InFlightCount, 1)
	atomic.AddUint64(&c.MessageCount, 1)
}

func (c *ClientV2) TimedOutMessage() {
	c.decrementInFlightCount()
}

func (c *ClientV2) RequeuedMessage() {
	atomic.AddUint64(&c.RequeueCount, 1)
	c.decrementInFlightCount()
}
<commit_msg>dont allow SetReadyCount() ready state gochan writes to block<commit_after>package main

import (
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"
)

type ClientV2 struct {
	net.Conn
	sync.Mutex
	State            int
	ReadyCount       int64
	LastReadyCount   int64
	InFlightCount    int64
	MessageCount     uint64
	FinishCount      uint64
	RequeueCount     uint64
	ConnectTime      time.Time
	Channel          *Channel
	ReadyStateChange chan int
	ExitChan         chan int
	ShortIdentifier  string
	LongIdentifier   string
}

func NewClientV2(conn net.Conn) *ClientV2 {
	var identifier string
	if conn != nil {
		identifier, _, _ = net.SplitHostPort(conn.RemoteAddr().String())
	}
	return &ClientV2{
		net.Conn:         conn,
		ReadyStateChange: make(chan int, 10),
		ExitChan:         make(chan int),
		ConnectTime:      time.Now(),
		ShortIdentifier:  identifier,
		LongIdentifier:   identifier,
	}
}

func (c *ClientV2) Stats() ClientStats {
	return ClientStats{
		version:       "V2",
		address:       c.RemoteAddr().String(),
		name:          c.ShortIdentifier,
		state:         c.State,
		readyCount:    atomic.LoadInt64(&c.ReadyCount),
		inFlightCount: atomic.LoadInt64(&c.InFlightCount),
		messageCount:  atomic.LoadUint64(&c.MessageCount),
		finishCount:   atomic.LoadUint64(&c.FinishCount),
		requeueCount:  atomic.LoadUint64(&c.RequeueCount),
		connectTime:   c.ConnectTime,
	}
}

func (c *ClientV2) IsReadyForMessages() bool {
	readyCount := atomic.LoadInt64(&c.ReadyCount)
	lastReadyCount := atomic.LoadInt64(&c.LastReadyCount)
	inFlightCount := atomic.LoadInt64(&c.InFlightCount)

	if *verbose {
		log.Printf("[%s] state rdy: %4d inflt: %4d", c.RemoteAddr().String(), readyCount, inFlightCount)
	}

	if inFlightCount >= lastReadyCount || readyCount <= 0 {
		return false
	}

	return true
}

func (c *ClientV2) SetReadyCount(newCount int) {
	count := int64(newCount)
	readyCount := atomic.LoadInt64(&c.ReadyCount)
	atomic.StoreInt64(&c.ReadyCount, count)
	atomic.StoreInt64(&c.LastReadyCount, count)
	if count != readyCount {
		select {
		case c.ReadyStateChange <- 1:
		case <-c.ExitChan:
		}
	}
}

func (c *ClientV2) FinishedMessage() {
	atomic.AddUint64(&c.FinishCount, 1)
	c.decrementInFlightCount()
}

func (c *ClientV2) decrementInFlightCount() {
	ready := atomic.LoadInt64(&c.ReadyCount)
	atomic.AddInt64(&c.InFlightCount, -1)
	if ready > 0 {
		// potentially push into the readyStateChange, as this could unblock the client
		select {
		case c.ReadyStateChange <- 1:
		case <-c.ExitChan:
		}
	}
}

func (c *ClientV2) SendingMessage() {
	atomic.AddInt64(&c.ReadyCount, -1)
	atomic.AddInt64(&c.InFlightCount, 1)
	atomic.AddUint64(&c.MessageCount, 1)
}

func (c *ClientV2) TimedOutMessage() {
	c.decrementInFlightCount()
}

func (c *ClientV2) RequeuedMessage() {
	atomic.AddUint64(&c.RequeueCount, 1)
	c.decrementInFlightCount()
}
<|endoftext|>


<commit_before>// Tideland Go REST Server Library - REST - Handlers
//
// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package rest

//--------------------
// IMPORTS
//--------------------

import (
	"fmt"
	"net/http"

	"github.com/tideland/golib/errors"
)

//--------------------
// RESOURCE HANDLER INTERFACES
//--------------------

// ResourceHandler is the base interface for all resource
// handlers understanding the REST verbs. It allows the
// initialization and returns an id that has to be unique
// for the combination of domain and resource. So it can
// later be removed again.
type ResourceHandler interface {
	// ID returns the deployment ID of the handler.
	ID() string

	// Init initializes the resource handler after registrations.
	Init(env Environment, domain, resource string) error
}

// GetResourceHandler is the additional interface for
// handlers understanding the verb GET.
type GetResourceHandler interface {
	Get(job Job) (bool, error)
}

// HeadResourceHandler is the additional interface for
// handlers understanding the verb HEAD.
type HeadResourceHandler interface {
	Head(job Job) (bool, error)
}

// PutResourceHandler is the additional interface for
// handlers understanding the verb PUT.
type PutResourceHandler interface {
	Put(job Job) (bool, error)
}

// PostResourceHandler is the additional interface for
// handlers understanding the verb POST.
type PostResourceHandler interface {
	Post(job Job) (bool, error)
}

// PatchResourceHandler is the additional interface for
// handlers understanding the verb PATCH.
type PatchResourceHandler interface {
	Patch(job Job) (bool, error)
}

// DeleteResourceHandler is the additional interface for
// handlers understanding the verb DELETE.
type DeleteResourceHandler interface {
	Delete(job Job) (bool, error)
}

// OptionsResourceHandler is the additional interface for
// handlers understanding the verb OPTION.
type OptionsResourceHandler interface {
	Options(job Job) (bool, error)
}

// handleJob dispatches the passed job to the right method of the
// passed handler.
func handleJob(handler ResourceHandler, job Job) (bool, error) {
	id := func() string {
		return fmt.Sprintf("%s@%s/%s", handler.ID(), job.Domain(), job.Resource())
	}
	switch job.Request().Method {
	case http.MethodGet:
		grh, ok := handler.(GetResourceHandler)
		if !ok {
			return false, errors.New(ErrNoGetHandler, errorMessages, id())
		}
		return grh.Get(job)
	case http.MethodHead:
		hrh, ok := handler.(HeadResourceHandler)
		if !ok {
			return false, errors.New(ErrNoHeadHandler, errorMessages, id())
		}
		return hrh.Head(job)
	case http.MethodPut:
		prh, ok := handler.(PutResourceHandler)
		if !ok {
			return false, errors.New(ErrNoPutHandler, errorMessages, id())
		}
		return prh.Put(job)
	case http.MethodPost:
		prh, ok := handler.(PostResourceHandler)
		if !ok {
			return false, errors.New(ErrNoPostHandler, errorMessages, id())
		}
		return prh.Post(job)
	case http.MethodPatch:
		prh, ok := handler.(PatchResourceHandler)
		if !ok {
			return false, errors.New(ErrNoPatchHandler, errorMessages, id())
		}
		return prh.Patch(job)
	case http.MethodDelete:
		drh, ok := handler.(DeleteResourceHandler)
		if !ok {
			return false, errors.New(ErrNoDeleteHandler, errorMessages, id())
		}
		return drh.Delete(job)
	case http.MethodOptions:
		orh, ok := handler.(OptionsResourceHandler)
		if !ok {
			return false, errors.New(ErrNoOptionsHandler, errorMessages, id())
		}
		return orh.Options(job)
	}
	return false, errors.New(ErrMethodNotSupported, errorMessages, job.Request().Method)
}

// EOF
<commit_msg>Started adding REST method name dispatching<commit_after>// Tideland Go REST Server Library - REST - Handlers
//
// Copyright (C) 2009-2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package rest

//--------------------
// IMPORTS
//--------------------

import (
	"fmt"
	"net/http"

	"github.com/tideland/golib/errors"
)

//--------------------
// RESOURCE HANDLER INTERFACES
//--------------------

// ResourceHandler is the base interface for all resource
// handlers understanding the REST verbs. It allows the
// initialization and returns an id that has to be unique
// for the combination of domain and resource. So it can
// later be removed again.
type ResourceHandler interface {
	// ID returns the deployment ID of the handler.
	ID() string

	// Init initializes the resource handler after registrations.
	Init(env Environment, domain, resource string) error
}

// GetResourceHandler is the additional interface for
// handlers understanding the verb GET.
type GetResourceHandler interface {
	Get(job Job) (bool, error)
}

// ReadResourceHandler is the additional interface for
// handlers understanding the verb GET but mapping it
// to method Read() according to the REST conventions.
type ReadResourceHandler interface {
	Read(job Job) (bool, error)
}

// HeadResourceHandler is the additional interface for
// handlers understanding the verb HEAD.
type HeadResourceHandler interface {
	Head(job Job) (bool, error)
}

// PutResourceHandler is the additional interface for
// handlers understanding the verb PUT.
type PutResourceHandler interface {
	Put(job Job) (bool, error)
}

// UpdateResourceHandler is the additional interface for
// handlers understanding the verb PUT but mapping it
// to method Update() according to the REST conventions.
type UpdateResourceHandler interface {
	Update(job Job) (bool, error)
}

// PostResourceHandler is the additional interface for
// handlers understanding the verb POST.
type PostResourceHandler interface {
	Post(job Job) (bool, error)
}

// CreateResourceHandler is the additional interface for
// handlers understanding the verb POST but mapping it
// to method Create() according to the REST conventions.
type CreateResourceHandler interface {
	Create(job Job) (bool, error)
}

// PatchResourceHandler is the additional interface for
// handlers understanding the verb PATCH.
type PatchResourceHandler interface {
	Patch(job Job) (bool, error)
}

// ModifyResourceHandler is the additional interface for
// handlers understanding the verb PATCH but mapping it
// to method Modify() according to the REST conventions.
type ModifyResourceHandler interface {
	Modify(job Job) (bool, error)
}

// DeleteResourceHandler is the additional interface for
// handlers understanding the verb DELETE.
type DeleteResourceHandler interface {
	Delete(job Job) (bool, error)
}

// OptionsResourceHandler is the additional interface for
// handlers understanding the verb OPTION.
type OptionsResourceHandler interface {
	Options(job Job) (bool, error)
}

// InfoResourceHandler is the additional interface for
// handlers understanding the verb OPTION but mapping it
// to method Info() according to the REST conventions.
type InfoResourceHandler interface {
	Info(job Job) (bool, error)
}

// handleJob dispatches the passed job to the right method of the
// passed handler. It always tries the nativ method first, then
// the alias method according to the REST conventions.
func handleJob(handler ResourceHandler, job Job) (bool, error) {
	id := func() string {
		return fmt.Sprintf("%s@%s/%s", handler.ID(), job.Domain(), job.Resource())
	}
	switch job.Request().Method {
	case http.MethodGet:
		grh, ok := handler.(GetResourceHandler)
		if !ok {
			grh, ok = handler.(ReadResourceHandler)
			if !ok {
				return false, errors.New(ErrNoGetHandler, errorMessages, id())
			}
		}
		return grh.Get(job)
	case http.MethodHead:
		hrh, ok := handler.(HeadResourceHandler)
		if !ok {
			return false, errors.New(ErrNoHeadHandler, errorMessages, id())
		}
		return hrh.Head(job)
	case http.MethodPut:
		prh, ok := handler.(PutResourceHandler)
		if !ok {
			prh, ok = handler.(UpdateResourceHandler)
			if !ok {
				return false, errors.New(ErrNoPutHandler, errorMessages, id())
			}
		}
		return prh.Put(job)
	case http.MethodPost:
		prh, ok := handler.(PostResourceHandler)
		if !ok {
			prh, ok = handler.(CreateResourceHandler)
			if !ok {
				return false, errors.New(ErrNoPostHandler, errorMessages, id())
			}
		}
		return prh.Post(job)
	case http.MethodPatch:
		prh, ok := handler.(PatchResourceHandler)
		if !ok {
			prh, ok = handler.(ModifyResourceHandler)
			if !ok {
				return false, errors.New(ErrNoPatchHandler, errorMessages, id())
			}
		}
		return prh.Patch(job)
	case http.MethodDelete:
		drh, ok := handler.(DeleteResourceHandler)
		if !ok {
			return false, errors.New(ErrNoDeleteHandler, errorMessages, id())
		}
		return drh.Delete(job)
	case http.MethodOptions:
		orh, ok := handler.(OptionsResourceHandler)
		if !ok {
			orh, ok = handler.(InfoResourceHandler)
			if !ok {
				return false, errors.New(ErrNoOptionsHandler, errorMessages, id())
			}
		}
		return orh.Options(job)
	}
	return false, errors.New(ErrMethodNotSupported, errorMessages, job.Request().Method)
}

// EOF
<|endoftext|>


<commit_before>package rest

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"

	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

// Options for REST call
type Options struct {
	Headers map[string]string
	Query   map[string]interface{}
}

// Client - generic REST api client
type Client struct {
	Method
	User       string
	Password   string
	Domain     string
	APIKey     string
	APIVersion int
	SSLVerify  bool
	Endpoint   string
	Option     Options
}

// NewClient - get a new network client
func (c *Client) NewClient(user, key, endpoint string) *Client {
	var options Options
	return &Client{User: user, APIKey: key, Endpoint: endpoint, Option: options}
}

// isOkStatus - check the return status of the response
func (c *Client) isOkStatus(code int) bool {
	codes := map[int]bool{
		200: true,
		201: true,
		202: true,
		204: true,
		400: false,
		404: false,
		500: false,
		409: false,
		406: false,
	}

	return codes[code]
}

// SetQueryString - set the query strings to use
func (c *Client) SetQueryString(query map[string]interface{}) {
	// TODO: uuencode the query String
	c.Option.Query = query
}

// GetQueryString - get a query string for url
func (c *Client) GetQueryString(u *url.URL) {
	if len(c.Option.Query) == 0 {
		return
	}
	parameters := url.Values{}
	for k, v := range c.Option.Query {
		var r []string
		if reflect.TypeOf(v) == reflect.TypeOf(r) {
			for _, va := range v.([]string) {
				parameters.Add(k, va)
			}
		} else {
			parameters.Add(k, v.(string))
		}
		u.RawQuery = parameters.Encode()
	}
	return
}

// SetAuthHeaderOptins - set the Headers Options
func (c *Client) SetAuthHeaderOptions(headers map[string]string) {
	c.Option.Headers = headers
}

// RestAPICall - general rest method caller
func (c *Client) RestAPICall(method Method, path string, options interface{}) ([]byte, error) {
	log.Debugf("RestAPICall %s - %s%s", method, utils.Sanatize(c.Endpoint), path)

	var (
		Url *url.URL
		err error
		req *http.Request
	)

	Url, err = url.Parse(utils.Sanatize(c.Endpoint))
	if err != nil {
		return nil, err
	}
	Url.Path += path

	// Manage the query string
	c.GetQueryString(Url)

	// TODO: this should have a real cert
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	// get a client
	client := &http.Client{Transport: tr}

	log.Debugf("*** url => %s", Url.String())
	log.Debugf("*** method => %s", method.String())

	// parse url
	reqUrl, err := url.Parse(Url.String())
	if err != nil {
		return nil, fmt.Errorf("Error with request: %v - %q", Url, err)
	}

	// handle options
	if options != nil {
		OptionsJSON, err := json.Marshal(options)
		if err != nil {
			return nil, err
		}
		log.Debugf("*** options => %+v", bytes.NewBuffer(OptionsJSON))
		req, err = http.NewRequest(method.String(), reqUrl.String(), bytes.NewBuffer(OptionsJSON))
	} else {
		req, err = http.NewRequest(method.String(), reqUrl.String(), nil)
	}

	if err != nil {
		return nil, fmt.Errorf("Error with request: %v - %q", Url, err)
	}

	// setup proxy
	proxyUrl, err := http.ProxyFromEnvironment(req)
	if err != nil {
		return nil, fmt.Errorf("Error with proxy: %v - %q", proxyUrl, err)
	}
	if proxyUrl != nil {
		tr.Proxy = http.ProxyURL(proxyUrl)
		log.Debugf("*** proxy => %+v", tr.Proxy)
	}

	// build the auth headerU
	for k, v := range c.Option.Headers {
		log.Debugf("Headers -> %s -> %+v\n", k, v)
		req.Header.Add(k, v)
	}

	// req.SetBasicAuth(c.User, c.APIKey)
	req.Method = fmt.Sprintf("%s", method.String())

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// TODO: CLeanup Later
	// DEBUGGING WHILE WE WORK
	// DEBUGGING WHILE WE WORK
	// fmt.Printf("METHOD --> %+v\n",method)
	log.Debugf("REQ    --> %+v\n", req)
	log.Debugf("RESP   --> %+v\n", resp)
	log.Debugf("ERROR  --> %+v\n", err)
	// DEBUGGING WHILE WE WORK

	data, err := ioutil.ReadAll(resp.Body)

	if !c.isOkStatus(resp.StatusCode) {
		type apiErr struct {
			Err string `json:"details"`
		}
		var outErr apiErr
		json.Unmarshal(data, &outErr)
		return nil, fmt.Errorf("Error in response: %s\n Response Status: %s", outErr.Err, resp.Status)
	}

	if err != nil {
		return nil, err
	}

	return data, nil
}
<commit_msg>Remove reflection from the package. Minor opts.<commit_after>package rest

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"

	"github.com/HewlettPackard/oneview-golang/utils"
	"github.com/docker/machine/libmachine/log"
)

var (
	codes = map[int]bool{
		http.StatusOK:                  true,
		http.StatusCreated:             true,
		http.StatusAccepted:            true,
		http.StatusNoContent:           true,
		http.StatusBadRequest:          false,
		http.StatusNotFound:            false,
		http.StatusNotAcceptable:       false,
		http.StatusConflict:            false,
		http.StatusInternalServerError: false,
	}

	// TODO: this should have a real cert
	tr = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	// get a client
	client = &http.Client{Transport: tr, Timeout: 5 * time.Minute}
)

// Options for REST call
type Options struct {
	Headers map[string]string
	Query   map[string]interface{}
}

// Client - generic REST api client
type Client struct {
	Method
	User       string
	Password   string
	Domain     string
	APIKey     string
	APIVersion int
	SSLVerify  bool
	Endpoint   string
	Option     Options
}

// NewClient - get a new network client
func (c *Client) NewClient(user, key, endpoint string) *Client {
	return &Client{User: user, APIKey: key, Endpoint: endpoint, Option: Options{}}
}

// isOkStatus - check the return status of the response
func (c *Client) isOkStatus(code int) bool {
	return codes[code]
}

// SetQueryString - set the query strings to use
func (c *Client) SetQueryString(query map[string]interface{}) {
	// TODO: uuencode the query String
	c.Option.Query = query
}

// GetQueryString - get a query string for url
func (c *Client) GetQueryString(u *url.URL) {
	if len(c.Option.Query) == 0 {
		return
	}
	parameters := url.Values{}
	for k, v := range c.Option.Query {
		if val, ok := v.([]string); ok {
			for _, va := range val {
				parameters.Add(k, va)
			}
		} else {
			parameters.Add(k, v.(string))
		}
		u.RawQuery = parameters.Encode()
	}
	return
}

// SetAuthHeaderOptins - set the Headers Options
func (c *Client) SetAuthHeaderOptions(headers map[string]string) {
	c.Option.Headers = headers
}

// RestAPICall - general rest method caller
func (c *Client) RestAPICall(method Method, path string, options interface{}) ([]byte, error) {
	log.Debugf("RestAPICall %s - %s%s", method, utils.Sanatize(c.Endpoint), path)

	var (
		Url *url.URL
		err error
		req *http.Request
	)

	Url, err = url.Parse(utils.Sanatize(c.Endpoint))
	if err != nil {
		return nil, err
	}
	Url.Path += path

	// Manage the query string
	c.GetQueryString(Url)

	log.Debugf("*** url => %s", Url.String())
	log.Debugf("*** method => %s", method.String())

	// parse url
	reqUrl, err := url.Parse(Url.String())
	if err != nil {
		return nil, fmt.Errorf("Error with request: %v - %q", Url, err)
	}

	// handle options
	if options != nil {
		OptionsJSON, err := json.Marshal(options)
		if err != nil {
			return nil, err
		}
		log.Debugf("*** options => %+v", bytes.NewBuffer(OptionsJSON))
		req, err = http.NewRequest(method.String(), reqUrl.String(), bytes.NewBuffer(OptionsJSON))
	} else {
		req, err = http.NewRequest(method.String(), reqUrl.String(), nil)
	}

	if err != nil {
		return nil, fmt.Errorf("Error with request: %v - %q", Url, err)
	}

	// setup proxy
	proxyUrl, err := http.ProxyFromEnvironment(req)
	if err != nil {
		return nil, fmt.Errorf("Error with proxy: %v - %q", proxyUrl, err)
	}
	if proxyUrl != nil {
		tr.Proxy = http.ProxyURL(proxyUrl)
		log.Debugf("*** proxy => %+v", tr.Proxy)
	}

	// build the auth headerU
	for k, v := range c.Option.Headers {
		log.Debugf("Headers -> %s -> %+v\n", k, v)
		req.Header.Add(k, v)
	}

	// req.SetBasicAuth(c.User, c.APIKey)
	req.Method = fmt.Sprintf("%s", method.String())

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// TODO: CLeanup Later
	// DEBUGGING WHILE WE WORK
	// DEBUGGING WHILE WE WORK
	// fmt.Printf("METHOD --> %+v\n",method)
	log.Debugf("REQ    --> %+v\n", req)
	log.Debugf("RESP   --> %+v\n", resp)
	log.Debugf("ERROR  --> %+v\n", err)
	// DEBUGGING WHILE WE WORK

	data, err := ioutil.ReadAll(resp.Body)

	if !c.isOkStatus(resp.StatusCode) {
		type apiErr struct {
			Err string `json:"details"`
		}
		var outErr apiErr
		json.Unmarshal(data, &outErr)
		return nil, fmt.Errorf("Error in response: %s\n Response Status: %s", outErr.Err, resp.Status)
	}

	if err != nil {
		return nil, err
	}

	return data, nil
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"reflect"
	"testing"
)

func TestNewManagerRESTRouter(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	ring, err := NewMsgRing(nil, 1)

	cfg := NewCfgMem()
	mgr := NewManager(VERSION, cfg, NewUUID(), nil, "", 1, ":1000",
		emptyDir, "some-datasource", nil)
	r, err := NewManagerRESTRouter(mgr, emptyDir, ring)
	if r == nil || err != nil {
		t.Errorf("expected no errors")
	}

	mgr = NewManager(VERSION, cfg, NewUUID(), []string{"queryer", "anotherTag"},
		"", 1, ":1000", emptyDir, "some-datasource", nil)
	r, err = NewManagerRESTRouter(mgr, emptyDir, ring)
	if r == nil || err != nil {
		t.Errorf("expected no errors")
	}
}

func TestHandlers(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	cfg := NewCfgMem()
	meh := &TestMEH{}
	mgr := NewManager(VERSION, cfg, NewUUID(),
		nil, "", 1, ":1000", emptyDir, "some-datasource", meh)
	mgr.Start("wanted")
	mgr.Kick("test-start-kick")

	mr, _ := NewMsgRing(os.Stderr, 1000)

	router, err := NewManagerRESTRouter(mgr, "static", mr)
	if err != nil || router == nil {
		t.Errorf("no mux router")
	}

	tests := []struct {
		Desc          string
		Handler       http.Handler
		Path          string
		Method        string
		Params        url.Values
		Body          []byte
		Status        int
		ResponseBody  []byte
		ResponseMatch map[string]bool
	}{
		{
			Desc:         "log",
			Handler:      NewGetLogHandler(mr),
			Path:         "/api/log",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       http.StatusOK,
			ResponseBody: []byte(`{"messages":[]}`),
		},
		{
			Desc:         "list empty indexes",
			Handler:      NewListIndexHandler(mgr),
			Path:         "/api/index",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       http.StatusOK,
			ResponseBody: []byte(`{"status":"ok","indexDefs":null}`),
		},
		{
			Desc:         "try to get a nonexistent index",
			Handler:      NewGetIndexHandler(mgr),
			Path:         "/api/index/NOT-AN-INDEX",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       400,
			ResponseBody: []byte(`not an index`),
		},
		{
			Desc:    "try to delete a nonexistent index when no indexes",
			Handler: NewDeleteIndexHandler(mgr),
			Path:    "/api/index/NOT-AN-INDEX",
			Method:  "DELETE",
			Params:  nil,
			Body:    nil,
			Status:  400,
			ResponseMatch: map[string]bool{
				`indexes do not exist`: true,
			},
		},
	}

	for _, test := range tests {
		record := httptest.NewRecorder()
		req := &http.Request{
			Method: test.Method,
			URL:    &url.URL{Path: test.Path},
			Form:   test.Params,
			Body:   ioutil.NopCloser(bytes.NewBuffer(test.Body)),
		}
		router.ServeHTTP(record, req)
		if got, want := record.Code, test.Status; got != want {
			t.Errorf("%s: response code = %d, want %d", test.Desc, got, want)
			t.Errorf("%s: response body = %s", test.Desc, record.Body)
		}

		got := bytes.TrimRight(record.Body.Bytes(), "\n")
		if test.ResponseBody != nil {
			if !reflect.DeepEqual(got, test.ResponseBody) {
				t.Errorf("%s: expected: '%s', got: '%s'",
					test.Desc, test.ResponseBody, got)
			}
		}
		for pattern, shouldMatch := range test.ResponseMatch {
			didMatch := bytes.Contains(got, []byte(pattern))
			if didMatch != shouldMatch {
				t.Errorf("%s: expected match %t for pattern %s, got %t",
					test.Desc, shouldMatch, pattern, didMatch)
				t.Errorf("%s: response body was: %s", test.Desc, got)
			}
		}
	}
}
<commit_msg>test create-index when server is bad<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"reflect"
	"testing"
)

func TestNewManagerRESTRouter(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	ring, err := NewMsgRing(nil, 1)

	cfg := NewCfgMem()
	mgr := NewManager(VERSION, cfg, NewUUID(), nil, "", 1, ":1000",
		emptyDir, "some-datasource", nil)
	r, err := NewManagerRESTRouter(mgr, emptyDir, ring)
	if r == nil || err != nil {
		t.Errorf("expected no errors")
	}

	mgr = NewManager(VERSION, cfg, NewUUID(), []string{"queryer", "anotherTag"},
		"", 1, ":1000", emptyDir, "some-datasource", nil)
	r, err = NewManagerRESTRouter(mgr, emptyDir, ring)
	if r == nil || err != nil {
		t.Errorf("expected no errors")
	}
}

func TestHandlers(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	cfg := NewCfgMem()
	meh := &TestMEH{}
	mgr := NewManager(VERSION, cfg, NewUUID(),
		nil, "", 1, ":1000", emptyDir, "some-datasource", meh)
	mgr.Start("wanted")
	mgr.Kick("test-start-kick")

	mr, _ := NewMsgRing(os.Stderr, 1000)

	router, err := NewManagerRESTRouter(mgr, "static", mr)
	if err != nil || router == nil {
		t.Errorf("no mux router")
	}

	tests := []struct {
		Desc          string
		Handler       http.Handler
		Path          string
		Method        string
		Params        url.Values
		Body          []byte
		Status        int
		ResponseBody  []byte
		ResponseMatch map[string]bool
	}{
		{
			Desc:         "log",
			Handler:      NewGetLogHandler(mr),
			Path:         "/api/log",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       http.StatusOK,
			ResponseBody: []byte(`{"messages":[]}`),
		},
		{
			Desc:         "list empty indexes",
			Handler:      NewListIndexHandler(mgr),
			Path:         "/api/index",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       http.StatusOK,
			ResponseBody: []byte(`{"status":"ok","indexDefs":null}`),
		},
		{
			Desc:         "try to get a nonexistent index",
			Handler:      NewGetIndexHandler(mgr),
			Path:         "/api/index/NOT-AN-INDEX",
			Method:       "GET",
			Params:       nil,
			Body:         nil,
			Status:       400,
			ResponseBody: []byte(`not an index`),
		},
		{
			Desc:    "try to create a default index with bad server",
			Handler: NewCreateIndexHandler(mgr),
			Path:    "/api/index/default-idx-to-bad-server",
			Method:  "PUT",
			Params:  nil,
			Body:    nil,
			Status:  500,
			ResponseMatch: map[string]bool{
				`failed to connect`: true,
			},
		},
		{
			Desc:    "try to delete a nonexistent index when no indexes",
			Handler: NewDeleteIndexHandler(mgr),
			Path:    "/api/index/NOT-AN-INDEX",
			Method:  "DELETE",
			Params:  nil,
			Body:    nil,
			Status:  400,
			ResponseMatch: map[string]bool{
				`indexes do not exist`: true,
			},
		},
	}

	for _, test := range tests {
		record := httptest.NewRecorder()
		req := &http.Request{
			Method: test.Method,
			URL:    &url.URL{Path: test.Path},
			Form:   test.Params,
			Body:   ioutil.NopCloser(bytes.NewBuffer(test.Body)),
		}
		router.ServeHTTP(record, req)
		if got, want := record.Code, test.Status; got != want {
			t.Errorf("%s: response code = %d, want %d", test.Desc, got, want)
			t.Errorf("%s: response body = %s", test.Desc, record.Body)
		}

		got := bytes.TrimRight(record.Body.Bytes(), "\n")
		if test.ResponseBody != nil {
			if !reflect.DeepEqual(got, test.ResponseBody) {
				t.Errorf("%s: expected: '%s', got: '%s'",
					test.Desc, test.ResponseBody, got)
			}
		}
		for pattern, shouldMatch := range test.ResponseMatch {
			didMatch := bytes.Contains(got, []byte(pattern))
			if didMatch != shouldMatch {
				t.Errorf("%s: expected match %t for pattern %s, got %t",
					test.Desc, shouldMatch, pattern, didMatch)
				t.Errorf("%s: response body was: %s", test.Desc, got)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

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

var (
	flagUserName, flagChannel, flagIconURL string
	flagPlainText, flagNoBuffer            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.BoolVar(&flagPlainText, "p", false, "Don't surround the post with triple backticks.")
	flag.BoolVar(&flagNoBuffer, "n", false, "Post input values without buffering.")
	flag.Parse()
}

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

func main() {
	url := os.Getenv("MM_HOOK")
	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)
		}
	} else {
		m.Send(msg)
	}
}
<commit_msg>Add extra info and matterurl parameter<commit_after>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)
	}
}
<|endoftext|>


<commit_before>// +build darwin

package mem

import (
	"os/exec"
	"strconv"
	"strings"

	common "github.com/shirou/gopsutil/common"
)

func getPageSize() (uint64, error) {
	out, err := exec.Command("pagesize").Output()
	if err != nil {
		return 0, err
	}
	o := strings.TrimSpace(string(out))
	p, err := strconv.ParseUint(o, 10, 64)
	if err != nil {
		return 0, err
	}

	return p, nil
}

// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
	p, err := getPageSize()
	if err != nil {
		return nil, err
	}

	total, err := common.DoSysctrl("hw.memsize")
	if err != nil {
		return nil, err
	}
	free, err := common.DoSysctrl("vm.page_free_count")
	if err != nil {
		return nil, err
	}
	parsed := make([]uint64, 0, 7)
	vv := []string{
		total[0],
		free[0],
	}
	for _, target := range vv {
		t, err := strconv.ParseUint(target, 10, 64)
		if err != nil {
			return nil, err
		}
		parsed = append(parsed, t)
	}

	ret := &VirtualMemoryStat{
		Total: parsed[0] * p,
		Free:  parsed[1] * p,
	}

	// TODO: platform independent (worked freebsd?)
	ret.Available = ret.Free + ret.Buffers + ret.Cached

	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0

	return ret, nil
}

// SwapMemory returns swapinfo.
func SwapMemory() (*SwapMemoryStat, error) {
	var ret *SwapMemoryStat

	swapUsage, err := common.DoSysctrl("vm.swapusage")
	if err != nil {
		return ret, err
	}

	total := strings.Replace(swapUsage[2], "M", "", 1)
	used := strings.Replace(swapUsage[5], "M", "", 1)
	free := strings.Replace(swapUsage[8], "M", "", 1)

	total_v, err := strconv.ParseFloat(total, 64)
	if err != nil {
		return nil, err
	}
	used_v, err := strconv.ParseFloat(used, 64)
	if err != nil {
		return nil, err
	}
	free_v, err := strconv.ParseFloat(free, 64)
	if err != nil {
		return nil, err
	}

	u := float64(0)
	if total_v != 0 {
		u = ((total_v - free_v) / total_v) * 100.0
	}

	// vm.swapusage shows "M", multiply 1000
	ret = &SwapMemoryStat{
		Total:       uint64(total_v * 1000),
		Used:        uint64(used_v * 1000),
		Free:        uint64(free_v * 1000),
		UsedPercent: u,
	}

	return ret, nil
}
<commit_msg>memory[darwin]: return value of "sysctl hw.memsize" is memory size in bytes.<commit_after>// +build darwin

package mem

import (
	"os/exec"
	"strconv"
	"strings"

	common "github.com/shirou/gopsutil/common"
)

func getPageSize() (uint64, error) {
	out, err := exec.Command("pagesize").Output()
	if err != nil {
		return 0, err
	}
	o := strings.TrimSpace(string(out))
	p, err := strconv.ParseUint(o, 10, 64)
	if err != nil {
		return 0, err
	}

	return p, nil
}

// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
	p, err := getPageSize()
	if err != nil {
		return nil, err
	}

	total, err := common.DoSysctrl("hw.memsize")
	if err != nil {
		return nil, err
	}
	free, err := common.DoSysctrl("vm.page_free_count")
	if err != nil {
		return nil, err
	}
	parsed := make([]uint64, 0, 7)
	vv := []string{
		total[0],
		free[0],
	}
	for _, target := range vv {
		t, err := strconv.ParseUint(target, 10, 64)
		if err != nil {
			return nil, err
		}
		parsed = append(parsed, t)
	}

	ret := &VirtualMemoryStat{
		Total: parsed[0],
		Free:  parsed[1] * p,
	}

	// TODO: platform independent (worked freebsd?)
	ret.Available = ret.Free + ret.Buffers + ret.Cached

	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0

	return ret, nil
}

// SwapMemory returns swapinfo.
func SwapMemory() (*SwapMemoryStat, error) {
	var ret *SwapMemoryStat

	swapUsage, err := common.DoSysctrl("vm.swapusage")
	if err != nil {
		return ret, err
	}

	total := strings.Replace(swapUsage[2], "M", "", 1)
	used := strings.Replace(swapUsage[5], "M", "", 1)
	free := strings.Replace(swapUsage[8], "M", "", 1)

	total_v, err := strconv.ParseFloat(total, 64)
	if err != nil {
		return nil, err
	}
	used_v, err := strconv.ParseFloat(used, 64)
	if err != nil {
		return nil, err
	}
	free_v, err := strconv.ParseFloat(free, 64)
	if err != nil {
		return nil, err
	}

	u := float64(0)
	if total_v != 0 {
		u = ((total_v - free_v) / total_v) * 100.0
	}

	// vm.swapusage shows "M", multiply 1000
	ret = &SwapMemoryStat{
		Total:       uint64(total_v * 1000),
		Used:        uint64(used_v * 1000),
		Free:        uint64(free_v * 1000),
		UsedPercent: u,
	}

	return ret, nil
}
<|endoftext|>


<commit_before>package gogitlab

import (
	"encoding/json"
	"time"
)

const (
	project_url_merge_requests             = "/projects/:id/merge_requests"                                                    // Get project merge requests
	project_url_merge_request              = "/projects/:id/merge_requests/:merge_request_id"                                  // Get information about a single merge request
	project_url_merge_request_commits      = "/projects/:id/merge_requests/:merge_request_id/commits"                          // Get a list of merge request commits
	project_url_merge_request_changes      = "/projects/:id/merge_requests/:merge_request_id/changes"                          // Shows information about the merge request including its files and changes
	project_url_merge_request_merge        = "/projects/:id/merge_requests/:merge_request_id/merge"                            // Merge changes submitted with MR
	project_url_merge_request_cancel_merge = "/projects/:id/merge_requests/:merge_request_id/cancel_merge_when_build_succeeds" // Cancel Merge When Build Succeeds
	project_url_merge_request_comments     = "/projects/:id/merge_requests/:merge_request_id/comments"                         // Lists all comments associated with a merge request
)

type MergeRequest struct {
	Id             int    `json:"id,omitempty"`
	Iid            int    `json:"iid,omitempty"`
	TargetBranch   string `json:"target_branch,omitempty"`
	SourceBranch   string `json:"source_branch,omitempty"`
	ProjectId      int    `json:"project_id,omitempty"`
	Title          string `json:"title,omitempty"`
	State          string `json:"state,omitempty"`
	CreatedAt      string `json:"created_at,omitempty"`
	UpdatedAt      string `json:"updated_at,omitempty"`
	Upvotes        int    `json:"upvotes,omitempty"`
	Downvotes      int    `json:"downvotes,omitempty"`
	Author         *User  `json:"author,omitempty"`
	Assignee       *User  `json:"assignee,omitempty"`
	Description    string `json:"description,omitempty"`
	WorkInProgress bool   `json:"work_in_progress,omitempty"`
}

type ChangeItem struct {
	OldPath     string `json:"old_path,omitempty"`
	NewPath     string `json:"new_path,omitempty"`
	AMode       string `json:"a_mode,omitempty"`
	BMode       string `json:"b_mode,omitempty"`
	Diff        string `json:"diff,omitempty"`
	NewFile     bool   `json:"new_file,omitempty"`
	RenamedFile bool   `json:"renamed_file,omitempty"`
	DeletedFile bool   `json:"deleted_file,omitempty"`
}

type MergeRequestChanges struct {
	*MergeRequest
	CreatedAt       string       `json:"created_at,omitempty"`
	UpdatedAt       string       `json:"updated_at,omitempty"`
	SourceProjectId int          `json:"source_project_id,omitempty"`
	TargetProjectId int          `json:"target_project_id,omitempty"`
	Labels          []string     `json:"labels,omitempty"`
	Milestone       Milestone    `json:"milestone,omitempty"`
	Changes         []ChangeItem `json:"changes,omitempty"`
}

type AddMergeRequestRequest struct {
	SourceBranch    string   `json:"source_branch"`
	TargetBranch    string   `json:"target_branch"`
	AssigneeId      int      `json:"assignee_id,omitempty"`
	Title           string   `json:"title"`
	Description     string   `json:"description,omitempty"`
	TargetProjectId int      `json:"target_project_id,omitempty"`
	Lables          []string `json:"lables,omitempty"`
}

type AcceptMergeRequestRequest struct {
	MergeCommitMessage       string `json:"merge_commit_message,omitempty"`
	ShouldRemoveSourceBranch bool   `json:"should_remove_source_branch,omitempty"`
	MergedWhenBuildSucceeds  bool   `json:"merged_when_build_succeeds,omitempty"`
}

/*
Get list of project merge requests.

    GET /projects/:id/merge_requests

Parameters:

    id The ID of a project

Params:
	iid (optional) - Return the request having the given iid
	state (optional) - Return all requests or just those that are merged, opened or closed
	order_by (optional) - Return requests ordered by created_at or updated_at fields. Default is created_at
	sort (optional) - Return requests sorted in asc or desc order. Default is desc

*/
func (g *Gitlab) ProjectMergeRequests(id string, params map[string]string) ([]*MergeRequest, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_requests, map[string]string{":id": id})

	for name, value := range params {
		url = url + "&" + name + "=" + value
	}

	var err error
	var mergeRequests []*MergeRequest

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return mergeRequests, err
	}

	err = json.Unmarshal(contents, &mergeRequests)

	return mergeRequests, err
}

/*
Get single project merge request.

    GET /projects/:id/merge_requests/:merge_request_id

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequest(id, merge_request_id string) (*MergeRequest, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	mr := new(MergeRequest)

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return mr, err
	}

	err = json.Unmarshal(contents, &mr)

	return mr, err
}

/*
Get a list of merge request commits.

    GET /projects/:id/merge_request/:merge_request_id/commits

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestCommits(id, merge_request_id string) ([]*Commit, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request_commits, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	var commits []*Commit

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err == nil {
		err = json.Unmarshal(contents, &commits)
		if err == nil {
			for _, commit := range commits {
				t, _ := time.Parse(dateLayout, commit.Created_At)
				commit.CreatedAt = t
			}
		}
	}

	return commits, err
}

/*
Get information about the merge request including its files and changes.

    GET /projects/:id/merge_request/:merge_request_id/changes

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestChanges(id, merge_request_id string) (*MergeRequestChanges, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request_changes, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	changes := new(MergeRequestChanges)

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return changes, err
	}

	err = json.Unmarshal(contents, &changes)

	return changes, err
}

/*
Creates a new merge request.

    POST /projects/:id/merge_requests

Parameters:

    id               The ID of a project

*/
func (g *Gitlab) AddMergeRequest(req *AddMergeRequestRequest) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_requests, map[string]string{
		":id": string(req.TargetProjectId),
	})

	encodedRequest, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	data, err := g.buildAndExecRequest("POST", url, encodedRequest)
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}

/*
Updates an existing merge request.

    PUT /projects/:id/merge_request/:merge_request_id

Parameters:

    id               The ID of a project

*/
func (g *Gitlab) EditMergeRequest(mr *MergeRequest) error {
	url, _ := g.ResourceUrlRaw(project_url_merge_request, map[string]string{
		":id":               string(mr.ProjectId),
		":merge_request_id": string(mr.Id),
	})

	encodedRequest, err := json.Marshal(mr)
	if err != nil {
		return err
	}

	data, err := g.buildAndExecRequest("PUT", url, encodedRequest)
	if err != nil {
		return err
	}

	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return nil
}

/*
Merge changes submitted with MR.

    PUT /projects/:id/merge_request/:merge_request_id/merge

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestAccept(id, merge_request_id string, req *AcceptMergeRequestRequest) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_request_merge, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	encodedRequest, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	data, err := g.buildAndExecRequest("PUT", url, encodedRequest)
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}

/*
Cancel Merge When Build Succeeds.

    PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestCancelMerge(id, merge_request_id string) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_request_cancel_merge, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	data, err := g.buildAndExecRequest("PUT", url, []byte{})
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}
<commit_msg>add merge_status to struct<commit_after>package gogitlab

import (
	"encoding/json"
	"time"
)

const (
	project_url_merge_requests             = "/projects/:id/merge_requests"                                                    // Get project merge requests
	project_url_merge_request              = "/projects/:id/merge_requests/:merge_request_id"                                  // Get information about a single merge request
	project_url_merge_request_commits      = "/projects/:id/merge_requests/:merge_request_id/commits"                          // Get a list of merge request commits
	project_url_merge_request_changes      = "/projects/:id/merge_requests/:merge_request_id/changes"                          // Shows information about the merge request including its files and changes
	project_url_merge_request_merge        = "/projects/:id/merge_requests/:merge_request_id/merge"                            // Merge changes submitted with MR
	project_url_merge_request_cancel_merge = "/projects/:id/merge_requests/:merge_request_id/cancel_merge_when_build_succeeds" // Cancel Merge When Build Succeeds
	project_url_merge_request_comments     = "/projects/:id/merge_requests/:merge_request_id/comments"                         // Lists all comments associated with a merge request
)

type MergeRequest struct {
	Id             int    `json:"id,omitempty"`
	Iid            int    `json:"iid,omitempty"`
	TargetBranch   string `json:"target_branch,omitempty"`
	SourceBranch   string `json:"source_branch,omitempty"`
	ProjectId      int    `json:"project_id,omitempty"`
	Title          string `json:"title,omitempty"`
	State          string `json:"state,omitempty"`
	CreatedAt      string `json:"created_at,omitempty"`
	UpdatedAt      string `json:"updated_at,omitempty"`
	Upvotes        int    `json:"upvotes,omitempty"`
	Downvotes      int    `json:"downvotes,omitempty"`
	Author         *User  `json:"author,omitempty"`
	Assignee       *User  `json:"assignee,omitempty"`
	Description    string `json:"description,omitempty"`
	WorkInProgress bool   `json:"work_in_progress,omitempty"`
	MergeStatus    string `json:"merge_status,omitempty"`
}

type ChangeItem struct {
	OldPath     string `json:"old_path,omitempty"`
	NewPath     string `json:"new_path,omitempty"`
	AMode       string `json:"a_mode,omitempty"`
	BMode       string `json:"b_mode,omitempty"`
	Diff        string `json:"diff,omitempty"`
	NewFile     bool   `json:"new_file,omitempty"`
	RenamedFile bool   `json:"renamed_file,omitempty"`
	DeletedFile bool   `json:"deleted_file,omitempty"`
}

type MergeRequestChanges struct {
	*MergeRequest
	CreatedAt       string       `json:"created_at,omitempty"`
	UpdatedAt       string       `json:"updated_at,omitempty"`
	SourceProjectId int          `json:"source_project_id,omitempty"`
	TargetProjectId int          `json:"target_project_id,omitempty"`
	Labels          []string     `json:"labels,omitempty"`
	Milestone       Milestone    `json:"milestone,omitempty"`
	Changes         []ChangeItem `json:"changes,omitempty"`
}

type AddMergeRequestRequest struct {
	SourceBranch    string   `json:"source_branch"`
	TargetBranch    string   `json:"target_branch"`
	AssigneeId      int      `json:"assignee_id,omitempty"`
	Title           string   `json:"title"`
	Description     string   `json:"description,omitempty"`
	TargetProjectId int      `json:"target_project_id,omitempty"`
	Lables          []string `json:"lables,omitempty"`
}

type AcceptMergeRequestRequest struct {
	MergeCommitMessage       string `json:"merge_commit_message,omitempty"`
	ShouldRemoveSourceBranch bool   `json:"should_remove_source_branch,omitempty"`
	MergedWhenBuildSucceeds  bool   `json:"merged_when_build_succeeds,omitempty"`
}

/*
Get list of project merge requests.

    GET /projects/:id/merge_requests

Parameters:

    id The ID of a project

Params:
	iid (optional) - Return the request having the given iid
	state (optional) - Return all requests or just those that are merged, opened or closed
	order_by (optional) - Return requests ordered by created_at or updated_at fields. Default is created_at
	sort (optional) - Return requests sorted in asc or desc order. Default is desc

*/
func (g *Gitlab) ProjectMergeRequests(id string, params map[string]string) ([]*MergeRequest, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_requests, map[string]string{":id": id})

	for name, value := range params {
		url = url + "&" + name + "=" + value
	}

	var err error
	var mergeRequests []*MergeRequest

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return mergeRequests, err
	}

	err = json.Unmarshal(contents, &mergeRequests)

	return mergeRequests, err
}

/*
Get single project merge request.

    GET /projects/:id/merge_requests/:merge_request_id

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequest(id, merge_request_id string) (*MergeRequest, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	mr := new(MergeRequest)

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return mr, err
	}

	err = json.Unmarshal(contents, &mr)

	return mr, err
}

/*
Get a list of merge request commits.

    GET /projects/:id/merge_request/:merge_request_id/commits

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestCommits(id, merge_request_id string) ([]*Commit, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request_commits, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	var commits []*Commit

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err == nil {
		err = json.Unmarshal(contents, &commits)
		if err == nil {
			for _, commit := range commits {
				t, _ := time.Parse(dateLayout, commit.Created_At)
				commit.CreatedAt = t
			}
		}
	}

	return commits, err
}

/*
Get information about the merge request including its files and changes.

    GET /projects/:id/merge_request/:merge_request_id/changes

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestChanges(id, merge_request_id string) (*MergeRequestChanges, error) {
	url, opaque := g.ResourceUrlRaw(project_url_merge_request_changes, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	var err error
	changes := new(MergeRequestChanges)

	contents, err := g.buildAndExecRequestRaw("GET", url, opaque, nil)
	if err != nil {
		return changes, err
	}

	err = json.Unmarshal(contents, &changes)

	return changes, err
}

/*
Creates a new merge request.

    POST /projects/:id/merge_requests

Parameters:

    id               The ID of a project

*/
func (g *Gitlab) AddMergeRequest(req *AddMergeRequestRequest) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_requests, map[string]string{
		":id": string(req.TargetProjectId),
	})

	encodedRequest, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	data, err := g.buildAndExecRequest("POST", url, encodedRequest)
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}

/*
Updates an existing merge request.

    PUT /projects/:id/merge_request/:merge_request_id

Parameters:

    id               The ID of a project

*/
func (g *Gitlab) EditMergeRequest(mr *MergeRequest) error {
	url, _ := g.ResourceUrlRaw(project_url_merge_request, map[string]string{
		":id":               string(mr.ProjectId),
		":merge_request_id": string(mr.Id),
	})

	encodedRequest, err := json.Marshal(mr)
	if err != nil {
		return err
	}

	data, err := g.buildAndExecRequest("PUT", url, encodedRequest)
	if err != nil {
		return err
	}

	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return nil
}

/*
Merge changes submitted with MR.

    PUT /projects/:id/merge_request/:merge_request_id/merge

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestAccept(id, merge_request_id string, req *AcceptMergeRequestRequest) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_request_merge, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	encodedRequest, err := json.Marshal(req)
	if err != nil {
		return nil, err
	}

	data, err := g.buildAndExecRequest("PUT", url, encodedRequest)
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}

/*
Cancel Merge When Build Succeeds.

    PUT /projects/:id/merge_request/:merge_request_id/cancel_merge_when_build_succeeds

Parameters:

    id               The ID of a project
    merge_request_id The ID of a merge request

*/
func (g *Gitlab) ProjectMergeRequestCancelMerge(id, merge_request_id string) (*MergeRequest, error) {
	url, _ := g.ResourceUrlRaw(project_url_merge_request_cancel_merge, map[string]string{
		":id":               id,
		":merge_request_id": merge_request_id,
	})

	data, err := g.buildAndExecRequest("PUT", url, []byte{})
	if err != nil {
		return nil, err
	}

	mr := new(MergeRequest)
	err = json.Unmarshal(data, mr)
	if err != nil {
		panic(err)
	}
	return mr, nil
}
<|endoftext|>


<commit_before>package messaging

import (
	"fmt"
	mq "github.com/eclipse/paho.mqtt.golang"
	"log"
	"time"
)

type mqttMessenger struct {
	client mq.Client
}

type Handler struct {
	Ann           chan Message
	Leave         chan Message
	AnnounceTopic string
	LeaveTopic    string
	DiscoverTopic string
	DiscoverDelay time.Duration
	DiscoverStart chan bool
}

// RetryWithBackoff will retry the operation for the amount of attempts. The
// backoff time gets multiplied by the attempt to create an exponential backoff.
//
// Returns an error if the operation still failed after the specified amount of
// attempts have been executed.
func RetryWithBackoff(attempts int, backoff time.Duration, callback func() error) (err error) {
	for i := 1; ; i++ {
		err = callback()
		if err == nil {
			log.Print("Operation succeed at attempt: ", i)
			return
		}

		if i >= attempts {
			break
		}
		backoff = time.Duration(i) * backoff
		log.Printf("Operation failed with error: %s. Going to reattempt in %d seconds", err, backoff/time.Second)
		time.Sleep(backoff)
	}
	return fmt.Errorf("Operation failed after %d attempts, last error: %s", attempts, err)
}

// onConnect gets executed when we've established a connection with the MQTT
// broker, regardless of if this was our first attempt or after a reconnect.
func (h *Handler) OnConnect(c mq.Client) {
	log.Print("Connected to MQTT broker")

	if h.Ann != nil && h.AnnounceTopic != "" {
		log.Print("Attempting to subscribe to announce topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Subscribe(h.AnnounceTopic, 1, func(client mq.Client, msg mq.Message) {
				h.Ann <- msg
			})
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not subscribe to announce topic")
		}
		log.Print("Subscribed to announce topic")
	}

	if h.Leave != nil && h.LeaveTopic != "" {
		log.Print("Attempting to subscribe to leave topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Subscribe(h.LeaveTopic, 1, func(client mq.Client, msg mq.Message) {
				h.Leave <- msg
			})
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not subscribe to leave topic")
		}
		log.Print("Subscribed to leave topic")
	}

	if h.DiscoverDelay > 0 {
		<-time.After(h.DiscoverDelay)
	}
	if h.DiscoverStart != nil {
		h.DiscoverStart <- true
	}

	if h.DiscoverTopic != "" {
		log.Print("Attempting to publish to discover topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Publish(h.DiscoverTopic, 1, true, "1")
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not publish to discover topic")
		}
		log.Print("Initiated discovery")
	}
}

// onConnectionLost gets triggered whenver we unexpectedly lose connection with
// the MQTT broker.
func (h *Handler) OnConnectionLost(c mq.Client, e error) {
	log.Print("Unexpectedly lost connection to MQTT broker, attempting to reconnect")
}

// NewMQTTMessenger returns a PublishSubscriber.
//
// It expects to be given something that looks like an MQTT Client and
// a channel on which it will publish any messages from topics to which
// we have subscribed.
//
// It allows for publishing messages to a topic on an MQTT broker, to
// subscribe to messages published to topics and to unsubscribe from topic.
func NewMQTTMessenger(client mq.Client) PublishSubscriber {
	return &mqttMessenger{
		client: client,
	}
}

// Publish publishes a msg on the specified topic. qos represents the MQTT QoS
// level and retain informs the broker that it needs to persist this message so
// that when a new client subscribes to the topic we published on they will
// automatically get that message.
func (m *mqttMessenger) Publish(topic string, msg []byte, qos int, retain bool) {
	m.client.Publish(topic, byte(qos), retain, msg)
}

// Subscribe subscribes to the specified topic with a certain qos. The topic
// and message are then passed into this messenger's recv channel and can be
// read from by any interested consumer.
func (m *mqttMessenger) Subscribe(topic string, qos int, callback func(Message)) {
	m.client.Subscribe(topic, byte(qos), func(c mq.Client, msg mq.Message) {
		callback(msg)
	})
}

// Unsubscribe unsubscribes from one or multiple topics.
func (m *mqttMessenger) Unsubscribe(topics ...string) {
	m.client.Unsubscribe(topics...)
}
<commit_msg>:ambulance: Reset DiscoverStart and DiscoverDelay<commit_after>package messaging

import (
	"fmt"
	mq "github.com/eclipse/paho.mqtt.golang"
	"log"
	"time"
)

type mqttMessenger struct {
	client mq.Client
}

type Handler struct {
	Ann           chan Message
	Leave         chan Message
	AnnounceTopic string
	LeaveTopic    string
	DiscoverTopic string
	DiscoverDelay time.Duration
	DiscoverStart chan bool
}

// RetryWithBackoff will retry the operation for the amount of attempts. The
// backoff time gets multiplied by the attempt to create an exponential backoff.
//
// Returns an error if the operation still failed after the specified amount of
// attempts have been executed.
func RetryWithBackoff(attempts int, backoff time.Duration, callback func() error) (err error) {
	for i := 1; ; i++ {
		err = callback()
		if err == nil {
			log.Print("Operation succeed at attempt: ", i)
			return
		}

		if i >= attempts {
			break
		}
		backoff = time.Duration(i) * backoff
		log.Printf("Operation failed with error: %s. Going to reattempt in %d seconds", err, backoff/time.Second)
		time.Sleep(backoff)
	}
	return fmt.Errorf("Operation failed after %d attempts, last error: %s", attempts, err)
}

// onConnect gets executed when we've established a connection with the MQTT
// broker, regardless of if this was our first attempt or after a reconnect.
func (h *Handler) OnConnect(c mq.Client) {
	log.Print("Connected to MQTT broker")

	if h.Ann != nil && h.AnnounceTopic != "" {
		log.Print("Attempting to subscribe to announce topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Subscribe(h.AnnounceTopic, 1, func(client mq.Client, msg mq.Message) {
				h.Ann <- msg
			})
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not subscribe to announce topic")
		}
		log.Print("Subscribed to announce topic")
	}

	if h.Leave != nil && h.LeaveTopic != "" {
		log.Print("Attempting to subscribe to leave topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Subscribe(h.LeaveTopic, 1, func(client mq.Client, msg mq.Message) {
				h.Leave <- msg
			})
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not subscribe to leave topic")
		}
		log.Print("Subscribed to leave topic")
	}

	if h.DiscoverDelay > 0 {
		<-time.After(h.DiscoverDelay)
		h.DiscoverDelay = 0
	}
	if h.DiscoverStart != nil {
		h.DiscoverStart <- true
		h.DiscoverStart = nil
	}

	if h.DiscoverTopic != "" {
		log.Print("Attempting to publish to discover topic")
		err := RetryWithBackoff(5, 2*time.Second, func() error {
			token := c.Publish(h.DiscoverTopic, 1, true, "1")
			token.Wait()
			return token.Error()
		})
		if err != nil {
			log.Fatal("Could not publish to discover topic")
		}
		log.Print("Initiated discovery")
	}
}

// onConnectionLost gets triggered whenver we unexpectedly lose connection with
// the MQTT broker.
func (h *Handler) OnConnectionLost(c mq.Client, e error) {
	log.Print("Unexpectedly lost connection to MQTT broker, attempting to reconnect")
}

// NewMQTTMessenger returns a PublishSubscriber.
//
// It expects to be given something that looks like an MQTT Client and
// a channel on which it will publish any messages from topics to which
// we have subscribed.
//
// It allows for publishing messages to a topic on an MQTT broker, to
// subscribe to messages published to topics and to unsubscribe from topic.
func NewMQTTMessenger(client mq.Client) PublishSubscriber {
	return &mqttMessenger{
		client: client,
	}
}

// Publish publishes a msg on the specified topic. qos represents the MQTT QoS
// level and retain informs the broker that it needs to persist this message so
// that when a new client subscribes to the topic we published on they will
// automatically get that message.
func (m *mqttMessenger) Publish(topic string, msg []byte, qos int, retain bool) {
	m.client.Publish(topic, byte(qos), retain, msg)
}

// Subscribe subscribes to the specified topic with a certain qos. The topic
// and message are then passed into this messenger's recv channel and can be
// read from by any interested consumer.
func (m *mqttMessenger) Subscribe(topic string, qos int, callback func(Message)) {
	m.client.Subscribe(topic, byte(qos), func(c mq.Client, msg mq.Message) {
		callback(msg)
	})
}

// Unsubscribe unsubscribes from one or multiple topics.
func (m *mqttMessenger) Unsubscribe(topics ...string) {
	m.client.Unsubscribe(topics...)
}
<|endoftext|>