<commit_before>package go_toast

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"

	"github.com/nu7hatch/gouuid"
)

var toastTemplate *template.Template

func init() {
	toastTemplate = template.New("toast")
	toastTemplate.Parse(`
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null

$APP_ID = '{{if .AppID}}{{.AppID}}{{else}}io.github.jacobmarshall.go-toast{{end}}'

$template = @"
<toast>
    <visual>
        <binding template="ToastGeneric">
            {{if .Icon}}
            <image placement="appLogoOverride" src="{{.Icon}}" />
            {{end}}
            {{if .Title}}
            <text>{{.Title}}</text>
            {{end}}
            {{if .Message}}
            <text>{{.Message}}</text>
            {{end}}
        </binding>
    </visual>
    {{if .Actions}}
    <actions>
        {{range .Actions}}
        <action activationType="{{.Type}}" content="{{.Label}}" arguments="{{.Arguments}}" />
        {{end}}
    </actions>
    {{end}}
</toast>
"@

$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($template)
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
    `)
}

type Notification struct {
	AppID   string
	Title   string
	Message string
	Icon    string
	Actions []Action
}

type Action struct {
	Type      string
	Label     string
	Arguments string
}

func (n *Notification) BuildXML() (string, error) {
	var out bytes.Buffer
	err := toastTemplate.Execute(&out, n)
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

func (n *Notification) Push() error {
	xml, _ := n.BuildXML()
	return invokeTemporaryScript(xml)
}

func invokeTemporaryScript(content string) error {
	id, _ := uuid.NewV4()
	file := filepath.Join(os.TempDir(), id.String()+".ps1")
	defer os.Remove(file)
	err := ioutil.WriteFile(file, []byte(content), 0600)
	if err != nil {
		return err
	}
	if err = exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file).Run(); err != nil {
		return err
	}
	return nil
}
<commit_msg>Add some documentation (not a lot, but hopefully will help a few people getting started)<commit_after>package go_toast

import (
	"bytes"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"

	"github.com/nu7hatch/gouuid"
)

var toastTemplate *template.Template

func init() {
	toastTemplate = template.New("toast")
	toastTemplate.Parse(`
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null

$APP_ID = '{{if .AppID}}{{.AppID}}{{else}}io.github.jacobmarshall.go-toast{{end}}'

$template = @"
<toast>
    <visual>
        <binding template="ToastGeneric">
            {{if .Icon}}
            <image placement="appLogoOverride" src="{{.Icon}}" />
            {{end}}
            {{if .Title}}
            <text>{{.Title}}</text>
            {{end}}
            {{if .Message}}
            <text>{{.Message}}</text>
            {{end}}
        </binding>
    </visual>
    {{if .Actions}}
    <actions>
        {{range .Actions}}
        <action activationType="{{.Type}}" content="{{.Label}}" arguments="{{.Arguments}}" />
        {{end}}
    </actions>
    {{end}}
</toast>
"@

$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($template)
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
    `)
}

type Notification struct {
	// The name of your app. This value shows up in Windows 10's Action Centre, so make it
	// something readable for your users. It can contain spaces, however special characters
	// (eg. é) are not supported.
	AppID   string

	// The main title/heading for the toast notification.
	Title   string

	// The single/multi line message to display for the toast notification.
	Message string

	// An optional path to an image on the OS to display to the left of the title & message.
	Icon    string

	// Optional action buttons to display below the notification title & message.
	Actions []Action
}

// Defines an actionable button.
// See https://msdn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts for more info.
//
// Only protocol type action buttons are actually useful, as there's no way of receiving feedback from the
// user's choice. Examples of protocol type action buttons include: "bingmaps:?q=sushi" to open up Windows 10's
// maps app with a pre-populated search field set to "sushi".
//
//     toast.Action{"protocol", "Open Maps", "bingmaps:?q=sushi"}
type Action struct {
	Type      string
	Label     string
	Arguments string
}

func (n *Notification) buildXML() (string, error) {
	var out bytes.Buffer
	err := toastTemplate.Execute(&out, n)
	if err != nil {
		return "", err
	}
	return out.String(), nil
}

// Builds the Windows PowerShell script & invokes it, causing the toast to display.
//
// Note: Running the PowerShell script is by far the slowest process here, and can take a few
// seconds in some cases.
//
//     notification := toast.Notification{
//         AppID: "Example App",
//         Title: "My notification",
//         Message: "Some message about how important something is...",
//         Icon: "go.png",
//         Actions: []toast.Action{
//             {"protocol", "I'm a button", ""},
//             {"protocol", "Me too!", ""},
//         },
//     }
//     err := notification.Push()
//     if err != nil {
//         log.Fatalln(err)
//     }
func (n *Notification) Push() error {
	xml, _ := n.buildXML()
	return invokeTemporaryScript(xml)
}

func invokeTemporaryScript(content string) error {
	id, _ := uuid.NewV4()
	file := filepath.Join(os.TempDir(), id.String()+".ps1")
	defer os.Remove(file)
	err := ioutil.WriteFile(file, []byte(content), 0600)
	if err != nil {
		return err
	}
	if err = exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file).Run(); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package kafka

import (
	"os"
	"sync"
	"testing"
	"time"

	"github.com/qiniu/logkit/conf"
	"github.com/stretchr/testify/assert"

	"github.com/qiniu/logkit/reader"
	. "github.com/qiniu/logkit/reader/config"
	. "github.com/qiniu/logkit/reader/test"
	. "github.com/qiniu/logkit/utils/models"
)

func TestKafkaReader(t *testing.T) {

	logkitConf := conf.MapConf{
		KeyMetaPath: MetaDir,
		KeyFileDone: MetaDir,
		KeyMode:     ModeElastic,
	}
	meta, err := reader.NewMetaWithConf(logkitConf)
	assert.NoError(t, err)
	defer os.RemoveAll(MetaDir)
	er := &Reader{
		meta:             meta,
		ConsumerGroup:    "group1",
		Topics:           []string{"topic1"},
		ZookeeperPeers:   []string{"localhost:2181"},
		ZookeeperTimeout: time.Second,
		Whence:           "oldest",
		errChan:          make(chan error, 1000),
		lock:             new(sync.Mutex),
		statsLock:        new(sync.RWMutex),
	}
	assert.EqualValues(t, "KafkaReader:[topic1],[group1]", er.Name())

	assert.Equal(t, StatsInfo{}, er.Status())
}
<commit_msg>Ci Retry<commit_after>package kafka

import (
	"os"
	"sync"
	"testing"
	"time"

	"github.com/qiniu/logkit/conf"
	"github.com/stretchr/testify/assert"

	"github.com/qiniu/logkit/reader"
	. "github.com/qiniu/logkit/reader/config"
	. "github.com/qiniu/logkit/reader/test"
	. "github.com/qiniu/logkit/utils/models"
)

func TestKafkaReader(t *testing.T) {
	logkitConf := conf.MapConf{
		KeyMetaPath: MetaDir,
		KeyFileDone: MetaDir,
		KeyMode:     ModeElastic,
	}
	meta, err := reader.NewMetaWithConf(logkitConf)
	assert.NoError(t, err)
	defer os.RemoveAll(MetaDir)
	er := &Reader{
		meta:             meta,
		ConsumerGroup:    "group1",
		Topics:           []string{"topic1"},
		ZookeeperPeers:   []string{"localhost:2181"},
		ZookeeperTimeout: time.Second,
		Whence:           "oldest",
		errChan:          make(chan error, 1000),
		lock:             new(sync.Mutex),
		statsLock:        new(sync.RWMutex),
	}
	assert.EqualValues(t, "KafkaReader:[topic1],[group1]", er.Name())

	assert.Equal(t, StatsInfo{}, er.Status())
}
<|endoftext|>


<commit_before>package lua

type lValueArraySorter struct {
	L      *LState
	Fn     *LFunction
	Values []LValue
}

func (lv lValueArraySorter) Len() int {
	return len(lv.Values)
}

func (lv lValueArraySorter) Swap(i, j int) {
	lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i]
}

func (lv lValueArraySorter) Less(i, j int) bool {
	if lv.Fn != nil {
		lv.L.Push(lv.Fn)
		lv.L.Push(lv.Values[i])
		lv.L.Push(lv.Values[j])
		lv.L.Call(2, 1)
		return LVAsBool(lv.L.reg.Pop())
	}
	return lessThan(lv.L, lv.Values[i], lv.Values[j])
}

func newLTable(acap int, hcap int) *LTable {
	if acap < 0 {
		acap = 0
	}
	if hcap < 0 {
		hcap = 0
	}
	tb := &LTable{
		array:     make([]LValue, 0, acap),
		dict:      make(map[LValue]LValue, hcap),
		strdict:   make(map[string]LValue, hcap),
		keys:      nil,
		k2i:       nil,
		Metatable: LNil,
	}
	return tb
}

func (tb *LTable) Len() int {
	var prev LValue = LNil
	for i := len(tb.array) - 1; i >= 0; i-- {
		v := tb.array[i]
		if prev == LNil && v != LNil {
			return i + 1
		}
		prev = v
	}
	return 0
}

func (tb *LTable) Append(value LValue) {
	tb.array = append(tb.array, value)
}

func (tb *LTable) Insert(i int, value LValue) {
	if i > len(tb.array) {
		tb.RawSetInt(i, value)
		return
	}
	if i <= 0 {
		tb.RawSet(LNumber(i), value)
		return
	}
	i -= 1
	tb.array = append(tb.array, LNil)
	copy(tb.array[i+1:], tb.array[i:])
	tb.array[i] = value
}

func (tb *LTable) MaxN() int {
	for i := len(tb.array) - 1; i >= 0; i-- {
		if tb.array[i] != LNil {
			return i + 1
		}
	}
	return 0
}

func (tb *LTable) Remove(pos int) LValue {
	i := pos - 1
	larray := len(tb.array)
	oldval := LNil
	switch {
	case i >= larray:
		// nothing to do
	case i == larray-1 || i < 0:
		oldval = tb.array[larray-1]
		tb.array = tb.array[:larray-1]
	default:
		oldval = tb.array[i]
		copy(tb.array[i:], tb.array[i+1:])
		tb.array[larray-1] = nil
		tb.array = tb.array[:larray-1]
	}
	return oldval
}

