<commit_before>package themes

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nlopes/slack"
	"github.com/tuna-timer/tuna-timer-api/models"
	"github.com/tuna-timer/tuna-timer-api/utils"
	"time"
)

// DefaultSlackMessageTheme - todo
type DefaultSlackMessageTheme struct {
	themeConfig
	ctx context.Context
}

var defaultThemeConfig = themeConfig{
	MarkdownEnabledFor:     []string{"text", "pretext"},
	SummaryAttachmentColor: "#000000",
	FooterIcon:             "http://icons.iconarchive.com/icons/martin-berube/flat-animal/48/tuna-icon.png",

	StartCommandThumbURL: "/assets/themes/default/ic_current.png",
	StartCommandColor:    "F5A623",

	StopCommandThumbURL: "/assets/themes/default/ic_completed.png",
	StopCommandColor:    "#4A90E2",

	StatusCommandThumbURL: "/assets/themes/default/ic_status.png",
	StatusCommandColor:    "#9B9B9B",
}

func NewDefaultSlackMessageTheme(ctx context.Context) *DefaultSlackMessageTheme {
	return &DefaultSlackMessageTheme{
		themeConfig: defaultThemeConfig,
		ctx:         ctx,
	}
}

func (t *DefaultSlackMessageTheme) FormatStatusCommand(data *models.StatusCommandReport) string {

	tpl := slackThemeTemplate{
		Text:        fmt.Sprintf("Your status for %s", data.PeriodName),
		Attachments: []slack.Attachment{},
	}

	summaryAttachmentVisible := len(data.Tasks) > 0 || data.AlreadyStartedTimer != nil

	if len(data.Tasks) > 0 {
		statusAttachment := t.defaultAttachment()
		statusAttachment.ThumbURL = t.asset(t.StopCommandThumbURL)
		statusAttachment.Color = t.StopCommandColor

		statusAttachment.Footer = "<http://www.foo.com|Open in Application>"
		//statusAttachment.FooterIcon = t.FooterIcon
		var buffer bytes.Buffer
		for _, task := range data.Tasks {

			if data.AlreadyStartedTimer == nil || data.AlreadyStartedTimer.TaskName != task.Name {
				buffer.WriteString(fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(task.Minutes) * int64(time.Minute))), task.Name))
			}
		}
		statusAttachment.AuthorName = "Completed:"
		statusAttachment.Text = buffer.String()
		tpl.Attachments = append(tpl.Attachments, statusAttachment)
	}

	if data.AlreadyStartedTimer != nil {
		sa := t.attachmentForCurrentTask(data.AlreadyStartedTimer, data.AlreadyStartedTimerTotalForToday)

		//sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(data.AlreadyStartedTimerTotalForToday)*int64(time.Minute))), data.AlreadyStartedTimer.TaskName)
		//sa.AuthorName = "Current:"

		//sa := t.attachmentForTimer(
		//	fmt.Sprintf("%s", data.AlreadyStartedTimer.TaskName),
		//	t.asset(t.StartCommandThumbURL),
		//	data.AlreadyStartedTimer,
		//	data.AlreadyStartedTimerTotalForToday)

		//sa.Color = t.StartCommandColor
		//sa.AuthorName = "Current:"

		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if summaryAttachmentVisible {
		tpl.Attachments = append(tpl.Attachments, t.summaryAttachment(data.PeriodName, data.UserTotalForPeriod))
	} else {
		tpl.Text = fmt.Sprintf("You have no tasks completed %s", data.PeriodName)
	}

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

func (t *DefaultSlackMessageTheme) FormatStopCommand(data *models.StopCommandReport) string {
	tpl := slackThemeTemplate{
		Text:        "Timer has been updated",
		Attachments: []slack.Attachment{},
	}

	if data.StoppedTimer != nil {
		sa := t.attachmentForStoppedTask(data.StoppedTimer, data.StoppedTaskTotalForToday)
			//t.attachmentForTimer(
			//fmt.Sprintf("Completed: %s", data.StoppedTimer.TaskName),
			//t.asset(t.StopCommandThumbURL),
			//data.StoppedTimer,
			//data.StoppedTaskTotalForToday)
		//
		//sa.Color = t.StopCommandColor

		tpl.Attachments = append(tpl.Attachments, sa)
	}

	tpl.Attachments = append(tpl.Attachments, t.summaryAttachment("today", data.UserTotalForToday))

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

func (t *DefaultSlackMessageTheme) FormatStartCommand(data *models.StartCommandReport) string {
	tpl := slackThemeTemplate{
		Text:        "Timer has been updated",
		Attachments: []slack.Attachment{},
	}

	if data.StoppedTimer != nil {
		sa := t.attachmentForStoppedTask(data.StoppedTimer, data.StoppedTaskTotalForToday)

		//
		//sa := t.attachmentForTimer(
		//	fmt.Sprintf("Completed: %s", data.StoppedTimer.TaskName),
		//	t.asset(t.StopCommandThumbURL),
		//	data.StoppedTimer,
		//	data.StoppedTaskTotalForToday)
		//
		//sa.Color = t.StopCommandColor

		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if data.StartedTimer != nil {
		sa := t.attachmentForNewTask(data.StartedTimer, data.StartedTaskTotalForToday)
			//t.attachmentForTimer(
			//fmt.Sprintf("Started: %s", data.StartedTimer.TaskName),
			//t.asset(t.StartCommandThumbURL),
			//data.StartedTimer,
			//data.StartedTaskTotalForToday)

		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if data.AlreadyStartedTimer != nil {
		sa := t.attachmentForNewTask(data.AlreadyStartedTimer, data.AlreadyStartedTimerTotalForToday)
			//t.attachmentForTimer(
			//fmt.Sprintf("Current: %s", data.AlreadyStartedTimer.TaskName),
			//t.asset(t.StartCommandThumbURL),
			//data.AlreadyStartedTimer,
			//data.AlreadyStartedTimerTotalForToday)
		//
		//sa.Color = t.StartCommandColor

		tpl.Attachments = append(tpl.Attachments, sa)
	}

	tpl.Attachments = append(tpl.Attachments, t.summaryAttachment("today", data.UserTotalForToday))

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

//func (t *DefaultSlackMessageTheme) attachmentForTimer(text string, thumbURL string, timer *models.Timer, totalForToday int) slack.Attachment {
//	sa := t.defaultAttachment()
//	sa.Text = text
//	sa.ThumbURL = thumbURL
//
//	sa.Footer = fmt.Sprintf(
//		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)
//
//	sa.Fields = []slack.AttachmentField{}
//
//	thisRoundField := slack.AttachmentField{
//		Title: "This Round",
//		Value: utils.FormatDuration(time.Duration(int64(timer.Minutes) * int64(time.Minute))),
//		Short: true,
//	}
//
//	todayField := slack.AttachmentField{
//		Title: "Today",
//		Value: utils.FormatDuration(time.Duration(int64(totalForToday) * int64(time.Minute))),
//		Short: true,
//	}
//
//	sa.Fields = append(sa.Fields, thisRoundField, todayField)
//	return sa
//} // StartedTaskTotalForToday

func (t *DefaultSlackMessageTheme) attachmentForNewTask(timer *models.Timer, taskTotalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(taskTotalForToday)*int64(time.Minute))), timer.TaskName)
	//sa.Text = fmt.Sprintf("Started: %s\n\n", timer.TaskName)
	sa.ThumbURL = t.asset(t.StartCommandThumbURL)
	sa.Color = t.StartCommandColor
	sa.AuthorName = "Started:"

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Edit in Application>", timer.TaskHash)

	//sa.Fields = []slack.AttachmentField{}
	//
	//thisRoundField := slack.AttachmentField{
	//	Title: "This Round",
	//	Value: utils.FormatDuration(time.Duration(int64(timer.Minutes) * int64(time.Minute))),
	//	Short: true,
	//}
	//
	//todayField := slack.AttachmentField{
	//	Title: "Today",
	//	Value: utils.FormatDuration(time.Duration(int64(totalForToday) * int64(time.Minute))),
	//	Short: true,
	//}
	//sa.Fields = append(sa.Fields, thisRoundField, todayField)
	return sa
}

func (t *DefaultSlackMessageTheme) attachmentForCurrentTask(timer *models.Timer, totalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(totalForToday)*int64(time.Minute))), timer.TaskName)
	sa.ThumbURL = t.asset(t.StartCommandThumbURL)
	sa.Color = t.StartCommandColor
	sa.AuthorName = "Current:"

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)

	sa.Fields = []slack.AttachmentField{}
	//
	//thisRoundField := slack.AttachmentField{
	//	Title: "This Round",
	//	Value: utils.FormatDuration(time.Duration(int64(timer.Minutes) * int64(time.Minute))),
	//	Short: true,
	//}

	//todayField := slack.AttachmentField{
	//	Title: "Total for today",
	//	Value: utils.FormatDuration(time.Duration(int64(totalForToday) * int64(time.Minute))),
	//	Short: false,
	//}
	//sa.Fields = append(sa.Fields, todayField)
	return sa
}

func (t *DefaultSlackMessageTheme) attachmentForRestartedTask(timer *models.Timer, totalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.Text = fmt.Sprintf("Resumed: %s", timer.TaskName)
	sa.ThumbURL = t.asset(t.StartCommandThumbURL)
	sa.Color = t.StartCommandColor

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)

	sa.Fields = []slack.AttachmentField{}
	//
	//thisRoundField := slack.AttachmentField{
	//	Title: "This Round",
	//	Value: utils.FormatDuration(time.Duration(int64(timer.Minutes) * int64(time.Minute))),
	//	Short: true,
	//}

	//todayField := slack.AttachmentField{
	//	Title: "Total for today",
	//	Value: utils.FormatDuration(time.Duration(int64(totalForToday) * int64(time.Minute))),
	//	Short: false,
	//}
	//sa.Fields = append(sa.Fields, todayField)
	return sa
}

func (t *DefaultSlackMessageTheme) attachmentForStoppedTask(timer *models.Timer, totalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.AuthorName = "Completed:"

	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(totalForToday)*int64(time.Minute))), timer.TaskName)
	sa.ThumbURL = t.asset(t.StopCommandThumbURL)
	sa.Color = t.StopCommandColor

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)

	sa.Fields = []slack.AttachmentField{}

	//totalField := slack.AttachmentField{
	//	Title: "Spent",
	//	Value: utils.FormatDuration(time.Duration(int64(timer.Minutes) * int64(time.Minute))),
	//	Short: true,
	//}
	//
	//todayField := slack.AttachmentField{
	//	Title: "Total for Today",
	//	Value: utils.FormatDuration(time.Duration(int64(totalForToday) * int64(time.Minute))),
	//	Short: true,
	//}
	//sa.Fields = append(sa.Fields, totalField)
	//
	//if timer.Minutes != totalForToday {
	//	sa.Fields = append(sa.Fields, todayField)
	//}
	return sa
}

func (t *DefaultSlackMessageTheme) summaryAttachment(period string, minutes int) slack.Attachment {
	result := slack.Attachment{}
	result.Text = fmt.Sprintf("*Your total for %s is %s*",
		period,
		utils.FormatDuration(time.Duration(int64(minutes)*int64(time.Minute))))

	result.Color = t.SummaryAttachmentColor
	result.MarkdownIn = t.MarkdownEnabledFor
	return result
}

func (t *DefaultSlackMessageTheme) defaultAttachment() slack.Attachment {
	result := slack.Attachment{}
	result.MarkdownIn = t.MarkdownEnabledFor
	//result.FooterIcon = t.FooterIcon
	return result
}

func (t *DefaultSlackMessageTheme) asset(assetPath string) string {
	return utils.GetSelfBaseURLFromContext(t.ctx) + assetPath
}
<commit_msg>cleans the code out<commit_after>package themes

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nlopes/slack"
	"github.com/tuna-timer/tuna-timer-api/models"
	"github.com/tuna-timer/tuna-timer-api/utils"
	"time"
)

// DefaultSlackMessageTheme - the basic UI theme for messages that go back from us to Slack users
type DefaultSlackMessageTheme struct {
	themeConfig
	ctx context.Context
}

var defaultThemeConfig = themeConfig{
	MarkdownEnabledFor:     []string{"text", "pretext"},
	SummaryAttachmentColor: "#000000",
	FooterIcon:             "http://icons.iconarchive.com/icons/martin-berube/flat-animal/48/tuna-icon.png",
	StartCommandThumbURL:   "/assets/themes/default/ic_current.png",
	StartCommandColor:      "F5A623",
	StopCommandThumbURL:    "/assets/themes/default/ic_completed.png",
	StopCommandColor:       "#4A90E2",
	StatusCommandThumbURL:  "/assets/themes/default/ic_status.png",
	StatusCommandColor:     "#9B9B9B",
}

func NewDefaultSlackMessageTheme(ctx context.Context) *DefaultSlackMessageTheme {
	return &DefaultSlackMessageTheme{
		themeConfig: defaultThemeConfig,
		ctx:         ctx,
	}
}