func (tb *LTable) RawSet(key LValue, value LValue) {
	switch v := key.(type) {
	case LNumber:
		if isArrayKey(v) {
			index := int(v) - 1
			alen := len(tb.array)
			switch {
			case index == alen:
				tb.array = append(tb.array, value)
			case index > alen:
				for i := 0; i < (index - alen); i++ {
					tb.array = append(tb.array, LNil)
				}
				tb.array = append(tb.array, value)
			case index < alen:
				tb.array[index] = value
			}
			return
		}
	case LString:
		tb.RawSetString(string(v), value)
		return
	}

	tb.RawSetH(key, value)
}

func (tb *LTable) RawSetInt(key int, value LValue) {
	if key < 1 || key >= MaxArrayIndex {
		tb.RawSetH(LNumber(key), value)
		return
	}
	index := key - 1
	alen := len(tb.array)
	switch {
	case index == alen:
		tb.array = append(tb.array, value)
	case index > alen:
		for i := 0; i < (index - alen); i++ {
			tb.array = append(tb.array, LNil)
		}
		tb.array = append(tb.array, value)
	case index < alen:
		tb.array[index] = value
	}
}

func (tb *LTable) RawSetString(key string, value LValue) {
	if value == LNil {
		delete(tb.strdict, key)
	} else {
		tb.strdict[key] = value
	}
}

func (tb *LTable) RawSetH(key LValue, value LValue) {
	if s, ok := key.(LString); ok {
		tb.RawSetString(string(s), value)
		return
	}

	if value == LNil {
		delete(tb.dict, key)
	} else {
		tb.dict[key] = value
	}
}

func (tb *LTable) RawGet(key LValue) LValue {
	switch v := key.(type) {
	case LNumber:
		if isArrayKey(v) {
			index := int(v) - 1
			if index >= len(tb.array) {
				return LNil
			}
			return tb.array[index]
		}
	case LString:
		if ret, ok := tb.strdict[string(v)]; ok {
			return ret
		}
		return LNil
	}
	if v, ok := tb.dict[key]; ok {
		return v
	}
	return LNil
}

func (tb *LTable) RawGetInt(key int) LValue {
	index := int(key) - 1
	if index >= len(tb.array) || index < 0 {
		return LNil
	}
	return tb.array[index]
}

func (tb *LTable) RawGetH(key LValue) LValue {
	if s, sok := key.(LString); sok {
		if v, vok := tb.strdict[string(s)]; vok {
			return v
		}
		return LNil
	}
	if v, ok := tb.dict[key]; ok {
		return v
	}
	return LNil
}

func (tb *LTable) RawGetString(key string) LValue {
	if v, vok := tb.strdict[string(key)]; vok {
		return v
	}
	return LNil
}

func (tb *LTable) ForEach(cb func(LValue, LValue)) {
	for i, v := range tb.array {
		if v != LNil {
			cb(LNumber(i+1), v)
		}
	}
	for k, v := range tb.strdict {
		if v != LNil {
			cb(LString(k), v)
		}
	}
	for k, v := range tb.dict {
		if v != LNil {
			cb(k, v)
		}
	}
}

func (tb *LTable) Next(key LValue) (LValue, LValue) {
	// TODO: inefficient way
	if key == LNil {
		tb.keys = nil
		tb.k2i = nil
		key = LNumber(0)
	}

	if tb.keys == nil {
		tb.keys = make([]LValue, len(tb.dict)+len(tb.strdict))
		tb.k2i = make(map[LValue]int)
		i := 0
		for k, _ := range tb.dict {
			tb.keys[i] = k
			tb.k2i[k] = i
			i++
		}
		for k, _ := range tb.strdict {
			tb.keys[i] = LString(k)
			tb.k2i[LString(k)] = i
			i++
		}
	}

	if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 {
		index := int(kv)
		for ; index < len(tb.array); index++ {
			if v := tb.array[index]; v != LNil {
				return LNumber(index + 1), v
			}
		}
		if index == len(tb.array) {
			if len(tb.dict) == 0 && len(tb.strdict) == 0 {
				tb.keys = nil
				tb.k2i = nil
				return LNil, LNil
			}
			key = tb.keys[0]
			if skey, sok := key.(LString); sok {
				if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil {
					return key, sv
				}
			} else if v, vok := tb.dict[key]; vok && v != LNil {
				return key, v
			}
		}
	}
	length := len(tb.dict) + len(tb.strdict)
	for i := tb.k2i[key] + 1; i < length; i++ {
		key = tb.keys[i]
		if skey, sok := key.(LString); sok {
			if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil {
				return key, sv
			}
		} else if v, vok := tb.dict[key]; vok && v != LNil {
			return key, v
		}
	}
	tb.keys = nil
	tb.k2i = nil
	return LNil, LNil
}
<commit_msg>reduce table allocations<commit_after>package lua

const defaultArrayCap = 32
const defaultHashCap = 32

type lValueArraySorter struct {
	L      *LState
	Fn     *LFunction
	Values []LValue
}

func (lv lValueArraySorter) Len() int {
	return len(lv.Values)
}

func (lv lValueArraySorter) Swap(i, j int) {
	lv.Values[i], lv.Values[j] = lv.Values[j], lv.Values[i]
}

func (lv lValueArraySorter) Less(i, j int) bool {
	if lv.Fn != nil {
		lv.L.Push(lv.Fn)
		lv.L.Push(lv.Values[i])
		lv.L.Push(lv.Values[j])
		lv.L.Call(2, 1)
		return LVAsBool(lv.L.reg.Pop())
	}
	return lessThan(lv.L, lv.Values[i], lv.Values[j])
}

func newLTable(acap int, hcap int) *LTable {
	if acap < 0 {
		acap = 0
	}
	if hcap < 0 {
		hcap = 0
	}
	tb := &LTable{}
	tb.keys = nil
	tb.k2i = nil
	tb.Metatable = LNil
	if acap != 0 {
		tb.array = make([]LValue, 0, acap)
	}
	if hcap != 0 {
		tb.strdict = make(map[string]LValue, hcap)
	}
	return tb
}

func (tb *LTable) Len() int {
	if tb.array == nil {
		return 0
	}
	var prev LValue = LNil
	for i := len(tb.array) - 1; i >= 0; i-- {
		v := tb.array[i]
		if prev == LNil && v != LNil {
			return i + 1
		}
		prev = v
	}
	return 0
}

func (tb *LTable) Append(value LValue) {
	if tb.array == nil {
		tb.array = make([]LValue, 0, defaultArrayCap)
	}
	tb.array = append(tb.array, value)
}

func (tb *LTable) Insert(i int, value LValue) {
	if tb.array == nil {
		tb.array = make([]LValue, 0, defaultArrayCap)
	}
	if i > len(tb.array) {
		tb.RawSetInt(i, value)
		return
	}
	if i <= 0 {
		tb.RawSet(LNumber(i), value)
		return
	}
	i -= 1
	tb.array = append(tb.array, LNil)
	copy(tb.array[i+1:], tb.array[i:])
	tb.array[i] = value
}

func (tb *LTable) MaxN() int {
	if tb.array == nil {
		return 0
	}
	for i := len(tb.array) - 1; i >= 0; i-- {
		if tb.array[i] != LNil {
			return i + 1
		}
	}
	return 0
}

func (tb *LTable) Remove(pos int) LValue {
	if tb.array == nil {
		return LNil
	}
	i := pos - 1
	larray := len(tb.array)
	oldval := LNil
	switch {
	case i >= larray:
		// nothing to do
	case i == larray-1 || i < 0:
		oldval = tb.array[larray-1]
		tb.array = tb.array[:larray-1]
	default:
		oldval = tb.array[i]
		copy(tb.array[i:], tb.array[i+1:])
		tb.array[larray-1] = nil
		tb.array = tb.array[:larray-1]
	}
	return oldval
}

func (tb *LTable) RawSet(key LValue, value LValue) {
	switch v := key.(type) {
	case LNumber:
		if isArrayKey(v) {
			if tb.array == nil {
				tb.array = make([]LValue, 0, defaultArrayCap)
			}
			index := int(v) - 1
			alen := len(tb.array)
			switch {
			case index == alen:
				tb.array = append(tb.array, value)
			case index > alen:
				for i := 0; i < (index - alen); i++ {
					tb.array = append(tb.array, LNil)
				}
				tb.array = append(tb.array, value)
			case index < alen:
				tb.array[index] = value
			}
			return
		}
	case LString:
		tb.RawSetString(string(v), value)
		return
	}

	tb.RawSetH(key, value)
}

func (tb *LTable) RawSetInt(key int, value LValue) {
	if key < 1 || key >= MaxArrayIndex {
		tb.RawSetH(LNumber(key), value)
		return
	}
	if tb.array == nil {
		tb.array = make([]LValue, 0, 32)
	}
	index := key - 1
	alen := len(tb.array)
	switch {
	case index == alen:
		tb.array = append(tb.array, value)
	case index > alen:
		for i := 0; i < (index - alen); i++ {
			tb.array = append(tb.array, LNil)
		}
		tb.array = append(tb.array, value)
	case index < alen:
		tb.array[index] = value
	}
}

func (tb *LTable) RawSetString(key string, value LValue) {
	if tb.strdict == nil {
		tb.strdict = make(map[string]LValue, defaultHashCap)
	}
	if value == LNil {
		delete(tb.strdict, key)
	} else {
		tb.strdict[key] = value
	}
}

func (tb *LTable) RawSetH(key LValue, value LValue) {
	if s, ok := key.(LString); ok {
		tb.RawSetString(string(s), value)
		return
	}
	if tb.dict == nil {
		tb.dict = make(map[LValue]LValue, len(tb.strdict))
	}

	if value == LNil {
		delete(tb.dict, key)
	} else {
		tb.dict[key] = value
	}
}

func (tb *LTable) RawGet(key LValue) LValue {
	switch v := key.(type) {
	case LNumber:
		if isArrayKey(v) {
			if tb.array == nil {
				return LNil
			}
			index := int(v) - 1
			if index >= len(tb.array) {
				return LNil
			}
			return tb.array[index]
		}
	case LString:
		if tb.strdict == nil {
			return LNil
		}
		if ret, ok := tb.strdict[string(v)]; ok {
			return ret
		}
		return LNil
	}
	if tb.dict == nil {
		return LNil
	}
	if v, ok := tb.dict[key]; ok {
		return v
	}
	return LNil
}

func (tb *LTable) RawGetInt(key int) LValue {
	if tb.array == nil {
		return LNil
	}
	index := int(key) - 1
	if index >= len(tb.array) || index < 0 {
		return LNil
	}
	return tb.array[index]
}

func (tb *LTable) RawGetH(key LValue) LValue {
	if s, sok := key.(LString); sok {
		if tb.strdict == nil {
			return LNil
		}
		if v, vok := tb.strdict[string(s)]; vok {
			return v
		}
		return LNil
	}
	if tb.dict == nil {
		return LNil
	}
	if v, ok := tb.dict[key]; ok {
		return v
	}
	return LNil
}

func (tb *LTable) RawGetString(key string) LValue {
	if tb.strdict == nil {
		return LNil
	}
	if v, vok := tb.strdict[string(key)]; vok {
		return v
	}
	return LNil
}

func (tb *LTable) ForEach(cb func(LValue, LValue)) {
	if tb.array != nil {
		for i, v := range tb.array {
			if v != LNil {
				cb(LNumber(i+1), v)
			}
		}
	}
	if tb.strdict != nil {
		for k, v := range tb.strdict {
			if v != LNil {
				cb(LString(k), v)
			}
		}
	}
	if tb.dict != nil {
		for k, v := range tb.dict {
			if v != LNil {
				cb(k, v)
			}
		}
	}
}

func (tb *LTable) Next(key LValue) (LValue, LValue) {
	// TODO: inefficient way
	if key == LNil {
		tb.keys = nil
		tb.k2i = nil
		key = LNumber(0)
	}

	length := 0
	if tb.dict != nil {
		length += len(tb.dict)
	}
	if tb.strdict != nil {
		length += len(tb.strdict)
	}

	if tb.keys == nil {
		tb.keys = make([]LValue, length)
		tb.k2i = make(map[LValue]int)
		i := 0
		if tb.dict != nil {
			for k, _ := range tb.dict {
				tb.keys[i] = k
				tb.k2i[k] = i
				i++
			}
		}
		if tb.strdict != nil {
			for k, _ := range tb.strdict {
				tb.keys[i] = LString(k)
				tb.k2i[LString(k)] = i
				i++
			}
		}
	}

	if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 {
		index := int(kv)
		if tb.array != nil {
			for ; index < len(tb.array); index++ {
				if v := tb.array[index]; v != LNil {
					return LNumber(index + 1), v
				}
			}
		}
		if tb.array == nil || index == len(tb.array) {
			if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) {
				tb.keys = nil
				tb.k2i = nil
				return LNil, LNil
			}
			key = tb.keys[0]
			if skey, sok := key.(LString); sok && tb.strdict != nil {
				if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil {
					return key, sv
				}
			} else if tb.dict != nil {
				if v, vok := tb.dict[key]; vok && v != LNil {
					return key, v
				}
			}
		}
	}
	for i := tb.k2i[key] + 1; i < length; i++ {
		key = tb.keys[i]
		if skey, sok := key.(LString); sok && tb.strdict != nil {
			if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil {
				return key, sv
			}
		} else if tb.dict != nil {
			if v, vok := tb.dict[key]; vok && v != LNil {
				return key, v
			}
		}
	}
	tb.keys = nil
	tb.k2i = nil
	return LNil, LNil
}
<|endoftext|>


<commit_before>package main

import "bufio"
import "flag"
import "fmt"
import "io/ioutil"
import "os"

func jump_forward(source []uint8, start int, source_length int) int {
	var target = 0
	var cnt = 1
	for tip := start; tip < source_length; tip++ {
		cc := string(source[tip])
		if cc == "[" {
			cnt += 1
		} else if cc == "]" {
			cnt -= 1
		}
		if cnt == 0 {
			target = tip
			break
		}
	}
	return target + 1
}

func jump_backward(b []uint8, start int) int {
	var target = 0
	var cnt = 1
	for tip := start; tip > 0; tip-- {
		cc := string(b[tip])
		if cc == "]" {
			cnt += 1
		} else if cc == "[" {
			cnt -= 1
		}
		if cnt == 0 {
			target = tip
			break
		}
	}
	return target + 1
}

func main() {
	pathPtr := flag.String("path", "", "path to Brainfuck source")
	sizePtr := flag.Int("size", 30000, "size of the data array")

	flag.Parse()

	path := *pathPtr
	if path == "" {
		fmt.Println("You must specify a path to Brainfuck source: -path=...")
	}

	source, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	reader := bufio.NewReader(os.Stdin)

	var data = make([]int, *sizePtr)
	var source_length = len(source)
	var dp = 0
	for ip := 0; ip < source_length; {
		var c = string(source[ip])
		switch {
		case c == ">":
			dp += 1
			ip += 1
		case c == "<":
			dp -= 1
			ip += 1
		case c == "+":
			data[dp] += 1
			ip += 1
		case c == "-":
			data[dp] -= 1
			ip += 1
		case c == ".":
			fmt.Print(string(data[dp]))
			ip += 1
		case c == ",":
			s, err := reader.ReadString('\n')
			if err != nil {
				panic(err)
			}
			if len(s) != 2 {
				panic("You must provide a single character")
			}
			data[dp] = int(s[0])
			ip += 1
		case c == "[":
			if data[dp] == 0 {
				ip = jump_forward(source, ip+1, source_length)
			} else {
				ip += 1
			}
		case c == "]":
			if data[dp] != 0 {
				ip = jump_backward(source, ip-1)
			} else {
				ip += 1
			}
		default:
			ip += 1
		}
	}
}
<commit_msg>Keep variable names consistent<commit_after>package main

import "bufio"
import "flag"
import "fmt"
import "io/ioutil"
import "os"

func jump_forward(source []uint8, start int, source_length int) int {
	var target = 0
	var cnt = 1
	for tip := start; tip < source_length; tip++ {
		cc := string(source[tip])
		if cc == "[" {
			cnt += 1
		} else if cc == "]" {
			cnt -= 1
		}
		if cnt == 0 {
			target = tip
			break
		}
	}
	return target + 1
}

func jump_backward(source []uint8, start int) int {
	var target = 0
	var cnt = 1
	for tip := start; tip > 0; tip-- {
		cc := string(source[tip])
		if cc == "]" {
			cnt += 1
		} else if cc == "[" {
			cnt -= 1
		}
		if cnt == 0 {
			target = tip
			break
		}
	}
	return target + 1
}