func (t *DefaultSlackMessageTheme) FormatStatusCommand(data *models.StatusCommandReport) string {

	tpl := slackThemeTemplate{
		Text:        fmt.Sprintf("Your status for %s", data.PeriodName),
		Attachments: []slack.Attachment{},
	}

	summaryAttachmentVisible := len(data.Tasks) > 0 || data.AlreadyStartedTimer != nil

	if len(data.Tasks) > 0 {
		statusAttachment := t.defaultAttachment()
		statusAttachment.ThumbURL = t.asset(t.StopCommandThumbURL)
		statusAttachment.Color = t.StopCommandColor

		statusAttachment.Footer = "<http://www.foo.com|Open in Application>"
		var buffer bytes.Buffer
		for _, task := range data.Tasks {
			if data.AlreadyStartedTimer == nil || data.AlreadyStartedTimer.TaskName != task.Name {
				buffer.WriteString(fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(task.Minutes)*int64(time.Minute))), task.Name))
			}
		}
		statusAttachment.AuthorName = "Completed:"
		statusAttachment.Text = buffer.String()
		tpl.Attachments = append(tpl.Attachments, statusAttachment)
	}

	if data.AlreadyStartedTimer != nil {
		sa := t.attachmentForCurrentTask(data.AlreadyStartedTimer, data.AlreadyStartedTimerTotalForToday)
		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if summaryAttachmentVisible {
		tpl.Attachments = append(tpl.Attachments, t.summaryAttachment(data.PeriodName, data.UserTotalForPeriod))
	} else {
		tpl.Text = fmt.Sprintf("You have no tasks completed %s", data.PeriodName)
	}

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

func (t *DefaultSlackMessageTheme) FormatStopCommand(data *models.StopCommandReport) string {
	tpl := slackThemeTemplate{
		Attachments: []slack.Attachment{},
	}

	if data.StoppedTimer != nil {
		sa := t.attachmentForStoppedTask(data.StoppedTimer, data.StoppedTaskTotalForToday)
		tpl.Attachments = append(tpl.Attachments, sa)
	}

	tpl.Attachments = append(tpl.Attachments, t.summaryAttachment("today", data.UserTotalForToday))

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

func (t *DefaultSlackMessageTheme) FormatStartCommand(data *models.StartCommandReport) string {
	tpl := slackThemeTemplate{
		Attachments: []slack.Attachment{},
	}

	if data.StoppedTimer != nil {
		sa := t.attachmentForStoppedTask(data.StoppedTimer, data.StoppedTaskTotalForToday)
		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if data.StartedTimer != nil {
		sa := t.attachmentForNewTask(data.StartedTimer, data.StartedTaskTotalForToday)
		tpl.Attachments = append(tpl.Attachments, sa)
	}

	if data.AlreadyStartedTimer != nil {
		sa := t.attachmentForNewTask(data.AlreadyStartedTimer, data.AlreadyStartedTimerTotalForToday)
		tpl.Attachments = append(tpl.Attachments, sa)
	}

	tpl.Attachments = append(tpl.Attachments, t.summaryAttachment("today", data.UserTotalForToday))

	result, err := json.Marshal(tpl)
	if err != nil {
		// todo return { "text": err.String() }
	}

	return string(result)
}

func (t *DefaultSlackMessageTheme) attachmentForNewTask(timer *models.Timer, taskTotalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(taskTotalForToday)*int64(time.Minute))), timer.TaskName)
	sa.ThumbURL = t.asset(t.StartCommandThumbURL)
	sa.Color = t.StartCommandColor
	sa.AuthorName = "Started:"

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Edit in Application>", timer.TaskHash)

	return sa
}

func (t *DefaultSlackMessageTheme) attachmentForCurrentTask(timer *models.Timer, totalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(totalForToday)*int64(time.Minute))), timer.TaskName)
	sa.ThumbURL = t.asset(t.StartCommandThumbURL)
	sa.Color = t.StartCommandColor
	sa.AuthorName = "Current:"

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)

	sa.Fields = []slack.AttachmentField{}
	return sa
}

func (t *DefaultSlackMessageTheme) attachmentForStoppedTask(timer *models.Timer, totalForToday int) slack.Attachment {
	sa := t.defaultAttachment()
	sa.AuthorName = "Completed:"

	sa.Text = fmt.Sprintf("•  *%s*  %s\n", utils.FormatDuration(time.Duration(int64(totalForToday)*int64(time.Minute))), timer.TaskName)
	sa.ThumbURL = t.asset(t.StopCommandThumbURL)
	sa.Color = t.StopCommandColor

	sa.Footer = fmt.Sprintf(
		"Task ID: %s > <http://www.google.com|Open in Application>", timer.TaskHash)

	sa.Fields = []slack.AttachmentField{}
	return sa
}

func (t *DefaultSlackMessageTheme) summaryAttachment(period string, minutes int) slack.Attachment {
	result := slack.Attachment{}
	result.Text = fmt.Sprintf("*Your total for %s is %s*",
		period,
		utils.FormatDuration(time.Duration(int64(minutes)*int64(time.Minute))))

	result.Color = t.SummaryAttachmentColor
	result.MarkdownIn = t.MarkdownEnabledFor
	return result
}

func (t *DefaultSlackMessageTheme) defaultAttachment() slack.Attachment {
	result := slack.Attachment{}
	result.MarkdownIn = t.MarkdownEnabledFor
	return result
}

func (t *DefaultSlackMessageTheme) asset(assetPath string) string {
	return utils.GetSelfBaseURLFromContext(t.ctx) + assetPath
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"github.com/realglobe-Inc/go-lib-rg/file"
	"github.com/realglobe-Inc/go-lib-rg/rglog/level"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type parameters struct {
	// 画面表示ログ。
	consLv level.Level

	// 追加ログ。
	logType string
	logLv   level.Level

	// ファイルログ。
	logPath string

	// fluentd ログ。
	fluAddr string
	fluTag  string

	// ID プロバイダリスト。
	idpListType string

	// ファイルベース ID プロバイダリスト。
	idpListPath string

	// Web ベース ID プロバイダリスト。
	idpListAddr string

	// mongo ID プロバイダリスト。
	idpListUrl  string
	idpListDb   string
	idpListColl string

	// ID プロバイダ属性レジストリ。
	idpAttrRegType string

	// ファイルベース ID プロバイダ属性レジストリ。
	idpAttrRegPath string

	// Web ベース ID プロバイダ属性レジストリ。
	idpAttrRegAddr string

	// mongo ID プロバイダ属性レジストリ。
	idpAttrRegUrl  string
	idpAttrRegDb   string
	idpAttrRegColl string

	// ソケット。
	socType string

	// UNIX ソケット。
	socPath string

	// TCP ソケット。
	socPort int

	// プロトコル。
	protType string

	// cookie の有効期間（秒）。
	cookieMaxAge int
}

func parseParameters(args ...string) (param *parameters, err error) {

	const label = "idp-selector"

	flags := util.NewFlagSet("edo-"+label+" parameters", flag.ExitOnError)
	flags.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:")
		fmt.Fprintln(os.Stderr, "  "+args[0]+" [{FLAG}...]")
		fmt.Fprintln(os.Stderr, "FLAG:")
		flags.PrintDefaults()
	}

	param = &parameters{}

	flags.Var(level.Var(&param.consLv, level.INFO), "consLv", "Console log level.")
	flags.StringVar(&param.logType, "logType", "", "Extra log type.")
	flags.Var(level.Var(&param.logLv, level.ALL), "logLv", "Extra log level.")
	flags.StringVar(&param.logPath, "logPath", filepath.Join(os.TempDir(), "edo", label+".log"), "File log path.")
	flags.StringVar(&param.fluAddr, "fluAddr", "localhost:24224", "fluentd address.")
	flags.StringVar(&param.fluTag, "fluTag", "edo."+label, "fluentd tag.")

	flags.StringVar(&param.idpListType, "idpListType", "web", "ID provider lister type.")
	flags.StringVar(&param.idpListPath, "idpListPath", filepath.Join("sandbox", "idp-lister"), "ID provider lister directory.")
	flags.StringVar(&param.idpListAddr, "idpListAddr", "http://localhost:16031", "ID provider lister address.")
	flags.StringVar(&param.idpListUrl, "idpListUrl", "localhost", "ID provider lister address.")
	flags.StringVar(&param.idpListDb, "idpListDb", "edo", "ID provider lister database name.")
	flags.StringVar(&param.idpListColl, "idpListColl", "idp-lister", "ID provider lister collection name.")

	flags.StringVar(&param.idpAttrRegType, "idpAttrRegType", "web", "ID provider attribute provider type.")
	flags.StringVar(&param.idpAttrRegPath, "idpAttrRegPath", filepath.Join("sandbox", "idp-attribute-provider"), "ID provider attribute provider directory.")
	flags.StringVar(&param.idpAttrRegAddr, "idpAttrRegAddr", "http://localhost:16032", "ID provider attribute provider address.")
	flags.StringVar(&param.idpAttrRegUrl, "idpAttrRegUrl", "localhost", "ID provider attribute provider address.")
	flags.StringVar(&param.idpAttrRegDb, "idpAttrRegDb", "edo", "ID provider attribute provider database name.")
	flags.StringVar(&param.idpAttrRegColl, "idpAttrRegColl", "idp-attribute-provider", "ID provider attribute provider collection name.")

	flags.StringVar(&param.socType, "socType", "tcp", "Socket type.")
	flags.StringVar(&param.socPath, "socPath", filepath.Join(os.TempDir(), "edo", label), "UNIX socket path.")
	flags.IntVar(&param.socPort, "socPort", 16030, "TCP socket port.")

	flags.StringVar(&param.protType, "protType", "http", "Protocol type.")

	flags.IntVar(&param.cookieMaxAge, "cookieMaxAge", 7*24*60*60, "Cookie expiration duration (second).")

	var config string
	flags.StringVar(&config, "f", "", "Config file path.")

	// 実行引数を読んで、設定ファイルを指定させてから、
	// 設定ファイルを読んで、また実行引数を読む。
	flags.Parse(args[1:])
	if config != "" {
		if exist, err := file.IsExist(config); err != nil {
			return nil, erro.Wrap(err)
		} else if !exist {
			log.Warn("Config file " + config + " is not exist.")
		} else {
			buff, err := ioutil.ReadFile(config)
			if err != nil {
				return nil, erro.Wrap(err)
			}
			flags.CompleteParse(strings.Fields(string(buff)))
		}
	}
	flags.Parse(args[1:])

	if l := len(flags.Args()); l > 0 {
		log.Warn("Ignore extra parameters ", flags.Args(), ".")
	}

	return param, nil
}
<commit_msg>使用するファイルが1つのディレクトリ以下に収まるようにデフォルト値を変更<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"github.com/realglobe-Inc/go-lib-rg/file"
	"github.com/realglobe-Inc/go-lib-rg/rglog/level"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type parameters struct {
	// 画面表示ログ。
	consLv level.Level

	// 追加ログ。
	logType string
	logLv   level.Level

	// ファイルログ。
	logPath string

	// fluentd ログ。
	fluAddr string
	fluTag  string

	// ID プロバイダリスト。
	idpListType string

	// ファイルベース ID プロバイダリスト。
	idpListPath string

	// Web ベース ID プロバイダリスト。
	idpListAddr string

	// mongo ID プロバイダリスト。
	idpListUrl  string
	idpListDb   string
	idpListColl string

	// ID プロバイダ属性レジストリ。
	idpAttrRegType string

	// ファイルベース ID プロバイダ属性レジストリ。
	idpAttrRegPath string

	// Web ベース ID プロバイダ属性レジストリ。
	idpAttrRegAddr string

	// mongo ID プロバイダ属性レジストリ。
	idpAttrRegUrl  string
	idpAttrRegDb   string
	idpAttrRegColl string

	// ソケット。
	socType string

	// UNIX ソケット。
	socPath string

	// TCP ソケット。
	socPort int

	// プロトコル。
	protType string

	// cookie の有効期間（秒）。
	cookieMaxAge int
}

func parseParameters(args ...string) (param *parameters, err error) {

	const label = "edo-idp-selector"

	flags := util.NewFlagSet(label+" parameters", flag.ExitOnError)
	flags.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:")
		fmt.Fprintln(os.Stderr, "  "+args[0]+" [{FLAG}...]")
		fmt.Fprintln(os.Stderr, "FLAG:")
		flags.PrintDefaults()
	}

	param = &parameters{}

	flags.Var(level.Var(&param.consLv, level.INFO), "consLv", "Console log level.")
	flags.StringVar(&param.logType, "logType", "", "Extra log type.")
	flags.Var(level.Var(&param.logLv, level.ALL), "logLv", "Extra log level.")
	flags.StringVar(&param.logPath, "logPath", filepath.Join(filepath.Dir(os.Args[0]), "log", label+".log"), "File log path.")
	flags.StringVar(&param.fluAddr, "fluAddr", "localhost:24224", "fluentd address.")
	flags.StringVar(&param.fluTag, "fluTag", "edo."+label, "fluentd tag.")

	flags.StringVar(&param.idpListType, "idpListType", "web", "ID provider lister type.")
	flags.StringVar(&param.idpListPath, "idpListPath", filepath.Join(filepath.Dir(os.Args[0]), "idps"), "ID provider lister directory.")
	flags.StringVar(&param.idpListAddr, "idpListAddr", "http://localhost:16031", "ID provider lister address.")
	flags.StringVar(&param.idpListUrl, "idpListUrl", "localhost", "ID provider lister address.")
	flags.StringVar(&param.idpListDb, "idpListDb", "edo", "ID provider lister database name.")
	flags.StringVar(&param.idpListColl, "idpListColl", "idps", "ID provider lister collection name.")

	flags.StringVar(&param.idpAttrRegType, "idpAttrRegType", "web", "ID provider attribute provider type.")
	flags.StringVar(&param.idpAttrRegPath, "idpAttrRegPath", filepath.Join(filepath.Dir(os.Args[0]), "idp_attributes"), "ID provider attribute provider directory.")
	flags.StringVar(&param.idpAttrRegAddr, "idpAttrRegAddr", "http://localhost:16032", "ID provider attribute provider address.")
	flags.StringVar(&param.idpAttrRegUrl, "idpAttrRegUrl", "localhost", "ID provider attribute provider address.")
	flags.StringVar(&param.idpAttrRegDb, "idpAttrRegDb", "edo", "ID provider attribute provider database name.")
	flags.StringVar(&param.idpAttrRegColl, "idpAttrRegColl", "idp_attributes", "ID provider attribute provider collection name.")

	flags.StringVar(&param.socType, "socType", "tcp", "Socket type.")
	flags.StringVar(&param.socPath, "socPath", filepath.Join(filepath.Dir(os.Args[0]), "run", label+".soc"), "UNIX socket path.")
	flags.IntVar(&param.socPort, "socPort", 16030, "TCP socket port.")

	flags.StringVar(&param.protType, "protType", "http", "Protocol type.")

	flags.IntVar(&param.cookieMaxAge, "cookieMaxAge", 7*24*60*60, "Cookie expiration duration (second).")

	var config string
	flags.StringVar(&config, "f", "", "Config file path.")

	// 実行引数を読んで、設定ファイルを指定させてから、
	// 設定ファイルを読んで、また実行引数を読む。
	flags.Parse(args[1:])
	if config != "" {
		if exist, err := file.IsExist(config); err != nil {
			return nil, erro.Wrap(err)
		} else if !exist {
			log.Warn("Config file " + config + " is not exist.")
		} else {
			buff, err := ioutil.ReadFile(config)
			if err != nil {
				return nil, erro.Wrap(err)
			}
			flags.CompleteParse(strings.Fields(string(buff)))
		}
	}
	flags.Parse(args[1:])

	if l := len(flags.Args()); l > 0 {
		log.Warn("Ignore extra parameters ", flags.Args(), ".")
	}

	return param, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by a BSD-style license.

// package gxlog is based on log4go.
// color.go provides colorful terminal log output functions.
package gxlog

import (
	"fmt"
	"os"
)

import (
	"github.com/mattn/go-isatty"
)

var (
	// Normal colors
	NORMAL   = []byte{'\033', '0', 'm'}
	NBlack   = []byte{'\033', '[', '3', '0', 'm'}
	NRed     = []byte{'\033', '[', '3', '1', 'm'}
	NGreen   = []byte{'\033', '[', '3', '2', 'm'}
	NYellow  = []byte{'\033', '[', '3', '3', 'm'}
	NBlue    = []byte{'\033', '[', '3', '4', 'm'}
	NMagenta = []byte{'\033', '[', '3', '5', 'm'}
	NCyan    = []byte{'\033', '[', '3', '6', 'm'}
	NWhite   = []byte{'\033', '[', '3', '7', 'm'}
	// Bright colors
	BBlack                    = []byte{'\033', '[', '3', '0', ';', '1', 'm'}
	BRed                      = []byte{'\033', '[', '3', '1', ';', '1', 'm'}
	BGreen                    = []byte{'\033', '[', '3', '2', ';', '1', 'm'}
	BYellow                   = []byte{'\033', '[', '3', '3', ';', '1', 'm'}
	BBlue                     = []byte{'\033', '[', '3', '4', ';', '1', 'm'}
	BMagenta                  = []byte{'\033', '[', '3', '5', ';', '1', 'm'}
	BCyan                     = []byte{'\033', '[', '3', '6', ';', '1', 'm'}
	BWhite                    = []byte{'\033', '[', '3', '7', ';', '1', 'm'}
	UnderlineTwinkleHighLight = []byte{'\033', '[', '1', ';', '6', ';', '4', '0', 'm'}

	reset = []byte{'\033', '[', '0', 'm'}
)

func CPrintf(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stdout, string(color)+fmt.Sprintf(format, args...)+string(reset))
	} else {
		fmt.Fprintf(os.Stdout, fmt.Sprintf(format, args...))
	}
}

func CPrintfln(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stdout, string(color)+fmt.Sprintf(format, args...)+string(reset)+"\n")
	} else {
		fmt.Fprintf(os.Stdout, fmt.Sprintf(format, args...)+"\n")
	}
}

func CEPrintf(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stderr, string(color)+fmt.Sprintf(format, args...)+string(reset))
	} else {
		fmt.Fprintf(os.Stderr, fmt.Sprintf(format, args...))
	}
}

func CEPrintfln(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stderr, string(color)+fmt.Sprintf(format, args...)+string(reset)+"\n")
	} else {
		fmt.Fprintf(os.Stderr, fmt.Sprintf(format, args...)+"\n")
	}
}

func CDebug(format string, args ...interface{}) {
	CPrintfln(NORMAL, format, args...)
}

func CInfo(format string, args ...interface{}) {
	CPrintfln(NGreen, format, args...)
}

func CWarn(format string, args ...interface{}) {
	CPrintfln(BYellow, format, args...)
}

func CError(format string, args ...interface{}) {
	CPrintfln(NRed, format, args...)
}

func CFatal(format string, args ...interface{}) {
	CPrintfln(BRed, format, args...)
}
<commit_msg>add func-file-line info for color.go<commit_after>// Copyright 2016 AlexStocks(https://github.com/AlexStocks).
// All rights reserved.  Use of this source code is
// governed by a BSD-style license.

// package gxlog is based on log4go.
// color.go provides colorful terminal log output functions.
package gxlog

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
)

import (
	"github.com/mattn/go-isatty"
)

var (
	// Normal colors
	NORMAL   = []byte{'\033', '0', 'm'}
	NBlack   = []byte{'\033', '[', '3', '0', 'm'}
	NRed     = []byte{'\033', '[', '3', '1', 'm'}
	NGreen   = []byte{'\033', '[', '3', '2', 'm'}
	NYellow  = []byte{'\033', '[', '3', '3', 'm'}
	NBlue    = []byte{'\033', '[', '3', '4', 'm'}
	NMagenta = []byte{'\033', '[', '3', '5', 'm'}
	NCyan    = []byte{'\033', '[', '3', '6', 'm'}
	NWhite   = []byte{'\033', '[', '3', '7', 'm'}
	// Bright colors
	BBlack                    = []byte{'\033', '[', '3', '0', ';', '1', 'm'}
	BRed                      = []byte{'\033', '[', '3', '1', ';', '1', 'm'}
	BGreen                    = []byte{'\033', '[', '3', '2', ';', '1', 'm'}
	BYellow                   = []byte{'\033', '[', '3', '3', ';', '1', 'm'}
	BBlue                     = []byte{'\033', '[', '3', '4', ';', '1', 'm'}
	BMagenta                  = []byte{'\033', '[', '3', '5', ';', '1', 'm'}
	BCyan                     = []byte{'\033', '[', '3', '6', ';', '1', 'm'}
	BWhite                    = []byte{'\033', '[', '3', '7', ';', '1', 'm'}
	UnderlineTwinkleHighLight = []byte{'\033', '[', '1', ';', '6', ';', '4', '0', 'm'}

	reset = []byte{'\033', '[', '0', 'm'}
)

func funcFileLine() string {
	funcName, file, line, _ := runtime.Caller(3)
	return "[" + runtime.FuncForPC(funcName).Name() +
		": " + filepath.Base(file) +
		": " + fmt.Sprintf("%d", line) +
		"] "
}

func CPrintf(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stdout, string(color)+funcFileLine()+fmt.Sprintf(format, args...)+string(reset))
	} else {
		fmt.Fprintf(os.Stdout, fmt.Sprintf(format, args...))
	}
}

func CPrintfln(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stdout, string(color)+funcFileLine()+fmt.Sprintf(format, args...)+string(reset)+"\n")
	} else {
		fmt.Fprintf(os.Stdout, fmt.Sprintf(format, args...)+"\n")
	}
}

func CEPrintf(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stderr, string(color)+funcFileLine()+fmt.Sprintf(format, args...)+string(reset))
	} else {
		fmt.Fprintf(os.Stderr, fmt.Sprintf(format, args...))
	}
}

func CEPrintfln(color []byte, format string, args ...interface{}) {
	if isatty.IsTerminal(os.Stdout.Fd()) {
		fmt.Fprintf(os.Stderr, string(color)+funcFileLine()+fmt.Sprintf(format, args...)+string(reset)+"\n")
	} else {
		fmt.Fprintf(os.Stderr, fmt.Sprintf(format, args...)+"\n")
	}
}

func CDebug(format string, args ...interface{}) {
	CPrintfln(NORMAL, format, args...)
}

func CInfo(format string, args ...interface{}) {
	CPrintfln(NGreen, format, args...)
}

func CWarn(format string, args ...interface{}) {
	CPrintfln(BYellow, format, args...)
}

func CError(format string, args ...interface{}) {
	CPrintfln(NRed, format, args...)
}

func CFatal(format string, args ...interface{}) {
	CPrintfln(BRed, format, args...)
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/heketi/heketi/apps/glusterfs"
	"github.com/heketi/heketi/tests"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
)