func main() {
	pathPtr := flag.String("path", "", "path to Brainfuck source")
	sizePtr := flag.Int("size", 30000, "size of the data array")

	flag.Parse()

	path := *pathPtr
	if path == "" {
		fmt.Println("You must specify a path to Brainfuck source: -path=...")
	}

	source, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	reader := bufio.NewReader(os.Stdin)

	var data = make([]int, *sizePtr)
	var source_length = len(source)
	var dp = 0
	for ip := 0; ip < source_length; {
		var c = string(source[ip])
		switch {
		case c == ">":
			dp += 1
			ip += 1
		case c == "<":
			dp -= 1
			ip += 1
		case c == "+":
			data[dp] += 1
			ip += 1
		case c == "-":
			data[dp] -= 1
			ip += 1
		case c == ".":
			fmt.Print(string(data[dp]))
			ip += 1
		case c == ",":
			s, err := reader.ReadString('\n')
			if err != nil {
				panic(err)
			}
			if len(s) != 2 {
				panic("You must provide a single character")
			}
			data[dp] = int(s[0])
			ip += 1
		case c == "[":
			if data[dp] == 0 {
				ip = jump_forward(source, ip+1, source_length)
			} else {
				ip += 1
			}
		case c == "]":
			if data[dp] != 0 {
				ip = jump_backward(source, ip-1)
			} else {
				ip += 1
			}
		default:
			ip += 1
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"reflect"
)

const (
	DEFAULT_FILE_MODE = 0777
)

type Task func() error

type Constructor func(target *Target, args Object) (Task, error)

var tasksMap map[string]Constructor

func init() {
	tasksMap = map[string]Constructor{
		"go":     Go,
		"print":  Print,
		"cd":     Cd,
		"mkdir":  MkDir,
		"if":     If,
		"for":    For,
		"while":  While,
		"delete": Delete,
	}
}

// TASKS DEFINITIONS

func Go(target *Target, args Object) (Task, error) {
	source, ok := args["go"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task go must be a string")
	}
	return func() error {
		_, err := target.Build.Context.Evaluate(source)
		if err != nil {
			return fmt.Errorf("evaluating go source: %v", err)
		}
		return nil
	}, nil
}

func Print(target *Target, args Object) (Task, error) {
	message, ok := args["print"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task print must be a string")
	}
	return func() error {
		evaluated, err := target.Build.Context.ReplaceProperties(message)
		if err != nil {
			return fmt.Errorf("processing print argument: %v", err)
		}
		fmt.Println(evaluated)
		return nil
	}, nil
}

func Cd(target *Target, args Object) (Task, error) {
	dir, ok := args["cd"].(string)
	if !ok {
		return nil, fmt.Errorf("argument to task cd must be a string")
	}
	return func() error {
		directory, err := target.Build.Context.ReplaceProperties(dir)
		fmt.Printf("Changing to directory '%s'\n", directory)
		if err != nil {
			return fmt.Errorf("processing cd argument: %v", err)
		}
		err = os.Chdir(directory)
		if err != nil {
			return fmt.Errorf("changing to directory '%s': %s", directory, err)
		}
		return nil
	}, nil
}

func MkDir(target *Target, args Object) (Task, error) {
	dir, ok := args["mkdir"].(string)
	if !ok {
		return nil, fmt.Errorf("argument to task mkdir must be a string")
	}
	return func() error {
		directory, err := target.Build.Context.ReplaceProperties(dir)
		fmt.Printf("Making directory '%s'\n", directory)
		if err != nil {
			return fmt.Errorf("processing mkdir argument: %v", err)
		}
		err = os.MkdirAll(directory, DEFAULT_FILE_MODE)
		if err != nil {
			return fmt.Errorf("making directory '%s': %s", directory, err)
		}
		return nil
	}, nil
}

func If(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"if", "then", "else"}); err != nil {
		return nil, fmt.Errorf("building if condition: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"if", "then"}); err != nil {
		return nil, fmt.Errorf("building if condition: %v", err)
	}
	condition, err := args.GetString("if")
	if err != nil {
		return nil, fmt.Errorf("evaluating if construct: %v", err)
	}
	thenSteps, err := ParseSteps(target, args, "then")
	if err != nil {
		return nil, err
	}
	var elseSteps []Step
	if FieldInList("else", fields) {
		elseSteps, err = ParseSteps(target, args, "else")
		if err != nil {
			return nil, err
		}
	}
	return func() error {
		result, err := target.Build.Context.Evaluate(condition)
		if err != nil {
			return fmt.Errorf("evaluating 'if' condition: %v", err)
		}
		boolean, ok := result.(bool)
		if !ok {
			return fmt.Errorf("evaluating if condition: must return a bool")
		}
		if boolean {
			err := RunSteps(thenSteps)
			if err != nil {
				return err
			}
		} else {
			err := RunSteps(elseSteps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil
}

func For(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"for", "in", "do"}); err != nil {
		return nil, fmt.Errorf("building 'for' loop: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"for", "in", "do"}); err != nil {
		return nil, fmt.Errorf("building 'for' loop: %v", err)
	}
	variable, err := args.GetString("for")
	if err != nil {
		return nil, fmt.Errorf("'for' field of a 'for' loop must be a string")
	}
	list, err := args.GetList("in")
	expression := ""
	if err != nil {
		expression, err = args.GetString("in")
		if err != nil {
			return nil, fmt.Errorf("'in' field of 'for' loop must be a list or string")
		}
	}
	steps, err := ParseSteps(target, args, "do")
	if err != nil {
		return nil, err
	}
	return func() error {
		if expression != "" {
			result, err := target.Build.Context.Evaluate(expression)
			if err != nil {
				return fmt.Errorf("evaluating in field of for loop: %v", err)
			}
			list, err = ToList(result)
			if err != nil {
				return fmt.Errorf("'in' field of 'for' loop must be an expression that returns a list")
			}
		}
		for _, value := range list {
			target.Build.Context.SetProperty(variable, value)
			if err != nil {
				return err
			}
			err := RunSteps(steps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil

}

func While(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"while", "do"}); err != nil {
		return nil, fmt.Errorf("building 'while' loop: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"while", "do"}); err != nil {
		return nil, fmt.Errorf("building 'while' loop: %v", err)
	}
	condition, err := args.GetString("while")
	if err != nil {
		return nil, fmt.Errorf("'while' field of a 'while' loop must be a string")
	}
	steps, err := ParseSteps(target, args, "do")
	if err != nil {
		return nil, err
	}
	return func() error {
		for {
			result, err := target.Build.Context.Evaluate(condition)
			if err != nil {
				return fmt.Errorf("evaluating 'while' field of 'while' loop: %v", err)
			}
			loop, ok := result.(bool)
			if !ok {
				return fmt.Errorf("evaluating 'while' condition: must return a bool")
			}
			if !loop {
				break
			}
			err = RunSteps(steps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil
}

func Delete(target *Target, args Object) (Task, error) {
	directories, err := args.GetListStringsOrString("delete")
	if err != nil {
		return nil, fmt.Errorf("delete argument must be string or list of strings")
	}
	return func() error {
		for _, dir := range directories {
			directory, err := target.Build.Context.ReplaceProperties(dir)
			if err != nil {
				return fmt.Errorf("evaluating directory in task delete: %v", err)
			}
			if _, err := os.Stat(directory); err == nil {
				fmt.Printf("Deleting directory '%s'\n", directory)
				err = os.RemoveAll(directory)
				if err != nil {
					return fmt.Errorf("deleting directory '%s': %v", directory, err)
				}
			}
		}
		return nil
	}, nil
}

// UTILITY FUNCTIONS

func FieldsInList(fields, list []string) error {
	for _, field := range fields {
		found := false
		for _, e := range list {
			if e == field {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("unknown field '%s'", field)
		}
	}
	return nil
}

func FieldInList(field string, list []string) bool {
	for _, f := range list {
		if f == field {
			return true
		}
	}
	return false
}

func FieldsMandatory(fields, mandatory []string) error {
	for _, manda := range mandatory {
		found := false
		for _, field := range fields {
			if manda == field {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("mandatory field '%s' not found", manda)
		}
	}
	return nil
}

func ParseSteps(target *Target, object Object, field string) ([]Step, error) {
	list, err := object.GetList(field)
	if err != nil {
		return nil, err
	}
	var steps []Step
	for index, element := range list {
		target.Build.Log("Parsing step %v in %s field", index, field)
		step, err := NewStep(target, element)
		if err != nil {
			return nil, fmt.Errorf("parsing target '%s': %v", target.Name, err)
		}
		steps = append(steps, step)
	}
	return steps, nil
}

func RunSteps(steps []Step) error {
	for _, step := range steps {
		err := step.Run()
		if err != nil {
			return err
		}
	}
	return nil
}

func ToList(object interface{}) ([]interface{}, error) {
	slice := reflect.ValueOf(object)
	if slice.Kind() == reflect.Slice {
		result := make([]interface{}, slice.Len())
		for i := 0; i < slice.Len(); i++ {
			result[i] = slice.Index(i).Interface()
		}
		return result, nil
	} else {
		return nil, fmt.Errorf("must be a list")
	}
}
<commit_msg>Reordered tasks<commit_after>package main

import (
	"fmt"
	"os"
	"reflect"
)

const (
	DEFAULT_FILE_MODE = 0777
)

type Task func() error

type Constructor func(target *Target, args Object) (Task, error)

var tasksMap map[string]Constructor

func init() {
	tasksMap = map[string]Constructor{
		"go":     Go,
		"print":  Print,
		"cd":     Cd,
		"mkdir":  MkDir,
		"delete": Delete,
		"if":     If,
		"for":    For,
		"while":  While,
	}
}

// TASKS DEFINITIONS

func Go(target *Target, args Object) (Task, error) {
	source, ok := args["go"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task go must be a string")
	}
	return func() error {
		_, err := target.Build.Context.Evaluate(source)
		if err != nil {
			return fmt.Errorf("evaluating go source: %v", err)
		}
		return nil
	}, nil
}

func Print(target *Target, args Object) (Task, error) {
	message, ok := args["print"].(string)
	if !ok {
		return nil, fmt.Errorf("argument of task print must be a string")
	}
	return func() error {
		evaluated, err := target.Build.Context.ReplaceProperties(message)
		if err != nil {
			return fmt.Errorf("processing print argument: %v", err)
		}
		fmt.Println(evaluated)
		return nil
	}, nil
}

func Cd(target *Target, args Object) (Task, error) {
	dir, ok := args["cd"].(string)
	if !ok {
		return nil, fmt.Errorf("argument to task cd must be a string")
	}
	return func() error {
		directory, err := target.Build.Context.ReplaceProperties(dir)
		fmt.Printf("Changing to directory '%s'\n", directory)
		if err != nil {
			return fmt.Errorf("processing cd argument: %v", err)
		}
		err = os.Chdir(directory)
		if err != nil {
			return fmt.Errorf("changing to directory '%s': %s", directory, err)
		}
		return nil
	}, nil
}

func MkDir(target *Target, args Object) (Task, error) {
	dir, ok := args["mkdir"].(string)
	if !ok {
		return nil, fmt.Errorf("argument to task mkdir must be a string")
	}
	return func() error {
		directory, err := target.Build.Context.ReplaceProperties(dir)
		fmt.Printf("Making directory '%s'\n", directory)
		if err != nil {
			return fmt.Errorf("processing mkdir argument: %v", err)
		}
		err = os.MkdirAll(directory, DEFAULT_FILE_MODE)
		if err != nil {
			return fmt.Errorf("making directory '%s': %s", directory, err)
		}
		return nil
	}, nil
}

func Delete(target *Target, args Object) (Task, error) {
	directories, err := args.GetListStringsOrString("delete")
	if err != nil {
		return nil, fmt.Errorf("delete argument must be string or list of strings")
	}
	return func() error {
		for _, dir := range directories {
			directory, err := target.Build.Context.ReplaceProperties(dir)
			if err != nil {
				return fmt.Errorf("evaluating directory in task delete: %v", err)
			}
			if _, err := os.Stat(directory); err == nil {
				fmt.Printf("Deleting directory '%s'\n", directory)
				err = os.RemoveAll(directory)
				if err != nil {
					return fmt.Errorf("deleting directory '%s': %v", directory, err)
				}
			}
		}
		return nil
	}, nil
}

func If(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"if", "then", "else"}); err != nil {
		return nil, fmt.Errorf("building if condition: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"if", "then"}); err != nil {
		return nil, fmt.Errorf("building if condition: %v", err)
	}
	condition, err := args.GetString("if")
	if err != nil {
		return nil, fmt.Errorf("evaluating if construct: %v", err)
	}
	thenSteps, err := ParseSteps(target, args, "then")
	if err != nil {
		return nil, err
	}
	var elseSteps []Step
	if FieldInList("else", fields) {
		elseSteps, err = ParseSteps(target, args, "else")
		if err != nil {
			return nil, err
		}
	}
	return func() error {
		result, err := target.Build.Context.Evaluate(condition)
		if err != nil {
			return fmt.Errorf("evaluating 'if' condition: %v", err)
		}
		boolean, ok := result.(bool)
		if !ok {
			return fmt.Errorf("evaluating if condition: must return a bool")
		}
		if boolean {
			err := RunSteps(thenSteps)
			if err != nil {
				return err
			}
		} else {
			err := RunSteps(elseSteps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil
}

func For(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"for", "in", "do"}); err != nil {
		return nil, fmt.Errorf("building 'for' loop: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"for", "in", "do"}); err != nil {
		return nil, fmt.Errorf("building 'for' loop: %v", err)
	}
	variable, err := args.GetString("for")
	if err != nil {
		return nil, fmt.Errorf("'for' field of a 'for' loop must be a string")
	}
	list, err := args.GetList("in")
	expression := ""
	if err != nil {
		expression, err = args.GetString("in")
		if err != nil {
			return nil, fmt.Errorf("'in' field of 'for' loop must be a list or string")
		}
	}
	steps, err := ParseSteps(target, args, "do")
	if err != nil {
		return nil, err
	}
	return func() error {
		if expression != "" {
			result, err := target.Build.Context.Evaluate(expression)
			if err != nil {
				return fmt.Errorf("evaluating in field of for loop: %v", err)
			}
			list, err = ToList(result)
			if err != nil {
				return fmt.Errorf("'in' field of 'for' loop must be an expression that returns a list")
			}
		}
		for _, value := range list {
			target.Build.Context.SetProperty(variable, value)
			if err != nil {
				return err
			}
			err := RunSteps(steps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil

}

func While(target *Target, args Object) (Task, error) {
	fields := args.Fields()
	if err := FieldsInList(fields, []string{"while", "do"}); err != nil {
		return nil, fmt.Errorf("building 'while' loop: %v", err)
	}
	if err := FieldsMandatory(fields, []string{"while", "do"}); err != nil {
		return nil, fmt.Errorf("building 'while' loop: %v", err)
	}
	condition, err := args.GetString("while")
	if err != nil {
		return nil, fmt.Errorf("'while' field of a 'while' loop must be a string")
	}
	steps, err := ParseSteps(target, args, "do")
	if err != nil {
		return nil, err
	}
	return func() error {
		for {
			result, err := target.Build.Context.Evaluate(condition)
			if err != nil {
				return fmt.Errorf("evaluating 'while' field of 'while' loop: %v", err)
			}
			loop, ok := result.(bool)
			if !ok {
				return fmt.Errorf("evaluating 'while' condition: must return a bool")
			}
			if !loop {
				break
			}
			err = RunSteps(steps)
			if err != nil {
				return err
			}
		}
		return nil
	}, nil
}

// UTILITY FUNCTIONS

func FieldsInList(fields, list []string) error {
	for _, field := range fields {
		found := false
		for _, e := range list {
			if e == field {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("unknown field '%s'", field)
		}
	}
	return nil
}

func FieldInList(field string, list []string) bool {
	for _, f := range list {
		if f == field {
			return true
		}
	}
	return false
}

func FieldsMandatory(fields, mandatory []string) error {
	for _, manda := range mandatory {
		found := false
		for _, field := range fields {
			if manda == field {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("mandatory field '%s' not found", manda)
		}
	}
	return nil
}

func ParseSteps(target *Target, object Object, field string) ([]Step, error) {
	list, err := object.GetList(field)
	if err != nil {
		return nil, err
	}
	var steps []Step
	for index, element := range list {
		target.Build.Log("Parsing step %v in %s field", index, field)
		step, err := NewStep(target, element)
		if err != nil {
			return nil, fmt.Errorf("parsing target '%s': %v", target.Name, err)
		}
		steps = append(steps, step)
	}
	return steps, nil
}

func RunSteps(steps []Step) error {
	for _, step := range steps {
		err := step.Run()
		if err != nil {
			return err
		}
	}
	return nil
}

func ToList(object interface{}) ([]interface{}, error) {
	slice := reflect.ValueOf(object)
	if slice.Kind() == reflect.Slice {
		result := make([]interface{}, slice.Len())
		for i := 0; i < slice.Len(); i++ {
			result[i] = slice.Index(i).Interface()
		}
		return result, nil
	} else {
		return nil, fmt.Errorf("must be a list")
	}
}
<|endoftext|>


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

package application

import (
	"encoding/json"
	"errors"
	"github.com/cloudawan/cloudone/control"
	"github.com/cloudawan/cloudone_utility/random"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
)

type Cluster struct {
	Name                      string
	Description               string
	ReplicationControllerJson string
	ServiceJson               string
	Environment               map[string]string
	ScriptType                string
	ScriptContent             string
}

func LaunchClusterApplication(kubeapiHost string, kubeapiPort int, namespace string, name string, environmentSlice []interface{}, size int) error {
	cluster, err := GetStorage().LoadClusterApplication(name)
	if err != nil {
		log.Error("Load cluster application error %s", err)
		return err
	}

	switch cluster.ScriptType {
	case "none":
		return LaunchClusterApplicationNoScript(kubeapiHost, kubeapiPort, namespace, cluster, environmentSlice, size)
	case "python":
		return LaunchClusterApplicationPython(kubeapiHost, kubeapiPort, namespace, cluster, environmentSlice, size)
	default:
		log.Error("No such script type: %s", cluster.ScriptType)
		return errors.New("No such script type: " + cluster.ScriptType)
	}
}

func LaunchClusterApplicationNoScript(kubeapiHost string, kubeapiPort int, namespace string, cluster *Cluster, environmentSlice []interface{}, size int) error {
	replicationControllerJsonMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(cluster.ReplicationControllerJson), &replicationControllerJsonMap)
	if err != nil {
		log.Error("Unmarshal replication controller json for cluster application error %s", err)
		return err
	}

	serviceJsonMap := make(map[string]interface{})
	err = json.Unmarshal([]byte(cluster.ServiceJson), &serviceJsonMap)
	if err != nil {
		log.Error("Unmarshal service json for cluster application error %s", err)
		return err
	}

	// Add environment variable
	if environmentSlice != nil {
		specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
		if ok {
			templateJsonMap, ok := specJsonMap["template"].(map[string]interface{})
			if ok {
				specJsonMap, ok := templateJsonMap["spec"].(map[string]interface{})
				if ok {
					containerSlice, ok := specJsonMap["containers"].([]interface{})
					if ok {
						for i := 0; i < len(containerSlice); i++ {
							_, ok := containerSlice[i].(map[string]interface{})["env"].([]interface{})
							if ok {
								for _, environment := range environmentSlice {
									containerSlice[i].(map[string]interface{})["env"] = append(containerSlice[i].(map[string]interface{})["env"].([]interface{}), environment)
								}
							} else {
								containerSlice[i].(map[string]interface{})["env"] = environmentSlice
							}
						}
					}
				}
			}
		}
	}

	// Change size
	specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
	if ok {
		specJsonMap["replicas"] = size
	}

	err = control.CreateReplicationControllerWithJson(kubeapiHost, kubeapiPort, namespace, replicationControllerJsonMap)
	if err != nil {
		log.Error("CreateReplicationControllerWithJson error %s", err)
		return err
	}
	err = control.CreateServiceWithJson(kubeapiHost, kubeapiPort, namespace, serviceJsonMap)
	if err != nil {
		log.Error("CreateReplicationControllerWithJson error %s", err)
		return err
	}

	return nil
}

func LaunchClusterApplicationPython(kubeapiHost string, kubeapiPort int, namespace string, cluster *Cluster, environmentSlice []interface{}, size int) error {
	replicationControllerJsonMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(cluster.ReplicationControllerJson), &replicationControllerJsonMap)
	if err != nil {
		log.Error("Unmarshal replication controller json for cluster application error %s", err)
		return err
	}

	// Add environment variable
	if environmentSlice != nil {
		specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
		if ok {
			templateJsonMap, ok := specJsonMap["template"].(map[string]interface{})
			if ok {
				specJsonMap, ok := templateJsonMap["spec"].(map[string]interface{})
				if ok {
					containerSlice, ok := specJsonMap["containers"].([]interface{})
					if ok {
						for i := 0; i < len(containerSlice); i++ {
							_, ok := containerSlice[i].(map[string]interface{})["env"].([]interface{})
							if ok {
								for _, environment := range environmentSlice {
									containerSlice[i].(map[string]interface{})["env"] = append(containerSlice[i].(map[string]interface{})["env"].([]interface{}), environment)
								}
							} else {
								containerSlice[i].(map[string]interface{})["env"] = environmentSlice
							}
						}
					}
				}
			}
		}
	}

	replicationControllerByteSlice, err := json.Marshal(replicationControllerJsonMap)
	if err != nil {
		log.Error("Marshal replication controller json for cluster application error %s", err)
		return err
	}

	environmentByteSlice, err := json.Marshal(environmentSlice)
	if err != nil {
		log.Error("Marshal environment json for cluster application error %s", err)
		return err
	}

	// Generate random work space
	workingDirectory := "/tmp/tmp_" + random.UUID()
	replicationControllerFileName := "replication-controller.json"
	serviceFileName := "service.json"
	scriptFileName := "script"
	environmentFileName := "environment.json"

	// Check working space
	if _, err := os.Stat(workingDirectory); os.IsNotExist(err) {
		err := os.MkdirAll(workingDirectory, os.ModePerm)
		if err != nil {
			log.Error("Create non-existing directory %s error: %s", workingDirectory, err)
			return err
		}
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+environmentFileName, environmentByteSlice, os.ModePerm)
	if err != nil {
		log.Error("Write environment json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+replicationControllerFileName, replicationControllerByteSlice, os.ModePerm)
	if err != nil {
		log.Error("Write replication controller json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+serviceFileName, []byte(cluster.ServiceJson), os.ModePerm)
	if err != nil {
		log.Error("Write service json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+scriptFileName, []byte(cluster.ScriptContent), os.ModePerm)
	if err != nil {
		log.Error("Write script file for cluster application error %s", err)
		return err
	}

	command := exec.Command("python", scriptFileName,
		"--application_name="+cluster.Name,
		"--kubeapi_host_and_port=http://"+kubeapiHost+":"+strconv.Itoa(kubeapiPort),
		"--namespace="+namespace,
		"--size="+strconv.Itoa(size),
		"--service_file_name="+serviceFileName,
		"--replication_controller_file_name="+replicationControllerFileName,
		"--environment_file_name="+environmentFileName,
		"--timeout_in_second=120",
		"--action=create")
	command.Dir = workingDirectory
	out, err := command.CombinedOutput()
	log.Debug(string(out))
	if err != nil {
		log.Error("Run python script file for cluster application error %s", err)
		return err
	}

	// Remove working space
	err = os.RemoveAll(workingDirectory)
	if err != nil {
		log.Error("Remove the working directory for cluster application error %s", err)
		return err
	}

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

package application

import (
	"encoding/json"
	"errors"
	"github.com/cloudawan/cloudone/control"
	"github.com/cloudawan/cloudone_utility/random"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
)

type Cluster struct {
	Name                      string
	Description               string
	ReplicationControllerJson string
	ServiceJson               string
	Environment               map[string]string
	ScriptType                string
	ScriptContent             string
}

func LaunchClusterApplication(kubeapiHost string, kubeapiPort int, namespace string, name string, environmentSlice []interface{}, size int) error {
	cluster, err := GetStorage().LoadClusterApplication(name)
	if err != nil {
		log.Error("Load cluster application error %s", err)
		return err
	}

	switch cluster.ScriptType {
	case "none":
		return LaunchClusterApplicationNoScript(kubeapiHost, kubeapiPort, namespace, cluster, environmentSlice, size)
	case "python":
		return LaunchClusterApplicationPython(kubeapiHost, kubeapiPort, namespace, cluster, environmentSlice, size)
	default:
		log.Error("No such script type: %s", cluster.ScriptType)
		return errors.New("No such script type: " + cluster.ScriptType)
	}
}

func LaunchClusterApplicationNoScript(kubeapiHost string, kubeapiPort int, namespace string, cluster *Cluster, environmentSlice []interface{}, size int) error {
	replicationControllerJsonMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(cluster.ReplicationControllerJson), &replicationControllerJsonMap)
	if err != nil {
		log.Error("Unmarshal replication controller json for cluster application error %s", err)
		return err
	}

	serviceJsonMap := make(map[string]interface{})
	err = json.Unmarshal([]byte(cluster.ServiceJson), &serviceJsonMap)
	if err != nil {
		log.Error("Unmarshal service json for cluster application error %s", err)
		return err
	}

	// Add environment variable
	if environmentSlice != nil {
		specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
		if ok {
			templateJsonMap, ok := specJsonMap["template"].(map[string]interface{})
			if ok {
				specJsonMap, ok := templateJsonMap["spec"].(map[string]interface{})
				if ok {
					containerSlice, ok := specJsonMap["containers"].([]interface{})
					if ok {
						for i := 0; i < len(containerSlice); i++ {
							_, ok := containerSlice[i].(map[string]interface{})["env"].([]interface{})
							if ok {
								for _, environment := range environmentSlice {
									containerSlice[i].(map[string]interface{})["env"] = append(containerSlice[i].(map[string]interface{})["env"].([]interface{}), environment)
								}
							} else {
								containerSlice[i].(map[string]interface{})["env"] = environmentSlice
							}
						}
					}
				}
			}
		}
	}

	// Change size
	specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
	if ok {
		specJsonMap["replicas"] = size
	}

	err = control.CreateReplicationControllerWithJson(kubeapiHost, kubeapiPort, namespace, replicationControllerJsonMap)
	if err != nil {
		log.Error("CreateReplicationControllerWithJson error %s", err)
		return err
	}
	err = control.CreateServiceWithJson(kubeapiHost, kubeapiPort, namespace, serviceJsonMap)
	if err != nil {
		log.Error("CreateReplicationControllerWithJson error %s", err)
		return err
	}

	return nil
}

func LaunchClusterApplicationPython(kubeapiHost string, kubeapiPort int, namespace string, cluster *Cluster, environmentSlice []interface{}, size int) error {
	replicationControllerJsonMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(cluster.ReplicationControllerJson), &replicationControllerJsonMap)
	if err != nil {
		log.Error("Unmarshal replication controller json for cluster application error %s", err)
		return err
	}

	// Add environment variable
	if environmentSlice != nil {
		specJsonMap, ok := replicationControllerJsonMap["spec"].(map[string]interface{})
		if ok {
			templateJsonMap, ok := specJsonMap["template"].(map[string]interface{})
			if ok {
				specJsonMap, ok := templateJsonMap["spec"].(map[string]interface{})
				if ok {
					containerSlice, ok := specJsonMap["containers"].([]interface{})
					if ok {
						for i := 0; i < len(containerSlice); i++ {
							_, ok := containerSlice[i].(map[string]interface{})["env"].([]interface{})
							if ok {
								for _, environment := range environmentSlice {
									containerSlice[i].(map[string]interface{})["env"] = append(containerSlice[i].(map[string]interface{})["env"].([]interface{}), environment)
								}
							} else {
								containerSlice[i].(map[string]interface{})["env"] = environmentSlice
							}
						}
					}
				}
			}
		}
	}

	replicationControllerByteSlice, err := json.Marshal(replicationControllerJsonMap)
	if err != nil {
		log.Error("Marshal replication controller json for cluster application error %s", err)
		return err
	}

	environmentByteSlice, err := json.Marshal(environmentSlice)
	if err != nil {
		log.Error("Marshal environment json for cluster application error %s", err)
		return err
	}

	// Generate random work space
	workingDirectory := "/tmp/tmp_" + random.UUID()
	replicationControllerFileName := "replication-controller.json"
	serviceFileName := "service.json"
	scriptFileName := "script"
	environmentFileName := "environment.json"

	// Check working space
	if _, err := os.Stat(workingDirectory); os.IsNotExist(err) {
		err := os.MkdirAll(workingDirectory, os.ModePerm)
		if err != nil {
			log.Error("Create non-existing directory %s error: %s", workingDirectory, err)
			return err
		}
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+environmentFileName, environmentByteSlice, os.ModePerm)
	if err != nil {
		log.Error("Write environment json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+replicationControllerFileName, replicationControllerByteSlice, os.ModePerm)
	if err != nil {
		log.Error("Write replication controller json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+serviceFileName, []byte(cluster.ServiceJson), os.ModePerm)
	if err != nil {
		log.Error("Write service json file for cluster application error %s", err)
		return err
	}

	err = ioutil.WriteFile(workingDirectory+string(os.PathSeparator)+scriptFileName, []byte(cluster.ScriptContent), os.ModePerm)
	if err != nil {
		log.Error("Write script file for cluster application error %s", err)
		return err
	}

	command := exec.Command("python", scriptFileName,
		"--application_name="+cluster.Name,
		"--kubeapi_host_and_port=http://"+kubeapiHost+":"+strconv.Itoa(kubeapiPort),
		"--namespace="+namespace,
		"--size="+strconv.Itoa(size),
		"--service_file_name="+serviceFileName,
		"--replication_controller_file_name="+replicationControllerFileName,
		"--environment_file_name="+environmentFileName,
		"--timeout_in_second=120",
		"--action=create")
	command.Dir = workingDirectory
	out, err := command.CombinedOutput()
	log.Debug(string(out))
	if err != nil {
		log.Error("Run python script file for cluster application error %s", err)
		return errors.New("Error: " + err.Error() + " Output: " + string(out))
	}

	// Remove working space
	err = os.RemoveAll(workingDirectory)
	if err != nil {
		log.Error("Remove the working directory for cluster application error %s", err)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httputil"
	"strconv"
	"strings"

	"golang.org/x/crypto/ssh"
)

type tcpipServer interface {
	serve(readWriter io.ReadWriter, input chan<- string)
}

var servers = map[uint32]tcpipServer{
	25: smtpServer{},
	80: httpServer{},
}

type tcpipChannelData struct {
	Address           string
	Port              uint32
	OriginatorAddress string
	OriginatorPort    uint32
}

func handleDirectTCPIPChannel(newChannel ssh.NewChannel, context channelContext) error {
	channelData := &tcpipChannelData{}
	if err := ssh.Unmarshal(newChannel.ExtraData(), channelData); err != nil {
		return err
	}
	server := servers[channelData.Port]
	if server == nil {
		warningLogger.Printf("Unsupported port %v", channelData.Port)
		return newChannel.Reject(ssh.ConnectionFailed, "Connection refused")
	}
	channel, requests, err := newChannel.Accept()
	if err != nil {
		return err
	}
	context.logEvent(directTCPIPLog{
		channelLog: channelLog{
			ChannelID: context.channelID,
		},
		From: net.JoinHostPort(channelData.OriginatorAddress, strconv.Itoa(int(channelData.OriginatorPort))),
		To:   net.JoinHostPort(channelData.Address, strconv.Itoa(int(channelData.Port))),
	})
	defer context.logEvent(directTCPIPCloseLog{
		channelLog: channelLog{
			ChannelID: context.channelID,
		},
	})

	inputChan := make(chan string)
	go func() {
		defer close(inputChan)
		server.serve(channel, inputChan)
		if err := channel.CloseWrite(); err != nil {
			warningLogger.Printf("Error sending EOF to channel: %v", err)
			return
		}
		if err := channel.Close(); err != nil {
			warningLogger.Printf("Error closing channel: %v", err)
			return
		}
	}()

	for inputChan != nil || requests != nil {
		select {
		case input, ok := <-inputChan:
			if !ok {
				inputChan = nil
				continue
			}
			context.logEvent(directTCPIPInputLog{
				channelLog: channelLog{
					ChannelID: context.channelID,
				},
				Input: input,
			})
		case request, ok := <-requests:
			if !ok {
				requests = nil
				continue
			}
			warningLogger.Printf("Unsupported direct-tcpip request type %v", request.Type)
			if request.WantReply {
				if err := request.Reply(false, nil); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

type httpServer struct{}

func (server httpServer) serve(readWriter io.ReadWriter, input chan<- string) {
	for {
		request, err := http.ReadRequest(bufio.NewReader(readWriter))
		if err != nil {
			if err != io.EOF {
				warningLogger.Printf("Error reading request: %v", err)
			}
			return
		}
		requestBytes, err := httputil.DumpRequest(request, true)
		if err != nil {
			warningLogger.Printf("Error dumping request: %v", err)
			return
		}
		input <- string(requestBytes)
		response := &http.Response{
			StatusCode: 404,
			ProtoMajor: 1,
			ProtoMinor: 1,
		}
		responseBytes, err := httputil.DumpResponse(response, true)
		if err != nil {
			warningLogger.Printf("Error dumping response: %v", err)
			return
		}
		_, err = readWriter.Write(responseBytes)
		if err != nil {
			warningLogger.Printf("Error writing response: %v", err)
			return
		}
	}
}

type smtpServer struct{}

type smtpReply struct {
	code    int
	message string
}

func (smtpServer) writeReply(writer io.Writer, reply smtpReply) error {
	lines := strings.Split(reply.message, "\n")
	for i, line := range lines {
		var err error
		if i == len(lines)-1 {
			_, err = fmt.Fprintf(writer, "%d %s\r\n", reply.code, line)
		} else {
			_, err = fmt.Fprintf(writer, "%d-%s\r\n", reply.code, line)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

type smtpCommand struct {
	command string
	params  []string
}

func (command smtpCommand) String() string {
	if len(command.params) == 0 {
		return command.command
	}
	return fmt.Sprintf("%s %s", command.command, strings.Join(command.params, " "))
}

func (smtpServer) readCommand(reader io.Reader) (smtpCommand, error) {
	line, err := bufio.NewReader(reader).ReadString('\n')
	if err != nil {
		return smtpCommand{}, err
	}
	fields := strings.Fields(line)
	if len(fields) == 0 {
		return smtpCommand{}, fmt.Errorf("empty command")
	}
	command := strings.ToUpper(fields[0])
	params := fields[1:]
	return smtpCommand{command, params}, nil
}

func (smtpServer) readData(reader io.Reader) (string, error) {
	bufioReader := bufio.NewReader(reader)
	data := bytes.Buffer{}
	crlf := false
	for {
		line, err := bufioReader.ReadString('\n')
		if err != nil {
			return "", err
		}
		data.WriteString(line)
		if crlf && line == ".\r\n" {
			return data.String(), nil
		}
		crlf = strings.HasSuffix(line, "\r\n")
	}
}

func (server smtpServer) serve(readWriter io.ReadWriter, input chan<- string) {
	reply := smtpReply{
		code:    220,
		message: "localhost",
	}
	reader := bufio.NewReader(readWriter)
	var previousCommand string
	for {
		if err := server.writeReply(readWriter, reply); err != nil {
			warningLogger.Printf("Error writing reply: %v", err)
			return
		}
		if previousCommand == "QUIT" {
			return
		}
		if previousCommand == "DATA" {
			data, err := server.readData(readWriter)
			if err != nil {
				warningLogger.Printf("Error reading data: %v", err)
				return
			}
			input <- data
			reply = smtpReply{
				code:    250,
				message: "OK",
			}
			previousCommand = ""
			continue
		}
		command, err := server.readCommand(reader)
		if err != nil {
			warningLogger.Printf("Error reading command: %v", err)
			return
		}
		input <- command.String()
		previousCommand = command.command
		switch command.command {
		case "DATA":
			reply = smtpReply{
				code:    354,
				message: "Start mail input; end with <CRLF>.<CRLF>",
			}
		case "QUIT":
			reply = smtpReply{
				code:    221,
				message: "Bye",
			}
		default:
			reply = smtpReply{
				code:    250,
				message: "OK",
			}
		}
	}
}
<commit_msg>Record metrics about direct-tcpip channels<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httputil"
	"strconv"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/crypto/ssh"
)

type tcpipServer interface {
	serve(readWriter io.ReadWriter, input chan<- string)
	name() string
}

var servers = map[uint32]tcpipServer{
	25: smtpServer{},
	80: httpServer{},
}

type tcpipChannelData struct {
	Address           string
	Port              uint32
	OriginatorAddress string
	OriginatorPort    uint32
}

var (
	tcpipChannelsMetric = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "tcpip_channels_total",
		Help: "Total number of TCP/IP channels",
	}, []string{"service"})
	activeTCPIPChannelsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "active_tcpip_channels",
		Help: "Number of active TCP/IP channels",
	}, []string{"service"})
	tcpipChannelRequestsMetric = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "tcpip_channel_requests_total",
		Help: "Total number of TCP/IP channel requests",
	}, []string{"service"})
)

func handleDirectTCPIPChannel(newChannel ssh.NewChannel, context channelContext) error {
	channelData := &tcpipChannelData{}
	if err := ssh.Unmarshal(newChannel.ExtraData(), channelData); err != nil {
		return err
	}
	server := servers[channelData.Port]
	if server == nil {
		warningLogger.Printf("Unsupported port %v", channelData.Port)
		return newChannel.Reject(ssh.ConnectionFailed, "Connection refused")
	}
	channel, requests, err := newChannel.Accept()
	if err != nil {
		return err
	}
	tcpipChannelsMetric.WithLabelValues(server.name()).Inc()
	activeTCPIPChannelsMetric.WithLabelValues(server.name()).Inc()
	defer activeTCPIPChannelsMetric.WithLabelValues(server.name()).Dec()
	context.logEvent(directTCPIPLog{
		channelLog: channelLog{
			ChannelID: context.channelID,
		},
		From: net.JoinHostPort(channelData.OriginatorAddress, strconv.Itoa(int(channelData.OriginatorPort))),
		To:   net.JoinHostPort(channelData.Address, strconv.Itoa(int(channelData.Port))),
	})
	defer context.logEvent(directTCPIPCloseLog{
		channelLog: channelLog{
			ChannelID: context.channelID,
		},
	})

	inputChan := make(chan string)
	go func() {
		defer close(inputChan)
		server.serve(channel, inputChan)
		if err := channel.CloseWrite(); err != nil {
			warningLogger.Printf("Error sending EOF to channel: %v", err)
			return
		}
		if err := channel.Close(); err != nil {
			warningLogger.Printf("Error closing channel: %v", err)
			return
		}
	}()

	for inputChan != nil || requests != nil {
		select {
		case input, ok := <-inputChan:
			if !ok {
				inputChan = nil
				continue
			}
			context.logEvent(directTCPIPInputLog{
				channelLog: channelLog{
					ChannelID: context.channelID,
				},
				Input: input,
			})
		case request, ok := <-requests:
			if !ok {
				requests = nil
				continue
			}
			tcpipChannelRequestsMetric.WithLabelValues("unknown").Inc()
			warningLogger.Printf("Unsupported direct-tcpip request type %v", request.Type)
			if request.WantReply {
				if err := request.Reply(false, nil); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

type httpServer struct{}

func (server httpServer) serve(readWriter io.ReadWriter, input chan<- string) {
	for {
		request, err := http.ReadRequest(bufio.NewReader(readWriter))
		if err != nil {
			if err != io.EOF {
				warningLogger.Printf("Error reading request: %v", err)
			}
			return
		}
		requestBytes, err := httputil.DumpRequest(request, true)
		if err != nil {
			warningLogger.Printf("Error dumping request: %v", err)
			return
		}
		input <- string(requestBytes)
		response := &http.Response{
			StatusCode: 404,
			ProtoMajor: 1,
			ProtoMinor: 1,
		}
		responseBytes, err := httputil.DumpResponse(response, true)
		if err != nil {
			warningLogger.Printf("Error dumping response: %v", err)
			return
		}
		_, err = readWriter.Write(responseBytes)
		if err != nil {
			warningLogger.Printf("Error writing response: %v", err)
			return
		}
	}
}

func (httpServer) name() string {
	return "HTTP"
}

type smtpServer struct{}

type smtpReply struct {
	code    int
	message string
}

func (smtpServer) writeReply(writer io.Writer, reply smtpReply) error {
	lines := strings.Split(reply.message, "\n")
	for i, line := range lines {
		var err error
		if i == len(lines)-1 {
			_, err = fmt.Fprintf(writer, "%d %s\r\n", reply.code, line)
		} else {
			_, err = fmt.Fprintf(writer, "%d-%s\r\n", reply.code, line)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

type smtpCommand struct {
	command string
	params  []string
}

func (command smtpCommand) String() string {
	if len(command.params) == 0 {
		return command.command
	}
	return fmt.Sprintf("%s %s", command.command, strings.Join(command.params, " "))
}

func (smtpServer) readCommand(reader io.Reader) (smtpCommand, error) {
	line, err := bufio.NewReader(reader).ReadString('\n')
	if err != nil {
		return smtpCommand{}, err
	}
	fields := strings.Fields(line)
	if len(fields) == 0 {
		return smtpCommand{}, fmt.Errorf("empty command")
	}
	command := strings.ToUpper(fields[0])
	params := fields[1:]
	return smtpCommand{command, params}, nil
}

func (smtpServer) readData(reader io.Reader) (string, error) {
	bufioReader := bufio.NewReader(reader)
	data := bytes.Buffer{}
	crlf := false
	for {
		line, err := bufioReader.ReadString('\n')
		if err != nil {
			return "", err
		}
		data.WriteString(line)
		if crlf && line == ".\r\n" {
			return data.String(), nil
		}
		crlf = strings.HasSuffix(line, "\r\n")
	}
}

func (server smtpServer) serve(readWriter io.ReadWriter, input chan<- string) {
	reply := smtpReply{
		code:    220,
		message: "localhost",
	}
	reader := bufio.NewReader(readWriter)
	var previousCommand string
	for {
		if err := server.writeReply(readWriter, reply); err != nil {
			warningLogger.Printf("Error writing reply: %v", err)
			return
		}
		if previousCommand == "QUIT" {
			return
		}
		if previousCommand == "DATA" {
			data, err := server.readData(readWriter)
			if err != nil {
				warningLogger.Printf("Error reading data: %v", err)
				return
			}
			input <- data
			reply = smtpReply{
				code:    250,
				message: "OK",
			}
			previousCommand = ""
			continue
		}
		command, err := server.readCommand(reader)
		if err != nil {
			warningLogger.Printf("Error reading command: %v", err)
			return
		}
		input <- command.String()
		previousCommand = command.command
		switch command.command {
		case "DATA":
			reply = smtpReply{
				code:    354,
				message: "Start mail input; end with <CRLF>.<CRLF>",
			}
		case "QUIT":
			reply = smtpReply{
				code:    221,
				message: "Bye",
			}
		default:
			reply = smtpReply{
				code:    250,
				message: "OK",
			}
		}
	}
}

func (smtpServer) name() string {
	return "SMTP"
}
<|endoftext|>


<commit_before>package tally

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/textproto"
	"os"
	"os/signal"
	"reflect"
	"regexp"
	"strings"
)

// The Action struct represents a possible reaction to a given line.
// Regexps are attached to the Action so that they can be compiled once
// when the bot is initialized instead of each time a line needs to be parsed.

type Action struct {
	re    *regexp.Regexp
	Parse func(*regexp.Regexp, string) interface{}
	Run   func(*Bot, interface{})
}

type Bot struct {
	Server   string
	Port     string
	Nick     string
	Channel  string
	Trac_URL string
	Ignore   []string
	conn     net.Conn

	actions []*Action
}

// Returns a new bot that has been configured according to
// config.json

func NewBot() *Bot {
	bot := new(Bot)
	f, err := ioutil.ReadFile("./config.json")
	if err != nil {
		log.Fatal("Error loading config.json: %v\n\n", err)
	}
	err = json.Unmarshal(f, bot)
	if err != nil {
		log.Fatal("Error unmarshalling config.json: %v\n\n", err)
	}
	return bot
}

// Establishes a connection to the server and joins a channel

func (bot *Bot) Connect() {
	dest := bot.Server + ":" + bot.Port
	conn, err := net.Dial("tcp", dest)
	if err != nil {
		log.Fatalf("Unable to connect to %s\nError: %v\n\n", dest, err)
	}
	log.Printf("Successfully connected to %s\n", dest)
	bot.conn = conn
	bot.Send("USER " + bot.Nick + " 8 * :" + bot.Nick + "\n")
	bot.Send("NICK " + bot.Nick + "\n")
	bot.Send("JOIN " + bot.Channel + "\n")
}

// Sends a string to the server. Strings should end with a
// newline character.

func (bot *Bot) Send(str string) {
	msg := []byte(str)
	_, err := bot.conn.Write(msg)
	if err != nil {
		log.Printf("Error sending: %s", msg)
		log.Printf("Error: %v", err)
	} else {
		log.Printf("Successfully sent: %s", msg)
	}
}

// Sends a message to the channel

func (bot *Bot) MsgChannel(line string) {
	bot.Send("PRIVMSG " + bot.Channel + " :" + line + "\n")
}

func (bot *Bot) parse(line string) {
	for i := range bot.Ignore {
		if strings.Contains(line, bot.Ignore[i]) {
			return
		}
	}
	for i := range bot.actions {
		action := bot.actions[i]
		resp := action.Parse(action.re, line)
		if resp != nil {
			go action.Run(bot, resp)
		}
	}
}

func (bot *Bot) AddAction(re string, parse func(*regexp.Regexp, string) interface{},
	run func(*Bot, interface{})) {
	action := new(Action)
	action.re = regexp.MustCompile(re)
	action.Parse = parse
	action.Run = run
	bot.actions = append(bot.actions, action)
}

func signalHandling(bot *Bot) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for sig := range c {
		if sig == os.Interrupt {
			log.Printf("Bot received os.Interrupt, exiting normally.\n\n")
			bot.Send("QUIT :\n")
			bot.conn.Close()
			os.Exit(0)
		}
	}
}

func (bot *Bot) Run() {
	go signalHandling(bot)
	bot.SetActions()
	reader := bufio.NewReader(bot.conn)
	tp := textproto.NewReader(reader)
	for {
		line, error := tp.ReadLine()
		if error != nil {
			log.Printf("Error reading line: %s\n", line)
		} else {
			bot.parse(line)
		}
	}
}

func ParseTicket(re *regexp.Regexp, line string) interface{} {
	//Regex: #(\d+)([:alpha:])*
	matches := re.FindAllStringSubmatch(line, 10)
	var ticket_nums []string
	for i := range matches {
		if matches[i][2] == "" {
			ticket_nums = append(ticket_nums, matches[i][1])
		}
	}
	if len(ticket_nums) == 0 {
		return nil
	}
	return ticket_nums
}

func FetchTickets(bot *Bot, tickets interface{}) {
	url := bot.Trac_URL + "ticket/"
	used := make(map[string]bool)
	ticket_nums := reflect.ValueOf(tickets)
	for i := 0; i < ticket_nums.Len(); i++ {
		num := ticket_nums.Index(i).String()
		if used[num] {
			continue
		} else {
			used[num] = true
		}
		dest := url + num
		resp, err := http.Get(dest)
		if err != nil {
			fmt.Printf("%v\n", err)
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Printf("%v\n", err)
		}
		s := string(body)
		if strings.Contains(s, "
Error:") {

		} else {
			s = s[:300]
			a := strings.Split(s, "\n")
			title := strings.TrimLeft(a[7], " ")
			bot.MsgChannel(title)
			bot.MsgChannel(dest)
		}
	}
}

func ParsePing(re *regexp.Regexp, line string) interface{} {
	//Regex: ^PING
	str := re.FindString(line)
	if str == "" {
		return nil
	}
	return line
}

func SendPong(bot *Bot, str interface{}) {
	line := reflect.ValueOf(str).String()
	log.Printf("Received: %s\n", line)
	strs := strings.Split(line, " ")
	bot.Send("PONG " + strs[1] + "\n")
}

func (bot *Bot) SetActions() {
	if bot.Trac_URL != "" {
		bot.AddAction(`#(\d+)([:alpha:])*`, ParseTicket, FetchTickets)
	}
	bot.AddAction(`^PING`, ParsePing, SendPong)
}

func InitLogging() {
	logf, err := os.OpenFile("bot_log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0667)
	if err != nil {
		log.Fatal("Cannot open/create log file.\nError: %v\n\n", err)
	}
	log.SetOutput(logf)
}
<commit_msg>Adds TimelineUpdater to bot.Run()<commit_after>package tally

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/textproto"
	"os"
	"os/signal"
	"reflect"
	"regexp"
	"strings"
	"time"
)

// The Action struct represents a possible reaction to a given line.
// Regexps are attached to the Action so that they can be compiled once
// when the bot is initialized instead of each time a line needs to be parsed.

type Action struct {
	re    *regexp.Regexp
	Parse func(*regexp.Regexp, string) interface{}
	Run   func(*Bot, interface{})
}

type Bot struct {
	Server   string
	Port     string
	Nick     string
	Channel  string
	Trac_URL string
	Trac_RSS string
	Interval time.Duration
	Ignore   []string
	conn     net.Conn

	actions []*Action
}

// Returns a new bot that has been configured according to
// config.json

func NewBot() *Bot {
	bot := new(Bot)
	f, err := ioutil.ReadFile("./config.json")
	if err != nil {
		log.Fatal("Error loading config.json: %v\n\n", err)
	}
	err = json.Unmarshal(f, bot)
	if err != nil {
		log.Fatal("Error unmarshalling config.json: %v\n\n", err)
	}
	return bot
}

// Establishes a connection to the server and joins a channel

func (bot *Bot) Connect() {
	dest := bot.Server + ":" + bot.Port
	conn, err := net.Dial("tcp", dest)
	if err != nil {
		log.Fatalf("Unable to connect to %s\nError: %v\n\n", dest, err)
	}
	log.Printf("Successfully connected to %s\n", dest)
	bot.conn = conn
	bot.Send("USER " + bot.Nick + " 8 * :" + bot.Nick + "\n")
	bot.Send("NICK " + bot.Nick + "\n")
	bot.Send("JOIN " + bot.Channel + "\n")
}

// Sends a string to the server. Strings should end with a
// newline character.

func (bot *Bot) Send(str string) {
	msg := []byte(str)
	_, err := bot.conn.Write(msg)
	if err != nil {
		log.Printf("Error sending: %s", msg)
		log.Printf("Error: %v", err)
	} else {
		log.Printf("Successfully sent: %s", msg)
	}
}

// Sends a message to the channel

func (bot *Bot) MsgChannel(line string) {
	bot.Send("PRIVMSG " + bot.Channel + " :" + line + "\n")
}

func (bot *Bot) parse(line string) {
	for i := range bot.Ignore {
		if strings.Contains(line, bot.Ignore[i]) {
			return
		}
	}
	for i := range bot.actions {
		action := bot.actions[i]
		resp := action.Parse(action.re, line)
		if resp != nil {
			go action.Run(bot, resp)
		}
	}
}

func (bot *Bot) AddAction(re string, parse func(*regexp.Regexp, string) interface{},
	run func(*Bot, interface{})) {
	action := new(Action)
	action.re = regexp.MustCompile(re)
	action.Parse = parse
	action.Run = run
	bot.actions = append(bot.actions, action)
}

func signalHandling(bot *Bot) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for sig := range c {
		if sig == os.Interrupt {
			log.Printf("Bot received os.Interrupt, exiting normally.\n\n")
			bot.Send("QUIT :\n")
			bot.conn.Close()
			os.Exit(0)
		}
	}
}

func (bot *Bot) Run() {
	go signalHandling(bot)
	bot.SetActions()
	t := bot.NewTimelineUpdater(bot.Trac_RSS, bot.Interval)
	go t.Run()
	reader := bufio.NewReader(bot.conn)
	tp := textproto.NewReader(reader)
	for {
		line, error := tp.ReadLine()
		if error != nil {
			log.Printf("Error reading line: %s\n", line)
		} else {
			bot.parse(line)
		}
	}
}

func ParseTicket(re *regexp.Regexp, line string) interface{} {
	//Regex: #(\d+)([:alpha:])*
	matches := re.FindAllStringSubmatch(line, 10)
	var ticket_nums []string
	for i := range matches {
		if matches[i][2] == "" {
			ticket_nums = append(ticket_nums, matches[i][1])
		}
	}
	if len(ticket_nums) == 0 {
		return nil
	}
	return ticket_nums
}

func FetchTickets(bot *Bot, tickets interface{}) {
	url := bot.Trac_URL + "ticket/"
	used := make(map[string]bool)
	ticket_nums := reflect.ValueOf(tickets)
	for i := 0; i < ticket_nums.Len(); i++ {
		num := ticket_nums.Index(i).String()
		if used[num] {
			continue
		} else {
			used[num] = true
		}
		dest := url + num
		resp, err := http.Get(dest)
		if err != nil {
			fmt.Printf("%v\n", err)
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Printf("%v\n", err)
		}
		s := string(body)
		if strings.Contains(s, "
Error:") {

		} else {
			s = s[:300]
			a := strings.Split(s, "\n")
			title := strings.TrimLeft(a[7], " ")
			bot.MsgChannel(title)
			bot.MsgChannel(dest)
		}
	}
}

func ParsePing(re *regexp.Regexp, line string) interface{} {
	//Regex: ^PING
	str := re.FindString(line)
	if str == "" {
		return nil
	}
	return line
}

func SendPong(bot *Bot, str interface{}) {
	line := reflect.ValueOf(str).String()
	log.Printf("Received: %s\n", line)
	strs := strings.Split(line, " ")
	bot.Send("PONG " + strs[1] + "\n")
}

func (bot *Bot) SetActions() {
	if bot.Trac_URL != "" {
		bot.AddAction(`#(\d+)([:alpha:])*`, ParseTicket, FetchTickets)
	}
	bot.AddAction(`^PING`, ParsePing, SendPong)
}

func InitLogging() {
	logf, err := os.OpenFile("bot_log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0667)
	if err != nil {
		log.Fatal("Cannot open/create log file.\nError: %v\n\n", err)
	}
	log.SetOutput(logf)
}
<|endoftext|>