func TestJsonFlags(t *testing.T) {
	defer os.Remove("heketi.db")

	// Create the app
	app := glusterfs.NewApp()
	defer app.Close()
	router := mux.NewRouter()
	app.SetRoutes(router)

	// Setup the server
	ts := httptest.NewServer(router)
	defer ts.Close()

	//set options
	options := &Options{
		Url:  ts.URL,
		Json: true,
	}

	//create b to get values of stdout
	var b bytes.Buffer
	defer tests.Patch(&stdout, &b).Restore()

	//create mock cluster and mock destroy
	mockCluster := NewClusterCreateCommand(options)

	//create new cluster and assert json
	err := mockCluster.Exec([]string{})
	tests.Assert(t, err == nil)
	var clusterInfoResCreate glusterfs.ClusterInfoResponse
	err = json.Unmarshal(b.Bytes(), &clusterInfoResCreate)
	tests.Assert(t, err == nil, err)
	tests.Assert(t, strings.Contains(b.String(), clusterInfoResCreate.Id), clusterInfoResCreate)
	b.Reset()

	//get cluster info and assert json
	clusterInfo := NewClusterInfoCommand(options)
	args := []string{clusterInfoResCreate.Id}
	err = clusterInfo.Exec(args)
	tests.Assert(t, err == nil)
	tests.Assert(t, strings.Contains(b.String(), clusterInfoResCreate.Id))
	b.Reset()

	//get cluster list and assert json
	clusterList := NewClusterListCommand(options)
	err = clusterList.Exec([]string{})
	tests.Assert(t, err == nil)
	var clusterListResList glusterfs.ClusterInfoResponse
	err = json.Unmarshal(b.Bytes(), &clusterListResList)
	tests.Assert(t, strings.Contains(b.String(), clusterListResList.Id))
	b.Reset()

	//destroy cluster and assert proper json response
	clusterDestroy := NewClusterDestroyCommand(options)
	err = clusterDestroy.Exec(args)
	tests.Assert(t, err != nil)
	tests.Assert(t, strings.Contains(b.String(), ""))

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

package commands

import (
	"bytes"
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/heketi/heketi/apps/glusterfs"
	"github.com/heketi/heketi/tests"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
)

func TestJsonFlagsCreate(t *testing.T) {
	db := tests.Tempfile()
	defer os.Remove(db)

	// Create the app
	app := glusterfs.NewTestApp(db)
	defer app.Close()
	router := mux.NewRouter()
	app.SetRoutes(router)

	// Setup the server
	ts := httptest.NewServer(router)
	defer ts.Close()

	//set options
	options := &Options{
		Url:  ts.URL,
		Json: true,
	}

	//create b to get values of stdout
	var b bytes.Buffer
	defer tests.Patch(&stdout, &b).Restore()

	//create mock cluster and mock destroy
	mockCluster := NewClusterCreateCommand(options)

	//create new cluster and assert json
	err := mockCluster.Exec([]string{})
	tests.Assert(t, err == nil)
	var clusterInfoResCreate glusterfs.ClusterInfoResponse
	err = json.Unmarshal(b.Bytes(), &clusterInfoResCreate)
	tests.Assert(t, err == nil, err)
	tests.Assert(t, strings.Contains(b.String(), clusterInfoResCreate.Id), clusterInfoResCreate)
	b.Reset()

	//get cluster info and assert json
	clusterInfo := NewClusterInfoCommand(options)
	args := []string{clusterInfoResCreate.Id}
	err = clusterInfo.Exec(args)
	tests.Assert(t, err == nil)
	tests.Assert(t, strings.Contains(b.String(), clusterInfoResCreate.Id))
	b.Reset()

	//get cluster list and assert json
	clusterList := NewClusterListCommand(options)
	err = clusterList.Exec([]string{})
	tests.Assert(t, err == nil)
	var clusterListResList glusterfs.ClusterInfoResponse
	err = json.Unmarshal(b.Bytes(), &clusterListResList)
	tests.Assert(t, strings.Contains(b.String(), clusterListResList.Id))
	b.Reset()

	//destroy cluster and assert proper json response
	clusterDestroy := NewClusterDestroyCommand(options)
	err = clusterDestroy.Exec(args)
	tests.Assert(t, err != nil)
	tests.Assert(t, strings.Contains(b.String(), ""))

}
<|endoftext|>


<commit_before>package helium

import (
	"bytes"
	"errors"
	"io"
	"strings"

	"github.com/lestrrat/helium/internal/debug"
)

func CreateDocument() *Document {
	return NewDocument("1.0", "", StandaloneImplicitNo)
}

func NewDocument(version, encoding string, standalone DocumentStandaloneType) *Document {
	doc := &Document{
		encoding:   encoding,
		standalone: standalone,
		version:    version,
	}

	doc.etype = DocumentNode
	doc.name = "(document)"
	return doc
}

func (d Document) XMLString() (string, error) {
	out := bytes.Buffer{}
	if err := d.XML(&out); err != nil {
		return "", err
	}
	return out.String(), nil
}

func (d *Document) XML(out io.Writer) error {
	return (&Dumper{}).DumpDoc(out, d)
}

func (d *Document) AddChild(cur Node) error {
	return addChild(d, cur)
}

func (d *Document) AddContent(b []byte) error {
	return addContent(d, b)
}

func (d *Document) AddSibling(n Node) error {
	return errors.New("can't add sibling to a document")
}

func (d *Document) SetTreeDoc(doc *Document) {
	setTreeDoc(d, doc)
}

func (d *Document) Encoding() string {
	// In order to differentiate between a document with explicit
	// encoding in the XML declaration and one without, the XML dump
	// routine must check for d.encoding == "", and not Encoding()
	if enc := d.encoding; enc != "" {
		return d.encoding
	}
	return "utf8"
}

func (d *Document) Standalone() DocumentStandaloneType {
	return d.standalone
}

func (d *Document) Version() string {
	return d.version
}

func (d *Document) IntSubset() *DTD {
	return d.intSubset
}

func (d *Document) ExtSubset() *DTD {
	return d.extSubset
}

func (d *Document) Replace(n Node) {
	panic("d.Replace does not make sense")
}

func (d *Document) SetDocumentElement(root Node) error {
	if d == nil {
		// what are you trying to do?
		return nil
	}

	if root == nil || root.Type() == NamespaceDeclNode {
		return nil
	}

	root.SetParent(d)
	var old Node
	for old = d.firstChild; old != nil; old = old.NextSibling() {
		if old.Type() == ElementNode {
			break
		}
	}

	if old == nil {
		d.AddChild(root)
	} else {
		old.Replace(root)
	}
	return nil
}

func (d *Document) CreateReference(name string) (*EntityRef, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateReference '%s'", name)
		defer g.IRelease("END document.CreateReference")
	}
	n, err := d.CreateCharRef(name)
	if err != nil {
		return nil, err
	}

	ent, ok := d.GetEntity(n.name)
	if ok {
		n.content = []byte(ent.content)
		// Original code says:
		// The parent pointer in entity is a DTD pointer and thus is NOT
		// updated.  Not sure if this is 100% correct.
		n.setFirstChild(ent)
		n.setLastChild(ent)
	}

	return n, nil
}

func (d *Document) CreateAttribute(name, value string, ns *Namespace) (attr *Attribute, err error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateAttribute '%s' (%s)", name, value)
		defer func() {
			g.IRelease("END document.CreateAttribute (attr.Value = '%s')", attr.Value())
		}()
	}
	var n Node
	attr = newAttribute(name, ns)
	if value != "" {
		n, err = d.stringToNodeList(value)
		if err != nil {
			attr = nil
			return
		}

		attr.setFirstChild(n)
		for n != nil {
			n.SetParent(attr)
			x := n.NextSibling()
			if x == nil {
				n.setLastChild(x)
			}
			n = x
		}
	}
	return attr, nil
}

func (d *Document) CreateNamespace(prefix, uri string) (*Namespace, error) {
	ns := newNamespace(prefix, uri)
	ns.context = d
	return ns, nil
}

func (d *Document) CreatePI(target, data string) (*ProcessingInstruction, error) {
	return &ProcessingInstruction{
		target: target,
		data:   data,
	}, nil
}

func (d *Document) CreateDTD() (*DTD, error) {
	dtd := newDTD()
	dtd.doc = d
	return dtd, nil
}

func (d *Document) CreateElement(name string) (*Element, error) {
	e := newElement(name)
	e.doc = d
	return e, nil
}

func (d *Document) CreateText(value []byte) (*Text, error) {
	e := newText(value)
	e.doc = d
	return e, nil
}

func (d *Document) CreateComment(value []byte) (*Comment, error) {
	e := newComment(value)
	e.doc = d
	return e, nil
}

func (d *Document) CreateElementContent(name string, etype ElementContentType) (*ElementContent, error) {
	e, err := newElementContent(name, etype)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (d *Document) GetEntity(name string) (*Entity, bool) {
	if ints := d.intSubset; ints != nil {
		return ints.LookupEntity(name)
	}

	if exts := d.extSubset; exts != nil {
		return exts.LookupEntity(name)
	}

	return nil, false
}

func (d *Document) GetParameterEntity(name string) (*Entity, bool) {
	if ints := d.intSubset; ints != nil {
		return ints.LookupParameterEntity(name)
	}

	if exts := d.extSubset; exts != nil {
		return exts.LookupParameterEntity(name)
	}

	return nil, false
}

func (d *Document) IsMixedElement(name string) (bool, error) {
	if d.intSubset == nil {
		return false, errors.New("element declaration not found")
	}

	edecl, ok := d.intSubset.GetElementDesc(name)
	if !ok {
		return false, errors.New("element declaration not found")
	}

	switch edecl.decltype {
	case UndefinedElementType:
		return false, errors.New("element declaration not found")
	case ElementElementType:
		return false, nil
	case EmptyElementType, AnyElementType, MixedElementType:
		/*
		 * return 1 for EMPTY since we want VC error to pop up
		 * on <empty>     </empty> for example
		 */
		return true, nil
	}
	return true, nil
}

/*
 * @doc:  the document
 * @value:  the value of the attribute
 *
 * Parse the value string and build the node list associated. Should
 * produce a flat tree with only TEXTs and ENTITY_REFs.
 * Returns a pointer to the first child
 */
func (d *Document) stringToNodeList(value string) (Node, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.stringToNodeList '%s'", value)
		defer g.IRelease("END document.stringToNodeList")
	}
	rdr := strings.NewReader(value)
	buf := bytes.Buffer{}
	var ret Node
	var last Node
	var charval int32
	for rdr.Len() > 0 {
		r, _, err := rdr.ReadRune()
		if err != nil {
			return nil, err
		}

		// if this is not any sort of an entity , just go go go
		if r != '&' {
			buf.WriteRune(r)
			continue
		}

		// well, at least the first rune sure looks like an entity, see what
		// else we have.
		r, _, err = rdr.ReadRune()
		if err != nil {
			return nil, err
		}

		if r == '#' {
			r2, _, err := rdr.ReadRune()
			if err != nil {
				return nil, err
			}

			var accumulator func(int32, rune) (int32, error)
			if r2 == 'x' {
				accumulator = accumulateHexCharRef
			} else {
				rdr.UnreadRune()
				accumulator = accumulateDecimalCharRef
			}
			for {
				r, _, err = rdr.ReadRune()
				if err != nil {
					return nil, err
				}
				if r == ';' {
					break
				}
				charval, err = accumulator(charval, r)
				if err != nil {
					return nil, err
				}
			}
		} else {
			rdr.UnreadRune()
			entbuf := bytes.Buffer{}
			for rdr.Len() > 0 {
				r, _, err = rdr.ReadRune()
				if err != nil {
					return nil, err
				}
				if r == ';' {
					break
				}
				entbuf.WriteRune(r)
			}

			if r != ';' {
				return nil, errors.New("entity was unterminated (could not find terminating semicolon)")
			}

			val := entbuf.String()
			ent, ok := d.GetEntity(val)

			// XXX I *believe* libxml2 SKIPS entities that it can't resolve
			// at this point?
			if ok && ent.EntityType() == int(InternalPredefinedEntity) {
				buf.Write(ent.Content())
			} else {
				// flush the buffer so far
				if buf.Len() > 0 {
					node, err := d.CreateText(buf.Bytes())
					if err != nil {
						return nil, err
					}
					buf.Reset()

					if last == nil {
						last = node
						ret = node
					} else {
						last.AddSibling(node)
						last = node
					}
				}

				// create a new REFERENCE_REF node
				node, err := d.CreateReference(val)
				if err != nil {
					return nil, err
				}

				// no children
				if ok && ent.FirstChild() == nil {
					// XXX WTF am I doing here...?
					refchildren, err := d.stringToNodeList(string(node.Content()))
					if err != nil {
						return nil, err
					}
					ent.setFirstChild(refchildren)
					for n := refchildren; n != nil; {
						ent.AddChild(n)
						if x := n.NextSibling(); x != nil {
							n = x
						} else {
							n = nil
						}
					}
				}

				if last == nil {
					last = node
					ret = node
				} else {
					last.AddSibling(node)
					last = node
				}
			}
		}

		if charval != 0 {
			buf.WriteRune(rune(charval))
			charval = 0
		}
	}

	if buf.Len() > 0 {
		n, err := d.CreateText(buf.Bytes())
		if err != nil {
			return nil, err
		}

		if last == nil {
			ret = n
		} else {
			last.AddSibling(n)
		}
	}

	if debug.Enabled {
		for n := last; n != nil; n = n.PrevSibling() {
			debug.Printf("---> %s (%s)", n.Name(), n.Content())
		}
	}

	return ret, nil
}

func (d *Document) CreateCharRef(name string) (*EntityRef, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateCharRef '%s'", name)
		defer g.IRelease("END document.CreateCharRef")
	}

	if name == "" {
		return nil, errors.New("empty name")
	}

	n := newEntityRef()
	n.doc = d
	if name[0] != '&' {
		n.name = name
	} else {
		// the name should be everything but '&' and ';'
		if name[len(name)-1] == ';' {
			n.name = name[1 : len(name)-1]
		} else {
			n.name = name[1:]
		}
	}
	return n, nil
}
<commit_msg>Do not use AddChild here, as it creates node linking problems<commit_after>package helium

import (
	"bytes"
	"errors"
	"io"
	"strings"

	"github.com/lestrrat/helium/internal/debug"
)

func CreateDocument() *Document {
	return NewDocument("1.0", "", StandaloneImplicitNo)
}

func NewDocument(version, encoding string, standalone DocumentStandaloneType) *Document {
	doc := &Document{
		encoding:   encoding,
		standalone: standalone,
		version:    version,
	}

	doc.etype = DocumentNode
	doc.name = "(document)"
	return doc
}

func (d Document) XMLString() (string, error) {
	out := bytes.Buffer{}
	if err := d.XML(&out); err != nil {
		return "", err
	}
	return out.String(), nil
}

func (d *Document) XML(out io.Writer) error {
	return (&Dumper{}).DumpDoc(out, d)
}

func (d *Document) AddChild(cur Node) error {
	return addChild(d, cur)
}

func (d *Document) AddContent(b []byte) error {
	return addContent(d, b)
}

func (d *Document) AddSibling(n Node) error {
	return errors.New("can't add sibling to a document")
}

func (d *Document) SetTreeDoc(doc *Document) {
	setTreeDoc(d, doc)
}

func (d *Document) Encoding() string {
	// In order to differentiate between a document with explicit
	// encoding in the XML declaration and one without, the XML dump
	// routine must check for d.encoding == "", and not Encoding()
	if enc := d.encoding; enc != "" {
		return d.encoding
	}
	return "utf8"
}

func (d *Document) Standalone() DocumentStandaloneType {
	return d.standalone
}

func (d *Document) Version() string {
	return d.version
}

func (d *Document) IntSubset() *DTD {
	return d.intSubset
}

func (d *Document) ExtSubset() *DTD {
	return d.extSubset
}

func (d *Document) Replace(n Node) {
	panic("d.Replace does not make sense")
}

func (d *Document) SetDocumentElement(root Node) error {
	if d == nil {
		// what are you trying to do?
		return nil
	}

	if root == nil || root.Type() == NamespaceDeclNode {
		return nil
	}

	root.SetParent(d)
	var old Node
	for old = d.firstChild; old != nil; old = old.NextSibling() {
		if old.Type() == ElementNode {
			break
		}
	}

	if old == nil {
		d.AddChild(root)
	} else {
		old.Replace(root)
	}
	return nil
}

func (d *Document) CreateReference(name string) (*EntityRef, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateReference '%s'", name)
		defer g.IRelease("END document.CreateReference")
	}
	n, err := d.CreateCharRef(name)
	if err != nil {
		return nil, err
	}

	ent, ok := d.GetEntity(n.name)
	if ok {
		n.content = []byte(ent.content)
		// Original code says:
		// The parent pointer in entity is a DTD pointer and thus is NOT
		// updated.  Not sure if this is 100% correct.
		n.setFirstChild(ent)
		n.setLastChild(ent)
	}

	return n, nil
}

func (d *Document) CreateAttribute(name, value string, ns *Namespace) (attr *Attribute, err error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateAttribute '%s' (%s)", name, value)
		defer func() {
			g.IRelease("END document.CreateAttribute (attr.Value = '%s')", attr.Value())
		}()
	}
	var n Node
	attr = newAttribute(name, ns)
	if value != "" {
		n, err = d.stringToNodeList(value)
		if err != nil {
			attr = nil
			return
		}

		attr.setFirstChild(n)
		for n != nil {
			n.SetParent(attr)
			x := n.NextSibling()
			if x == nil {
				n.setLastChild(x)
			}
			n = x
		}
	}
	return attr, nil
}

func (d *Document) CreateNamespace(prefix, uri string) (*Namespace, error) {
	ns := newNamespace(prefix, uri)
	ns.context = d
	return ns, nil
}

func (d *Document) CreatePI(target, data string) (*ProcessingInstruction, error) {
	return &ProcessingInstruction{
		target: target,
		data:   data,
	}, nil
}

func (d *Document) CreateDTD() (*DTD, error) {
	dtd := newDTD()
	dtd.doc = d
	return dtd, nil
}

func (d *Document) CreateElement(name string) (*Element, error) {
	e := newElement(name)
	e.doc = d
	return e, nil
}

func (d *Document) CreateText(value []byte) (*Text, error) {
	e := newText(value)
	e.doc = d
	return e, nil
}

func (d *Document) CreateComment(value []byte) (*Comment, error) {
	e := newComment(value)
	e.doc = d
	return e, nil
}

func (d *Document) CreateElementContent(name string, etype ElementContentType) (*ElementContent, error) {
	e, err := newElementContent(name, etype)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (d *Document) GetEntity(name string) (*Entity, bool) {
	if ints := d.intSubset; ints != nil {
		return ints.LookupEntity(name)
	}

	if exts := d.extSubset; exts != nil {
		return exts.LookupEntity(name)
	}

	return nil, false
}

func (d *Document) GetParameterEntity(name string) (*Entity, bool) {
	if ints := d.intSubset; ints != nil {
		return ints.LookupParameterEntity(name)
	}

	if exts := d.extSubset; exts != nil {
		return exts.LookupParameterEntity(name)
	}

	return nil, false
}

func (d *Document) IsMixedElement(name string) (bool, error) {
	if d.intSubset == nil {
		return false, errors.New("element declaration not found")
	}

	edecl, ok := d.intSubset.GetElementDesc(name)
	if !ok {
		return false, errors.New("element declaration not found")
	}

	switch edecl.decltype {
	case UndefinedElementType:
		return false, errors.New("element declaration not found")
	case ElementElementType:
		return false, nil
	case EmptyElementType, AnyElementType, MixedElementType:
		/*
		 * return 1 for EMPTY since we want VC error to pop up
		 * on <empty>     </empty> for example
		 */
		return true, nil
	}
	return true, nil
}

/*
 * @doc:  the document
 * @value:  the value of the attribute
 *
 * Parse the value string and build the node list associated. Should
 * produce a flat tree with only TEXTs and ENTITY_REFs.
 * Returns a pointer to the first child
 */
func (d *Document) stringToNodeList(value string) (Node, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.stringToNodeList '%s'", value)
		defer g.IRelease("END document.stringToNodeList")
	}
	rdr := strings.NewReader(value)
	buf := bytes.Buffer{}
	var ret Node
	var last Node
	var charval int32
	for rdr.Len() > 0 {
		r, _, err := rdr.ReadRune()
		if err != nil {
			return nil, err
		}

		// if this is not any sort of an entity , just go go go
		if r != '&' {
			buf.WriteRune(r)
			continue
		}

		// well, at least the first rune sure looks like an entity, see what
		// else we have.
		r, _, err = rdr.ReadRune()
		if err != nil {
			return nil, err
		}

		if r == '#' {
			r2, _, err := rdr.ReadRune()
			if err != nil {
				return nil, err
			}

			var accumulator func(int32, rune) (int32, error)
			if r2 == 'x' {
				accumulator = accumulateHexCharRef
			} else {
				rdr.UnreadRune()
				accumulator = accumulateDecimalCharRef
			}
			for {
				r, _, err = rdr.ReadRune()
				if err != nil {
					return nil, err
				}
				if r == ';' {
					break
				}
				charval, err = accumulator(charval, r)
				if err != nil {
					return nil, err
				}
			}
		} else {
			rdr.UnreadRune()
			entbuf := bytes.Buffer{}
			for rdr.Len() > 0 {
				r, _, err = rdr.ReadRune()
				if err != nil {
					return nil, err
				}
				if r == ';' {
					break
				}
				entbuf.WriteRune(r)
			}

			if r != ';' {
				return nil, errors.New("entity was unterminated (could not find terminating semicolon)")
			}

			val := entbuf.String()
			ent, ok := d.GetEntity(val)

			// XXX I *believe* libxml2 SKIPS entities that it can't resolve
			// at this point?
			if ok && ent.EntityType() == int(InternalPredefinedEntity) {
				buf.Write(ent.Content())
			} else {
				// flush the buffer so far
				if buf.Len() > 0 {
					node, err := d.CreateText(buf.Bytes())
					if err != nil {
						return nil, err
					}
					buf.Reset()

					if last == nil {
						last = node
						ret = node
					} else {
						last.AddSibling(node)
						last = node
					}
				}

				// create a new REFERENCE_REF node
				node, err := d.CreateReference(val)
				if err != nil {
					return nil, err
				}

				// no children
				if ok && ent.FirstChild() == nil {
					// XXX WTF am I doing here...?
					refchildren, err := d.stringToNodeList(string(node.Content()))
					if err != nil {
						return nil, err
					}
					ent.setFirstChild(refchildren)
					for n := refchildren; n != nil; {
						n.SetParent(ent)
						if x := n.NextSibling(); x != nil {
							n = x
						} else {
							n = nil
						}
					}
				}

				if last == nil {
					last = node
					ret = node
				} else {
					last.AddSibling(node)
					last = node
				}
			}
		}

		if charval != 0 {
			buf.WriteRune(rune(charval))
			charval = 0
		}
	}

	if buf.Len() > 0 {
		n, err := d.CreateText(buf.Bytes())
		if err != nil {
			return nil, err
		}

		if last == nil {
			ret = n
		} else {
			last.AddSibling(n)
		}
	}

	if debug.Enabled {
		for n := last; n != nil; n = n.PrevSibling() {
			debug.Printf("---> %s (%s)", n.Name(), n.Content())
		}
	}

	return ret, nil
}

func (d *Document) CreateCharRef(name string) (*EntityRef, error) {
	if debug.Enabled {
		g := debug.IPrintf("START document.CreateCharRef '%s'", name)
		defer g.IRelease("END document.CreateCharRef")
	}

	if name == "" {
		return nil, errors.New("empty name")
	}

	n := newEntityRef()
	n.doc = d
	if name[0] != '&' {
		n.name = name
	} else {
		// the name should be everything but '&' and ';'
		if name[len(name)-1] == ';' {
			n.name = name[1 : len(name)-1]
		} else {
			n.name = name[1:]
		}
	}
	return n, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"time"
	"github.com/gocql/gocql"
	kafka "github.com/stealthly/go_kafka_client"
	"github.com/stealthly/go-avro"
	"fmt"
)

type Event struct {
	Topic      string `json:"topic"`
	Partition  string `json:"partition"`
	ConsumerId string `json:"consumerId"`
	EventName  string `json:"eventName"`
	Second     int64 `json:"second"`
	Operation  string `json:"operation"`
	Value      int64 `json:"value"`
	Cnt      int64 `json:"count"`
}

type EventFetcher struct {
	events     chan *Event
	connection *gocql.Session
	config *EventFetcherConfig
	consumer *kafka.Consumer
}

func NewEventFetcher(config *EventFetcherConfig) *EventFetcher {
	var err error
	fetcher := new(EventFetcher)
	fetcher.config = config
	fetcher.events = make(chan *Event)
	cluster := gocql.NewCluster(config.CassandraHost)
	cluster.Keyspace = "spark_analysis"
	fetcher.connection, err = cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}
	fetcher.consumer = fetcher.createConsumer()

	return fetcher
}

func (this *EventFetcher) Close() {
	this.connection.Close()
}

func (this *EventFetcher) createConsumer() *kafka.Consumer {
	coordinatorConfig := kafka.NewZookeeperConfig()
	coordinatorConfig.ZookeeperConnect = []string{this.config.ZkConnect}
	coordinator := kafka.NewZookeeperCoordinator(coordinatorConfig)
	consumerConfig := kafka.DefaultConsumerConfig()
	consumerConfig.AutoOffsetReset = kafka.LargestOffset
	consumerConfig.Coordinator = coordinator
	consumerConfig.Groupid = "event-dashboard"
	consumerConfig.ValueDecoder = kafka.NewKafkaAvroDecoder(this.config.SchemaRegistryUrl)
	consumerConfig.WorkerFailureCallback =  func(_ *kafka.WorkerManager) kafka.FailedDecision {
		return kafka.CommitOffsetAndContinue
	}
	consumerConfig.WorkerFailedAttemptCallback =  func(_ *kafka.Task, _ kafka.WorkerResult) kafka.FailedDecision {
		return kafka.CommitOffsetAndContinue
	}
	consumerConfig.Strategy = func(_ *kafka.Worker, msg *kafka.Message, taskId kafka.TaskId) kafka.WorkerResult {
		if record, ok := msg.DecodedValue.(*avro.GenericRecord); ok {
			this.events <- &Event{
				Topic: record.Get("topic").(string),
				Partition: record.Get("partition").(string),
				EventName: record.Get("eventname").(string),
				Second: record.Get("second").(int64),
				Operation: record.Get("operation").(string),
				Value: record.Get("value").(int64),
				Cnt: record.Get("cnt").(int64),
			}
		} else {
			return kafka.NewProcessingFailedResult(taskId)
		}

		return kafka.NewSuccessfulResult(taskId)
	}

	return kafka.NewConsumer(consumerConfig)
}

func (this *EventFetcher) EventHistory() []Event {
	time := time.Now().Add(-1*time.Hour).Unix()
	kafka.Infof("eventFetcher", "SELECT * FROM events WHERE topic = '%s' AND second > %d;", this.config.Topic, time)
	data := this.connection.Query(`SELECT * FROM events WHERE topic = ? AND second > ?;`, this.config.Topic, time).Iter()
	var events []Event
	var topic string
	var partition string
	var consumerId string
	var eventName string
	var second int64
	var operation string
	var value int64
	var cnt int64
	for data.Scan(&topic, &second, &partition, &consumerId, &eventName, &operation, &cnt, &value) {
		event := Event{
			Topic:      topic,
			Second:     second,
			Partition:  partition,
			ConsumerId: consumerId,
			EventName:  eventName,
			Operation:  operation,
			Cnt: cnt,
			Value:      value,
		}
		events = append(events, event)
	}
	if err := data.Close(); err != nil {
		log.Fatal(err)
	}
	return events
}

func (this *EventFetcher) startFetch() {
	topicCount := make(map[string]int)
	topicCount[fmt.Sprintf("mirror_%s-latencies", this.config.Topic)] = 1
	this.consumer.StartStatic(topicCount)
}

type EventFetcherConfig struct {
	CassandraHost string
	Topic string
	ZkConnect string
	SchemaRegistryUrl string
}<commit_msg>Go fmt.<commit_after>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/gocql/gocql"
	kafka "github.com/stealthly/go_kafka_client"
)

type Event struct {
	Topic      string `json:"topic"`
	Partition  string `json:"partition"`
	ConsumerId string `json:"consumerId"`
	EventName  string `json:"eventName"`
	Second     int64  `json:"second"`
	Operation  string `json:"operation"`
	Value      int64  `json:"value"`
	Cnt        int64  `json:"count"`
}

type EventFetcher struct {
	events     chan *Event
	connection *gocql.Session
	config     *EventFetcherConfig
	consumer   *kafka.Consumer
}

func NewEventFetcher(config *EventFetcherConfig) *EventFetcher {
	var err error
	fetcher := new(EventFetcher)
	fetcher.config = config
	fetcher.events = make(chan *Event)
	cluster := gocql.NewCluster(config.CassandraHost)
	cluster.Keyspace = "spark_analysis"
	fetcher.connection, err = cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}
	fetcher.consumer = fetcher.createConsumer()

	return fetcher
}

func (this *EventFetcher) Close() {
	this.connection.Close()
}

func (this *EventFetcher) createConsumer() *kafka.Consumer {
	coordinatorConfig := kafka.NewZookeeperConfig()
	coordinatorConfig.ZookeeperConnect = []string{this.config.ZkConnect}
	coordinator := kafka.NewZookeeperCoordinator(coordinatorConfig)
	consumerConfig := kafka.DefaultConsumerConfig()
	consumerConfig.AutoOffsetReset = kafka.LargestOffset
	consumerConfig.Coordinator = coordinator
	consumerConfig.Groupid = "event-dashboard"
	consumerConfig.ValueDecoder = kafka.NewKafkaAvroDecoder(this.config.SchemaRegistryUrl)
	consumerConfig.WorkerFailureCallback = func(_ *kafka.WorkerManager) kafka.FailedDecision {
		return kafka.CommitOffsetAndContinue
	}
	consumerConfig.WorkerFailedAttemptCallback = func(_ *kafka.Task, _ kafka.WorkerResult) kafka.FailedDecision {
		return kafka.CommitOffsetAndContinue
	}
	consumerConfig.Strategy = func(_ *kafka.Worker, msg *kafka.Message, taskId kafka.TaskId) kafka.WorkerResult {
		if record, ok := msg.DecodedValue.(*avro.GenericRecord); ok {
			this.events <- &Event{
				Topic:     record.Get("topic").(string),
				Partition: record.Get("partition").(string),
				EventName: record.Get("eventname").(string),
				Second:    record.Get("second").(int64),
				Operation: record.Get("operation").(string),
				Value:     record.Get("value").(int64),
				Cnt:       record.Get("cnt").(int64),
			}
		} else {
			return kafka.NewProcessingFailedResult(taskId)
		}

		return kafka.NewSuccessfulResult(taskId)
	}

	return kafka.NewConsumer(consumerConfig)
}

func (this *EventFetcher) EventHistory() []Event {
	time := time.Now().Add(-1 * time.Hour).Unix()
	kafka.Infof("eventFetcher", "SELECT * FROM events WHERE topic = '%s' AND second > %d;", this.config.Topic, time)
	data := this.connection.Query(`SELECT * FROM events WHERE topic = ? AND second > ?;`, this.config.Topic, time).Iter()
	var events []Event
	var topic string
	var partition string
	var consumerId string
	var eventName string
	var second int64
	var operation string
	var value int64
	var cnt int64
	for data.Scan(&topic, &second, &partition, &consumerId, &eventName, &operation, &cnt, &value) {
		event := Event{
			Topic:      topic,
			Second:     second,
			Partition:  partition,
			ConsumerId: consumerId,
			EventName:  eventName,
			Operation:  operation,
			Cnt:        cnt,
			Value:      value,
		}
		events = append(events, event)
	}
	if err := data.Close(); err != nil {
		log.Fatal(err)
	}
	return events
}

func (this *EventFetcher) startFetch() {
	topicCount := make(map[string]int)
	topicCount[fmt.Sprintf("mirror_%s-latencies", this.config.Topic)] = 1
	this.consumer.StartStatic(topicCount)
}

type EventFetcherConfig struct {
	CassandraHost     string
	Topic             string
	ZkConnect         string
	SchemaRegistryUrl string
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"

	"360.cn/elasticHD/main/search"
	_ "360.cn/elasticHD/main/statik"
	"github.com/rakyll/statik/fs"
)

func main() {
	statikFS, err := fs.New() // 静态文件编译成二进制
	if err != nil {
		log.Fatalf(err.Error())
	}
	http.FileServer(statikFS) // 加载http server file
	var mux = http.NewServeMux()
	// router
	mux.Handle("/", http.StripPrefix("/", http.FileServer(statikFS)))
	// 加载search package
	search.NewSearch(search.InitOptions{
		Mux: mux,
	})
	// start http server
	go func(serverAddr string, m *http.ServeMux) {
		if err = http.ListenAndServe(serverAddr, m); err != nil {
			fmt.Println("Cant start server:", err)
			os.Exit(1)
		}
	}(`0.0.0.0:9800`, mux)
	// 捕捉ctrl+C 退出信号
	handleSignals()
}

func handleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<commit_msg>elasticHD<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"

	"360.cn/elasticHD/main/search"
	_ "360.cn/elasticHD/main/statik"
	"github.com/rakyll/statik/fs"
)

var (
	Stderr io.Writer = os.Stderr // Stderr is the io.Writer to which executed commands write standard error.
	Stdout io.Writer = os.Stdout // Stdout is the io.Writer to which executed commands write standard output.
)

// Config ...
type Config struct {
	ServerHost string
}

var config *Config

func main() {

	parseFlags()
	statikFS, err := fs.New() // 静态文件编译成二进制
	if err != nil {
		log.Fatalf(err.Error())
	}
	http.FileServer(statikFS) // 加载http server file
	var mux = http.NewServeMux()
	// router
	mux.Handle("/", http.StripPrefix("/", http.FileServer(statikFS)))
	// 加载search package
	search.NewSearch(search.InitOptions{
		Mux: mux,
	})
	// start http server
	go func(serverAddr string, m *http.ServeMux) {
		if err = http.ListenAndServe(serverAddr, m); err != nil {
			fmt.Println("Cant start server:", err)
			os.Exit(1)
		}
	}(config.ServerHost, mux)
	openPage()
	// 捕捉ctrl+C 退出信号
	handleSignals()
}

func handleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}

func openPage() {
	url := fmt.Sprintf("http://%v", config.ServerHost)
	fmt.Println("To view elasticHD console open", url, "in browser")
	var err error
	switch runtime.GOOS {
	case "linux":
		err = runCmd("xdg-open", url)
	case "darwin":
		err = runCmd("open", url)
	case "windows":
		r := strings.NewReplacer("&", "^&")
		err = runCmd("cmd", "/c", "start", r.Replace(url))
	default:
		err = fmt.Errorf("unsupported platform")
	}
	if err != nil {
		fmt.Println(err)
	}
}

// runCmd run command opens a new browser window pointing to url.
func runCmd(prog string, args ...string) error {
	cmd := exec.Command(prog, args...)
	cmd.Stdout = Stdout
	cmd.Stderr = Stderr
	return cmd.Run()
}

// parseFlags parse flags of program.
func parseFlags() {
	config = &Config{}
	flag.StringVar(&config.ServerHost, "p", "0.0.0.0:9800", "local server address")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Google, Inc.,  All rights reserved.
//
// 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.
//
// File: simpleclient.go

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	// "github.com/jlmucb/cloudproxy/go/tao" // REMOVE
	taosupport "github.com/jlmucb/cloudproxy/go/apps/simpleexample/taosupport"
)

var simpleCfg = flag.String("domain_config",
	"./tao.config",
	"path to tao configuration")
var simpleClientPath = flag.String("path",
	"./SimpleClient",
	"path to SimpleClient files")
var serverHost = flag.String("host", "localhost", "address for client/server")
var serverPort = flag.String("port", "8123", "port for client/server")
var serverAddr string

func main() {

	// This holds the cloudproxy specific data for simpleclient
	// including the Program Cert and Program Private key.
	var clientProgramData taosupport.TaoProgramData

	// Make sure we zero keys when we're done.
	defer taosupport.ClearTaoProgramData(&clientProgramData)

	// Parse flags
	flag.Parse()
	serverAddr = *serverHost + ":" + *serverPort

	// If TaoParadigm completes without error, clientProgramData contains all the
	// Cloudproxy information needed throughout simpleclient execution.
	err := taosupport.TaoParadigm(simpleCfg, simpleClientPath, &clientProgramData)
	if err != nil {
		log.Fatalln("simpleclient: Can't establish Tao: ", err)
	}
	fmt.Printf("simpleclient: TaoParadigm complete, name: %s\n",
		clientProgramData.TaoName)

	// TODO(jlm): The commented out code hasn't been reviewed
	// it will be restored later.
/*
	err = tao.Parent().InitCounter("label", 0)  // REMOVE
	fmt.Printf("Return from InitCounter %s\n", err)
	_,  err = tao.Parent().GetCounter("label")  // REMOVE
	fmt.Printf("Return from GetCounter %s\n", err)
	data := []byte {
		0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,
		0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5, }
	_,  err = tao.Parent().RollbackProtectedSeal("label", data, tao.SealPolicyDefault)  // REMOVE
	fmt.Printf("Return from .RollBackProtectedSeal: %s\n", err)
*/

	// Open the Tao Channel using the Program key. This program does all the
	// standard channel negotiation and presents the secure server name
	// after negotiation is complete.
	ms, serverName, err := taosupport.OpenTaoChannel(&clientProgramData,
		&serverAddr)
	if err != nil {
		log.Fatalln("simpleclient: Can't establish Tao Channel")
	}
	log.Printf("simpleclient: establish Tao Channel with %s, %s\n",
		serverAddr, serverName)

	// Send a simple request and get response.
	// We have a simple service protobuf for requests and reponsed between
	// simpleclient and simpleserver.  There's only on request: tell me the
	// secret.
	secretRequest := "SecretRequest"

	msg := new(taosupport.SimpleMessage)
	msg.RequestType = &secretRequest
	taosupport.SendRequest(ms, msg)
	if err != nil {
		log.Fatalln("simpleclient: Error in response to SendRequest\n")
	}
	respmsg, err := taosupport.GetResponse(ms)
	if err != nil {
		log.Fatalln("simpleclient: Error in response to GetResponse\n")
	}

	// This is the secret.
	retrieveSecret := respmsg.Data[0]

	// Encrypt and store the secret in simpleclient's save area.
	out, err := taosupport.Protect(clientProgramData.ProgramSymKeys, retrieveSecret)
	if err != nil {
		log.Fatalln("simpleclient: Error protecting data\n")
	}
	err = ioutil.WriteFile(path.Join(*simpleClientPath,
		"retrieved_secret"), out, os.ModePerm)
	if err != nil {
		log.Fatalln("simpleclient: error saving retrieved secret\n")
	}

	// Close down.
	log.Printf("simpleclient: secret is %s, done\n", retrieveSecret)
}
<commit_msg>Integrate Rollback tests in simpleclient<commit_after>// Copyright (c) 2014, Google, Inc.,  All rights reserved.
//
// 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.
//
// File: simpleclient.go

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"

	"github.com/jlmucb/cloudproxy/go/tao"
	taosupport "github.com/jlmucb/cloudproxy/go/apps/simpleexample/taosupport"
)

var simpleCfg = flag.String("domain_config",
	"./tao.config",
	"path to tao configuration")
var simpleClientPath = flag.String("path",
	"./SimpleClient",
	"path to SimpleClient files")
var testRollback= flag.bool("test_rollback", false, "test rollback?")
var serverHost = flag.String("host", "localhost", "address for client/server")
var serverPort = flag.String("port", "8123", "port for client/server")
var serverAddr string

func main() {

	// This holds the cloudproxy specific data for simpleclient
	// including the Program Cert and Program Private key.
	var clientProgramData taosupport.TaoProgramData

	// Make sure we zero keys when we're done.
	defer taosupport.ClearTaoProgramData(&clientProgramData)

	// Parse flags
	flag.Parse()
	serverAddr = *serverHost + ":" + *serverPort

	// If TaoParadigm completes without error, clientProgramData contains all the
	// Cloudproxy information needed throughout simpleclient execution.
	err := taosupport.TaoParadigm(simpleCfg, simpleClientPath, &clientProgramData)
	if err != nil {
		log.Fatalln("simpleclient: Can't establish Tao: ", err)
	}
	fmt.Printf("simpleclient: TaoParadigm complete, name: %s\n",
		clientProgramData.TaoName)

	if testRollback {
		err = tao.Parent().InitCounter("label", 0)
		if err != nil {
			fmt.Printf("simpleclient: Can't InitCounter: ", err)
		}
		fmt.Printf("Return from InitCounter %s\n", err)
		c,  err := tao.Parent().GetCounter("label")
		fmt.Printf("Return from GetCounter %d %s\n", c, err)
		if err != nil {
			fmt.Printf("simpleclient: Can't GetCounter: ", err)
		}
		data := []byte {
			0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,
			0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5, }
		sealed,  err := tao.Parent().RollbackProtectedSeal("label", data,
			tao.SealPolicyDefault)  // REMOVE
		if err != nil {
			fmt.Printf("simpleclient: Can't GetCounter: ", err)
		}
		fmt.Printf("Return from .RollBackProtectedSeal: %s\n", err)
		recoveredData,  _, err := tao.Parent().RollbackProtectedUnseal(sealed)
		if err != nil {
			fmt.Printf("simpleclient: Can't GetCounter: ", err)
		}
		fmt.Printf("data: %x, recovered data: %x\n", data, recoveredData)
	}

	// Open the Tao Channel using the Program key. This program does all the
	// standard channel negotiation and presents the secure server name
	// after negotiation is complete.
	ms, serverName, err := taosupport.OpenTaoChannel(&clientProgramData,
		&serverAddr)
	if err != nil {
		log.Fatalln("simpleclient: Can't establish Tao Channel")
	}
	log.Printf("simpleclient: establish Tao Channel with %s, %s\n",
		serverAddr, serverName)

	// Send a simple request and get response.
	// We have a simple service protobuf for requests and reponsed between
	// simpleclient and simpleserver.  There's only on request: tell me the
	// secret.
	secretRequest := "SecretRequest"

	msg := new(taosupport.SimpleMessage)
	msg.RequestType = &secretRequest
	taosupport.SendRequest(ms, msg)
	if err != nil {
		log.Fatalln("simpleclient: Error in response to SendRequest\n")
	}
	respmsg, err := taosupport.GetResponse(ms)
	if err != nil {
		log.Fatalln("simpleclient: Error in response to GetResponse\n")
	}

	// This is the secret.
	retrieveSecret := respmsg.Data[0]

	// Encrypt and store the secret in simpleclient's save area.
	out, err := taosupport.Protect(clientProgramData.ProgramSymKeys, retrieveSecret)
	if err != nil {
		log.Fatalln("simpleclient: Error protecting data\n")
	}
	err = ioutil.WriteFile(path.Join(*simpleClientPath,
		"retrieved_secret"), out, os.ModePerm)
	if err != nil {
		log.Fatalln("simpleclient: error saving retrieved secret\n")
	}

	// Close down.
	log.Printf("simpleclient: secret is %s, done\n", retrieveSecret)
}
<|endoftext|>


<commit_before>package models

import (
	"socialapi/request"

	"github.com/koding/bongo"
)

type ChannelMessageContainer struct {
	Message      *ChannelMessage                  `json:"message"`
	Interactions map[string]*InteractionContainer `json:"interactions"`
	RepliesCount int                              `json:"repliesCount"`
	// Replies should stay as   ChannelMessageContainers
	// not as a pointer
	Replies            ChannelMessageContainers `json:"replies"`
	AccountOldId       string                   `json:"accountOldId"`
	IsFollowed         bool                     `json:"isFollowed"`
	UnreadRepliesCount int                      `json:"unreadRepliesCount,omitempty"`
	Err                error                    `json:"-"`
}

func NewChannelMessageContainer() *ChannelMessageContainer {
	container := &ChannelMessageContainer{}
	container.Interactions = make(map[string]*InteractionContainer)
	container.Interactions["like"] = NewInteractionContainer()

	return container
}

type InteractionContainer struct {
	IsInteracted  bool     `json:"isInteracted"`
	ActorsPreview []string `json:"actorsPreview"`
	ActorsCount   int      `json:"actorsCount"`
}

func NewInteractionContainer() *InteractionContainer {
	interactionContainer := &InteractionContainer{}
	interactionContainer.ActorsPreview = make([]string, 0)
	interactionContainer.IsInteracted = false
	interactionContainer.ActorsCount = 0

	return interactionContainer
}

func withChannelMessageContainerChecks(cmc *ChannelMessageContainer, f func(c *ChannelMessageContainer) error) *ChannelMessageContainer {
	if cmc == nil {
		cmc = NewChannelMessageContainer()
		cmc.Err = ErrMessageIsNotSet
		return cmc
	}

	// do not process from now on, if the container has Err
	if cmc.Err != nil {
		return cmc
	}

	cmc.Err = f(cmc)

	return cmc
}

func (c *ChannelMessageContainer) Fetch(id int64, q *request.Query) error {
	if q.ShowExempt {
		cmc, err := BuildChannelMessageContainer(id, q)
		if err != nil {
			return err
		}
		c = cmc

	} else {
		if err := bongo.B.Fetch(c, id); err != nil {
			return err
		}

		return c.UpdateReplies(q).Err
	}

	return nil
}

func (c *ChannelMessageContainer) TableName() string {
	return "api.channel_message"
}

func (c *ChannelMessageContainer) GetId() int64 {
	if c.Message != nil {
		return c.Message.Id
	}

	return 0
}

func (c *ChannelMessageContainer) PopulateWith(m *ChannelMessage) *ChannelMessageContainer {
	c.Message = m
	c.AddAccountOldId()
	return c
}

func (cc *ChannelMessageContainer) AddAccountOldId() *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		if c.AccountOldId != "" {
			return c
		}

		oldId, err := FetchAccountOldIdByIdFromCache(c.Message.AccountId)
		if err != nil {
			c.Err = err
			return c
		}

		c.AccountOldId = oldId
	})
}

func (c *ChannelMessageContainer) SetGenerics(query *request.Query) *ChannelMessageContainer {
	c.AddReplies(query)
	c.AddRepliesCount(query)
	c.AddInteractions(query)
	return c
}

func (cc *ChannelMessageContainer) AddReplies(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		if c.Message != nil && c.Message.TypeConstant == ChannelMessage_TYPE_REPLY {
			// if message itself already a reply, no need to add replies to it
			return c
		}

		// fetch the replies
		mr := NewMessageReply()
		mr.MessageId = c.Message.Id

		q := query.Clone()
		q.Limit = query.ReplyLimit
		q.Skip = query.ReplySkip

		replies, err := mr.List(q)
		if err != nil {
			c.Err = err
			return c
		}

		// populate the replies as containers
		rs := NewChannelMessageContainers()
		rs.PopulateWith(replies, query)

		// set channel message containers
		c.Replies = *rs
		return c
	})

}

func (c *ChannelMessageContainer) UpdateReplies(q *request.Query) *ChannelMessageContainer {
	if len(c.Replies) > 0 {
		for i, _ := range c.Replies {
			if err := c.Replies[i].Fetch(c.Replies[i].GetId(), q); err != nil {
				c.Replies[i].Err = err
			}
		}
	}

	return c
}

func (cc *ChannelMessageContainer) AddRepliesCount(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		// fetch the replies
		mr := NewMessageReply()
		mr.MessageId = c.Message.Id

		repliesCount, err := mr.Count(query)
		c.Err = err
		c.RepliesCount = repliesCount

		return c
	})
}

func (cc *ChannelMessageContainer) AddInteractions(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		// get preview
		q := query.Clone()
		q.Type = "like"
		q.Limit = 3

		// if the message is reply do not add  isInteracted data
		if c.Message.TypeConstant == ChannelMessage_TYPE_REPLY {
			q.AddIsInteracted = false
		}

		i := NewInteraction()
		i.MessageId = c.Message.Id
		interactionContainer, err := i.FetchInteractionContainer(q)
		if err != nil {
			c.Err = err
			return c
		}

		c.Interactions[q.Type] = interactionContainer

		return c
	})
}

func (c *ChannelMessageContainer) AddIsInteracted(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		i := NewInteraction()
		i.MessageId = c.Message.Id
		isInteracted, err := i.IsInteracted(query.AccountId)
		if err != nil {
			c.Err = err
			return c
		}

		c.Interactions["like"].IsInteracted = isInteracted

		return c
	})
}

func (cc *ChannelMessageContainer) AddIsFollowed(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		isFollowed, err := c.Message.CheckIsMessageFollowed(query)
		c.IsFollowed = isFollowed
		c.Err = err
		return c
	})
}

func (c *ChannelMessageContainer) AddUnreadRepliesCount() *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		panic("method not implemented")
		return c
	})
}

type ChannelMessageContainers []ChannelMessageContainer

func NewChannelMessageContainers() *ChannelMessageContainers {
	return &ChannelMessageContainers{}
}

func (c *ChannelMessageContainers) PopulateWith(cms []ChannelMessage, query *request.Query) *ChannelMessageContainers {
	for i, _ := range cms {
		cmc := NewChannelMessageContainer()
		cmc.PopulateWith(&cms[i])
		cmc.SetGenerics(query)
		c.Add(cmc)
	}

	return c
}

func (c *ChannelMessageContainers) Add(containers ...*ChannelMessageContainer) *ChannelMessageContainers {
	for _, cc := range containers {
		*c = append(*c, *cc)
	}
	return c
}
<commit_msg>Social: fix problems with the go build<commit_after>package models

import (
	"socialapi/request"

	"github.com/koding/bongo"
)

type ChannelMessageContainer struct {
	Message      *ChannelMessage                  `json:"message"`
	Interactions map[string]*InteractionContainer `json:"interactions"`
	RepliesCount int                              `json:"repliesCount"`
	// Replies should stay as   ChannelMessageContainers
	// not as a pointer
	Replies            ChannelMessageContainers `json:"replies"`
	AccountOldId       string                   `json:"accountOldId"`
	IsFollowed         bool                     `json:"isFollowed"`
	UnreadRepliesCount int                      `json:"unreadRepliesCount,omitempty"`
	Err                error                    `json:"-"`
}

func NewChannelMessageContainer() *ChannelMessageContainer {
	container := &ChannelMessageContainer{}
	container.Interactions = make(map[string]*InteractionContainer)
	container.Interactions["like"] = NewInteractionContainer()

	return container
}

type InteractionContainer struct {
	IsInteracted  bool     `json:"isInteracted"`
	ActorsPreview []string `json:"actorsPreview"`
	ActorsCount   int      `json:"actorsCount"`
}

func NewInteractionContainer() *InteractionContainer {
	interactionContainer := &InteractionContainer{}
	interactionContainer.ActorsPreview = make([]string, 0)
	interactionContainer.IsInteracted = false
	interactionContainer.ActorsCount = 0

	return interactionContainer
}

func withChannelMessageContainerChecks(cmc *ChannelMessageContainer, f func(c *ChannelMessageContainer) error) *ChannelMessageContainer {
	if cmc == nil {
		cmc = NewChannelMessageContainer()
		cmc.Err = ErrMessageIsNotSet
		return cmc
	}

	if cmc.Message == nil {
		cmc.Err = ErrMessageIsNotSet
		return cmc
	}

	// do not process from now on, if the container has Err
	if cmc.Err != nil {
		return cmc
	}

	cmc.Err = f(cmc)

	return cmc
}

func (c *ChannelMessageContainer) Fetch(id int64, q *request.Query) error {
	if q.ShowExempt {
		cmc, err := BuildChannelMessageContainer(id, q)
		if err != nil {
			return err
		}
		*c = *cmc

	} else {
		if err := bongo.B.Fetch(c, id); err != nil {
			return err
		}

		return c.UpdateReplies(q).Err
	}

	return nil
}

func (c *ChannelMessageContainer) TableName() string {
	return "api.channel_message"
}

func (c *ChannelMessageContainer) GetId() int64 {
	if c.Message != nil {
		return c.Message.Id
	}

	return 0
}

func (c *ChannelMessageContainer) PopulateWith(m *ChannelMessage) *ChannelMessageContainer {
	c.Message = m
	c.AddAccountOldId()
	return c
}

func (cc *ChannelMessageContainer) AddAccountOldId() *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		if c.AccountOldId != "" {
			return nil
		}

		oldId, err := FetchAccountOldIdByIdFromCache(c.Message.AccountId)
		if err != nil {
			return err
		}

		c.AccountOldId = oldId

		return nil
	})
}

func (c *ChannelMessageContainer) SetGenerics(query *request.Query) *ChannelMessageContainer {
	c.AddReplies(query)
	c.AddRepliesCount(query)
	c.AddInteractions(query)
	return c
}

func (cc *ChannelMessageContainer) AddReplies(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		if c.Message.TypeConstant == ChannelMessage_TYPE_REPLY {
			// if message itself already a reply, no need to add replies to it
			return nil
		}

		// fetch the replies
		mr := NewMessageReply()
		mr.MessageId = c.Message.Id

		q := query.Clone()
		q.Limit = query.ReplyLimit
		q.Skip = query.ReplySkip

		replies, err := mr.List(q)
		if err != nil {
			return err
		}

		// populate the replies as containers
		rs := NewChannelMessageContainers()
		rs.PopulateWith(replies, query)

		// set channel message containers
		c.Replies = *rs
		return nil
	})

}

func (c *ChannelMessageContainer) UpdateReplies(q *request.Query) *ChannelMessageContainer {
	if len(c.Replies) > 0 {
		for i, _ := range c.Replies {
			if err := c.Replies[i].Fetch(c.Replies[i].GetId(), q); err != nil {
				c.Replies[i].Err = err
			}
		}
	}

	return c
}

func (cc *ChannelMessageContainer) AddRepliesCount(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		// fetch the replies
		mr := NewMessageReply()
		mr.MessageId = c.Message.Id

		repliesCount, err := mr.Count(query)
		if err != nil {
			return err
		}

		c.RepliesCount = repliesCount

		return nil
	})
}

func (cc *ChannelMessageContainer) AddInteractions(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {

		// get preview
		q := query.Clone()
		q.Type = "like"
		q.Limit = 3

		// if the message is reply do not add  isInteracted data
		if c.Message.TypeConstant == ChannelMessage_TYPE_REPLY {
			q.AddIsInteracted = false
		}

		i := NewInteraction()
		i.MessageId = c.Message.Id
		interactionContainer, err := i.FetchInteractionContainer(q)
		if err != nil {
			return err
		}

		c.Interactions[q.Type] = interactionContainer

		return nil
	})
}

func (cc *ChannelMessageContainer) AddIsInteracted(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		i := NewInteraction()
		i.MessageId = c.Message.Id
		isInteracted, err := i.IsInteracted(query.AccountId)
		if err != nil {
			return err
		}

		c.Interactions["like"].IsInteracted = isInteracted
		return nil
	})
}

func (cc *ChannelMessageContainer) AddIsFollowed(query *request.Query) *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		isFollowed, err := c.Message.CheckIsMessageFollowed(query)
		c.IsFollowed = isFollowed
		return err
	})
}

func (cc *ChannelMessageContainer) AddUnreadRepliesCount() *ChannelMessageContainer {
	return withChannelMessageContainerChecks(cc, func(c *ChannelMessageContainer) error {
		panic("method not implemented")
		return nil
	})
}

type ChannelMessageContainers []ChannelMessageContainer

func NewChannelMessageContainers() *ChannelMessageContainers {
	return &ChannelMessageContainers{}
}

func (ccs *ChannelMessageContainers) PopulateWith(cms []ChannelMessage, query *request.Query) *ChannelMessageContainers {
	for i, _ := range cms {
		cmc := NewChannelMessageContainer()
		cmc.PopulateWith(&cms[i])
		cmc.SetGenerics(query)
		ccs.Add(cmc)
	}

	return ccs
}

func (ccs *ChannelMessageContainers) Add(containers ...*ChannelMessageContainer) *ChannelMessageContainers {
	for _, cc := range containers {
		*ccs = append(*ccs, *cc)
	}

	return ccs
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"

	"socialapi/config"
	"socialapi/models"
	"socialapi/workers/common/metrics"

	"github.com/rcrowley/go-tigertonic"
)

var (
	// TODO allowed origins must be configurable
	cors = tigertonic.NewCORSBuilder().AddAllowedOrigins("*")
)

func Wrapper(handler interface{}, logName string, collectMetrics bool) http.Handler {
	return cors.Build(
		tigertonic.Timed(
			tigertonic.If(
				func(r *http.Request) (http.Header, error) {
					// this is an example
					// set group name to context
					tigertonic.Context(r).(*models.Context).GroupName = "koding"
					return nil, nil
				},
				CountedByStatus(
					tigertonic.Marshaled(handler), logName, collectMetrics,
				),
			),
			logName,
			nil,
		),
	)
}

//----------------------------------------------------------
// CounterByStatus
//----------------------------------------------------------

type CounterByStatus struct {
	name           string
	handler        http.Handler
	collectMetrics bool
}

func (c *CounterByStatus) ServeHTTP(w0 http.ResponseWriter, r *http.Request) {
	w := tigertonic.NewTeeHeaderResponseWriter(w0)
	c.handler.ServeHTTP(w, r)

	if w.StatusCode <= 300 {
		conf := config.MustGet()
		trackers := metrics.InitTrackers(
			metrics.NewMixpanelTracker(conf.Analytics.MixpanelToken),
		)

		if c.collectMetrics && conf.Analytics.Enabled {
			trackers.Track(c.name)
		}
	}
}

func CountedByStatus(handler http.Handler, name string, collectMetrics bool) *CounterByStatus {
	return &CounterByStatus{
		name:           name,
		handler:        handler,
		collectMetrics: collectMetrics,
	}
}
<commit_msg>Social: refactor sending tracking events<commit_after>package handler

import (
	"net/http"

	"socialapi/config"
	"socialapi/models"
	"socialapi/workers/common/metrics"

	"github.com/rcrowley/go-tigertonic"
)

var (
	// TODO allowed origins must be configurable
	cors     = tigertonic.NewCORSBuilder().AddAllowedOrigins("*")
	conf     *config.Config
	trackers *metrics.Trackers
)

func Wrapper(handler interface{}, logName string, collectMetrics bool) http.Handler {
	return cors.Build(
		tigertonic.Timed(
			tigertonic.If(
				func(r *http.Request) (http.Header, error) {
					// this is an example
					// set group name to context
					tigertonic.Context(r).(*models.Context).GroupName = "koding"
					return nil, nil
				},
				CountedByStatus(
					tigertonic.Marshaled(handler), logName, collectMetrics,
				),
			),
			logName,
			nil,
		),
	)
}

//----------------------------------------------------------
// CounterByStatus
//----------------------------------------------------------

type CounterByStatus struct {
	name           string
	handler        http.Handler
	collectMetrics bool
}

func (c *CounterByStatus) ServeHTTP(w0 http.ResponseWriter, r *http.Request) {
	w := tigertonic.NewTeeHeaderResponseWriter(w0)
	c.handler.ServeHTTP(w, r)

	if w.StatusCode <= 300 {
		c.track()
	}
}

func (c *CounterByStatus) track() {
	// don't log if analytics are disabled globally or for that endpoint
	if !c.collectMetrics && !conf.Analytics.Enabled {
		return
	}

	// set `conf` and `trackers` if either is not set
	if conf == nil || trackers == nil {
		conf = config.MustGet()

		trackers = metrics.InitTrackers(
			metrics.NewMixpanelTracker(conf.Analytics.MixpanelToken),
		)
	}

	trackers.Track(c.name)
}

func CountedByStatus(handler http.Handler, name string, collectMetrics bool) *CounterByStatus {
	return &CounterByStatus{
		name:           name,
		handler:        handler,
		collectMetrics: collectMetrics,
	}
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"io"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"time"
)

var Connection *mgo.Session

// just a static welcome handler
func welcomeHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "
Image Server.
")
	fmt.Fprintf(w, "")
}

//
func imageHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	database := vars["database"]

	if database == "" {
		log.Fatal("database must not be empty")
		return
	}

	port := vars["port"]

	if port == "" {
		port = "27017"
	}

	filename := vars["image"]

	if filename == "" {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	gridfs := Connection.DB(database).GridFS("fs")
	fp, err := gridfs.Open(filename)

	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	} else {
		// if the file pointer is not set, fp.Close() throws an error.. FIX this upstream?
		defer fp.Close()
	}

	md5 := fp.MD5()

	modifiedHeader := r.Header.Get("If-Modified-Since")
	modifiedTime := time.Now()
	cachingEnabled := r.Header.Get("Cache-Control") != "no-cache"

	if modifiedHeader != "" {
		modifiedHeader = ""
	} else {
		modifiedTime, _ = time.Parse(time.RFC1123, modifiedHeader)
	}

	if hasCached(md5, r.Header.Get("If-None-Match"), modifiedTime, fp.UploadDate()) && cachingEnabled {
		w.WriteHeader(http.StatusNotModified)
		fmt.Printf("[DEBUG][304] Returning cached image for %s\n", md5)
		return
	}

	w.Header().Set("Etag", md5)
	w.Header().Set("Cache-Control", "max-age=315360000")
	d, _ := time.ParseDuration("315360000s")

	expires := fp.UploadDate().Add(d)

	w.Header().Set("Last-Modified", fp.UploadDate().Format(time.RFC1123))
	w.Header().Set("Expires", expires.Format(time.RFC1123))
	w.Header().Set("Date", fp.UploadDate().Format(time.RFC1123))

	fmt.Printf("[DEBUG][200] Returning raw image for %s\n", md5)

	_, err = io.Copy(w, fp)

	HandleError(err)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Printf("[ERROR][500] Bad Request for %s\n", md5)
		return
	}
}

//
func Deliver() int {
	err := errors.New("")

	serverPort := flag.Int("port", 8000, "the server port where we will serve images")
	host := flag.String("host", "localhost", "the database host")

	flag.Parse()

	fmt.Printf("Server started. Listening on %d database host is %s\n", *serverPort, *host)

	// in order to simple configure the image server in the proxy configuration of nginx
	// we will be getting every database variable from the request
	serverRoute := "/{database}/{port}/{image}"

	Connection, err = mgo.Dial(*host)
	Connection.SetMode(mgo.Eventual, true)
	Connection.SetSyncTimeout(0)

	if err != nil {
		log.Fatal("Cannot connect to database")
		return -1
	}

	r := mux.NewRouter()
	r.HandleFunc("/", welcomeHandler)
	r.HandleFunc(serverRoute, imageHandler)

	http.Handle("/", r)

	err = http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), nil)

	if err != nil {
		log.Fatal(err)
		return -1
	}

	return 0
}
<commit_msg>adds missing function<commit_after>package server

import (
	"errors"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"io"
	"labix.org/v2/mgo"
	"log"
	"net/http"
	"time"
)

var Connection *mgo.Session

// just a static welcome handler
func welcomeHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "
Image Server.
")
	fmt.Fprintf(w, "")
}

func hasCached(etag string, md5 string, modifiedTime time.Time, updateTime time.Time) bool {
	if updateTime.After(modifiedTime) || md5 != etag {
		return false
	}

	return true
}

//
func imageHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	database := vars["database"]

	if database == "" {
		log.Fatal("database must not be empty")
		return
	}

	port := vars["port"]

	if port == "" {
		port = "27017"
	}

	filename := vars["image"]

	if filename == "" {
		w.WriteHeader(http.StatusNotFound)
		return
	}

	gridfs := Connection.DB(database).GridFS("fs")
	fp, err := gridfs.Open(filename)

	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	} else {
		// if the file pointer is not set, fp.Close() throws an error.. FIX this upstream?
		defer fp.Close()
	}

	md5 := fp.MD5()

	modifiedHeader := r.Header.Get("If-Modified-Since")
	modifiedTime := time.Now()
	cachingEnabled := r.Header.Get("Cache-Control") != "no-cache"

	if modifiedHeader != "" {
		modifiedHeader = ""
	} else {
		modifiedTime, _ = time.Parse(time.RFC1123, modifiedHeader)
	}

	if hasCached(md5, r.Header.Get("If-None-Match"), modifiedTime, fp.UploadDate()) && cachingEnabled {
		w.WriteHeader(http.StatusNotModified)
		fmt.Printf("[DEBUG][304] Returning cached image for %s\n", md5)
		return
	}

	w.Header().Set("Etag", md5)
	w.Header().Set("Cache-Control", "max-age=315360000")
	d, _ := time.ParseDuration("315360000s")

	expires := fp.UploadDate().Add(d)

	w.Header().Set("Last-Modified", fp.UploadDate().Format(time.RFC1123))
	w.Header().Set("Expires", expires.Format(time.RFC1123))
	w.Header().Set("Date", fp.UploadDate().Format(time.RFC1123))

	fmt.Printf("[DEBUG][200] Returning raw image for %s\n", md5)

	_, err = io.Copy(w, fp)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Printf("[ERROR][500] Bad Request for %s\n", md5)
		return
	}
}

//
func Deliver() int {
	err := errors.New("")

	serverPort := flag.Int("port", 8000, "the server port where we will serve images")
	host := flag.String("host", "localhost", "the database host")

	flag.Parse()

	fmt.Printf("Server started. Listening on %d database host is %s\n", *serverPort, *host)

	// in order to simple configure the image server in the proxy configuration of nginx
	// we will be getting every database variable from the request
	serverRoute := "/{database}/{port}/{image}"

	Connection, err = mgo.Dial(*host)
	Connection.SetMode(mgo.Eventual, true)
	Connection.SetSyncTimeout(0)

	if err != nil {
		log.Fatal("Cannot connect to database")
		return -1
	}

	r := mux.NewRouter()
	r.HandleFunc("/", welcomeHandler)
	r.HandleFunc(serverRoute, imageHandler)

	http.Handle("/", r)

	err = http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), nil)

	if err != nil {
		log.Fatal(err)
		return -1
	}

	return 0
}
<|endoftext|>