<commit_before>package app

import (
	_ "expvar"
	"gitcent-web/app/services"
	"net/http"

	"github.com/gitcent/revel-csrf"
	"github.com/revel/revel"
)

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		csrf.CSRFFilter,               // CSRF prevention.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		revel.ActionInvoker,           // Invoke the action.
	}
	revel.OnAppStart(func() {
		services.InitServices(revel.Config)
		go http.ListenAndServe(":1234", nil)
	})
	// register startup functions with OnAppStart
	// ( order dependent )
	// revel.OnAppStart(InitDB)
	// revel.OnAppStart(FillCache)
}

// TODO turn this into revel.HeaderFilter
// should probably also have a filter for CSRF
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
	// Add some common security headers
	c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
	c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
	c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")

	fc[0](c, fc[1:]) // Execute the next filter stage.
}
<commit_msg>exempt git clone/push url<commit_after>package app

import (
	_ "expvar"
	"gitcent-web/app/services"
	"net/http"

	"github.com/gitcent/revel-csrf"
	"github.com/revel/revel"
)

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		csrf.CSRFFilter,               // CSRF prevention.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		revel.ActionInvoker,           // Invoke the action.
	}
	//csrf.ExemptedFullPath("/eiyaya")
	csrf.ExemptedGlobs("/*/*/info/refs", "/*/*/git-receive-pack", "/*/*/git-upload-pack")
	revel.OnAppStart(func() {
		services.InitServices(revel.Config)
		go http.ListenAndServe(":1234", nil)
	})
	// register startup functions with OnAppStart
	// ( order dependent )
	// revel.OnAppStart(InitDB)
	// revel.OnAppStart(FillCache)
}

// TODO turn this into revel.HeaderFilter
// should probably also have a filter for CSRF
// not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) {
	// Add some common security headers
	c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN")
	c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block")
	c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff")

	fc[0](c, fc[1:]) // Execute the next filter stage.
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/mail"
	"appengine/urlfetch"

	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/nlopes/slack"
)

var router *mux.Router
var slackOAuthConfig OAuthConfig
var sessionStore *sessions.CookieStore
var sessionConfig SessionConfig
var styles map[string]template.CSS
var templates map[string]*Template

func init() {
	styles = loadStyles()
	templates = loadTemplates()
	sessionStore, sessionConfig = initSession()
	slackOAuthConfig = initSlackOAuthConfig()

	router = mux.NewRouter()
	router.Handle("/", AppHandler(indexHandler)).Name("index")

	router.Handle("/session/sign-in", AppHandler(signInHandler)).Name("sign-in").Methods("POST")
	router.Handle("/session/sign-out", AppHandler(signOutHandler)).Name("sign-out").Methods("POST")
	router.Handle("/slack/callback", AppHandler(slackOAuthCallbackHandler)).Name("slack-callback")

	router.Handle("/archive/send", SignedInAppHandler(sendArchiveHandler)).Name("send-archive").Methods("POST")
	router.Handle("/archive/cron", AppHandler(archiveCronHandler))
	router.Handle("/archive/conversation/send", SignedInAppHandler(sendConversationArchiveHandler)).Name("send-conversation-archive").Methods("POST")
	router.Handle("/archive/conversation/{type}/{ref}", SignedInAppHandler(conversationArchiveHandler)).Name("conversation-archive")

	http.Handle("/", router)
}

func indexHandler(w http.ResponseWriter, r *http.Request) *AppError {
	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	userId, ok := session.Values[sessionConfig.UserIdKey].(string)
	if !ok {
		data := map[string]interface{}{
			"ContinueUrl": r.FormValue("continue_url"),
		}
		return templates["index-signed-out"].Render(w, data)
	}
	c := appengine.NewContext(r)
	account, err := getAccount(c, userId)
	if account == nil {
		// Can't look up the account, session cookie must be invalid, clear it.
		session.Options.MaxAge = -1
		session.Save(r, w)
		return RedirectToRoute("index")
	}
	if err != nil {
		return InternalError(err, "Could not look up account")
	}

	slackClient := slack.New(account.ApiToken)

	user, err := slackClient.GetUserInfo(account.SlackUserId)
	if err != nil {
		return SlackFetchError(err, "user")
	}
	team, err := slackClient.GetTeamInfo()
	if err != nil {
		return SlackFetchError(err, "team")
	}
	conversations, err := getConversations(slackClient, account)
	if err != nil {
		return SlackFetchError(err, "conversations")
	}

	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err != nil {
		return SlackFetchError(err, "emails")
	}

	var settingsSummary = map[string]interface{}{
		"EmailAddress": emailAddress,
	}
	var data = map[string]interface{}{
		"User":            user,
		"Team":            team,
		"Conversations":   conversations,
		"SettingsSummary": settingsSummary,
		"DetectTimezone":  !account.HasTimezoneSet,
	}
	return templates["index"].Render(w, data, &AppSignedInState{
		Account:        account,
		SlackClient:    slackClient,
		session:        session,
		responseWriter: w,
		request:        r,
	})
}

func signInHandler(w http.ResponseWriter, r *http.Request) *AppError {
	authCodeUrl, _ := url.Parse("https://slack.com/oauth/authorize")
	authCodeUrlQuery := authCodeUrl.Query()
	authCodeUrlQuery.Set("client_id", slackOAuthConfig.ClientId)
	authCodeUrlQuery.Set("scope",
		// Basic user info
		"users:read "+
			// Team info
			"team:read "+
			// Channel archive
			"channels:read channels:history "+
			// Private channel archive
			"groups:read groups:history "+
			// Direct message archive
			"im:read im:history "+
			// Multi-party direct mesage archive
			"mpim:read mpim:history")
	redirectUrlString, _ := AbsoluteRouteUrl("slack-callback")
	redirectUrl, _ := url.Parse(redirectUrlString)
	if continueUrl := r.FormValue("continue_url"); continueUrl != "" {
		redirectUrlQuery := redirectUrl.Query()
		redirectUrlQuery.Set("continue_url", continueUrl)
		redirectUrl.RawQuery = redirectUrlQuery.Encode()
	}
	authCodeUrlQuery.Set("redirect_uri", redirectUrl.String())
	authCodeUrl.RawQuery = authCodeUrlQuery.Encode()
	return RedirectToUrl(authCodeUrl.String())
}

func signOutHandler(w http.ResponseWriter, r *http.Request) *AppError {
	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	session.Options.MaxAge = -1
	session.Save(r, w)
	return RedirectToRoute("index")
}

func slackOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) *AppError {
	code := r.FormValue("code")
	redirectUrl := AbsolutePathUrl(r.URL.Path)
	token, _, err := slack.GetOAuthToken(
		slackOAuthConfig.ClientId, slackOAuthConfig.ClientSecret, code,
		redirectUrl, false)
	if err != nil {
		return InternalError(err, "Could not exchange OAuth code")
	}

	slackClient := slack.New(token)
	authTest, err := slackClient.AuthTest()
	if err != nil {
		return SlackFetchError(err, "user")
	}

	if authTest.Team != "Partyslack" {
		return templates["team-not-on-whitelist"].Render(w, map[string]interface{}{})
	}

	c := appengine.NewContext(r)
	account, err := getAccount(c, authTest.UserID)
	if err != nil && err != datastore.ErrNoSuchEntity {
		return InternalError(err, "Could not look up user")
	}
	if account == nil {
		account = &Account{
			SlackUserId:   authTest.UserID,
			SlackTeamName: authTest.Team,
			SlackTeamUrl:  authTest.URL,
		}
	}
	account.ApiToken = token
	// Persist the default email address now, both to avoid additional lookups
	// later and to have a way to contact the user if they ever revoke their
	// OAuth token.
	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err == nil && len(emailAddress) > 0 {
		account.DigestEmailAddress = emailAddress
	}
	err = account.Put(c)
	if err != nil {
		return InternalError(err, "Could not save user")
	}

	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	session.Values[sessionConfig.UserIdKey] = account.SlackUserId
	session.Save(r, w)
	continueUrl := r.FormValue("continue_url")
	if continueUrl != "" {
		continueUrlParsed, err := url.Parse(continueUrl)
		if err != nil || continueUrlParsed.Host != r.URL.Host {
			continueUrl = ""
		}
	}
	if continueUrl == "" {
		indexUrl, _ := router.Get("index").URL()
		continueUrl = indexUrl.String()
	}
	return RedirectToUrl(continueUrl)
}

func conversationArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	vars := mux.Vars(r)
	conversationType := vars["type"]
	ref := vars["ref"]
	conversation, err := getConversationFromRef(conversationType, ref, state.SlackClient)
	if err != nil {
		return SlackFetchError(err, "conversation")
	}

	archive, err := newConversationArchive(conversation, state.SlackClient, state.Account)
	if err != nil {
		return SlackFetchError(err, "archive")
	}

	var data = map[string]interface{}{
		"Conversation":        conversation,
		"ConversationType":    conversationType,
		"ConversationRef":     ref,
		"ConversationArchive": archive,
	}
	return templates["conversation-archive-page"].Render(w, data, state)
}

func sendArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	c := appengine.NewContext(r)
	sentCount, err := sendArchive(state.Account, c)
	if err != nil {
		return InternalError(err, "Could not send archive")
	}
	if sentCount > 0 {
		if sentCount == 1 {
			state.AddFlash("Emailed 1 archive!")
		} else {
			state.AddFlash(fmt.Sprintf("Emailed %d archives!", sentCount))
		}
	} else {
		state.AddFlash("No archives were sent, they were either all empty or disabled.")
	}
	return RedirectToRoute("index")
}

func archiveCronHandler(w http.ResponseWriter, r *http.Request) *AppError {
	c := appengine.NewContext(r)
	accounts, err := getAllAccounts(c)
	if err != nil {
		return InternalError(err, "Could not look up accounts")
	}
	for _, account := range accounts {
		c.Infof("Enqueing task for %s...", account.SlackUserId)
		sendArchiveFunc.Call(c, account.SlackUserId)
	}
	fmt.Fprint(w, "Done")
	return nil
}

var sendArchiveFunc = delay.Func(
	"sendArchive",
	func(c appengine.Context, slackUserId string) error {
		c.Infof("Sending digest for %s...", slackUserId)
		account, err := getAccount(c, slackUserId)
		if err != nil {
			c.Errorf("  Error looking up account: %s", err.Error())
			return err
		}
		// The Slack API uses the default HTTP transport, so we need to override
		// it to get it to work on App Engine. This is normally done for all
		// handlers, but since we're in a delay function that code has not run.
		appengineTransport := &urlfetch.Transport{Context: c}
		appengineTransport.Deadline = time.Second * 60
		http.DefaultTransport = &CachingTransport{
			Transport: appengineTransport,
			Context:   c,
		}
		sentCount, err := sendArchive(account, c)
		if err != nil {
			c.Errorf("  Error: %s", err.Error())
			if !appengine.IsDevAppServer() {
				sendArchiveErrorMail(err, c, slackUserId)
			}
		} else if sentCount > 0 {
			c.Infof(fmt.Sprintf("  Sent %d archives!", sentCount))
		} else {
			c.Infof("  Not sent, archive was empty")
		}
		return err
	})

func sendArchive(account *Account, c appengine.Context) (int, error) {
	slackClient := slack.New(account.ApiToken)
	conversations, err := getConversations(slackClient, account)
	if err != nil {
		return 0, err
	}
	sentCount := 0
	for _, conversation := range conversations.AllConversations {
		sent, err := sendConversationArchive(conversation, account, c)
		if err != nil {
			return sentCount, err
		}
		if sent {
			sentCount++
		}
	}
	return sentCount, nil
}

func sendArchiveErrorMail(e error, c appengine.Context, slackUserId string) {
	errorMessage := &mail.Message{
		Sender:  "Slack Archive Admin <admin@slack-archive.appspotmail.com>",
		To:      []string{"mihai.parparita@gmail.com"},
		Subject: fmt.Sprintf("Slack Archive Send Error for %s", slackUserId),
		Body:    fmt.Sprintf("Error: %s", e),
	}
	err := mail.Send(c, errorMessage)
	if err != nil {
		c.Errorf("Error %s sending error email.", err.Error())
	}
}

func sendConversationArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	conversationType := r.FormValue("conversation_type")
	ref := r.FormValue("conversation_ref")
	conversation, err := getConversationFromRef(conversationType, ref, state.SlackClient)
	if err != nil {
		return SlackFetchError(err, "conversation")
	}
	c := appengine.NewContext(r)
	sent, err := sendConversationArchive(conversation, state.Account, c)
	if err != nil {
		return InternalError(err, "Could not send conversation archive")
	}
	if sent {
		state.AddFlash("Emailed archive!")
	} else {
		state.AddFlash("No archive was sent, it was empty or disabled.")
	}
	return RedirectToRoute("conversation-archive", "type", conversationType, "ref", ref)
}

func sendConversationArchive(conversation Conversation, account *Account, c appengine.Context) (bool, error) {
	slackClient := slack.New(account.ApiToken)
	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err != nil {
		return false, err
	}
	if emailAddress == "disabled" {
		return false, nil
	}
	archive, err := newConversationArchive(conversation, slackClient, account)
	if err != nil {
		return false, err
	}
	if archive.Empty() {
		return false, nil
	}
	var data = map[string]interface{}{
		"ConversationArchive": archive,
	}
	var archiveHtml bytes.Buffer
	if err := templates["conversation-archive-email"].Execute(&archiveHtml, data); err != nil {
		return false, err
	}
	team, err := slackClient.GetTeamInfo()
	if err != nil {
		return false, err
	}
	sender := fmt.Sprintf(
		"%s Slack Archive <archive@slack-archive.appspotmail.com>", team.Name)
	archiveMessage := &mail.Message{
		Sender:   sender,
		To:       []string{emailAddress},
		Subject:  fmt.Sprintf("%s Archive", conversation.Name()),
		HTMLBody: archiveHtml.String(),
	}
	err = mail.Send(c, archiveMessage)
	return true, err
}
<commit_msg>Use a task per conversation when sending an archive.<commit_after>package main

import (
	"bytes"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/mail"
	"appengine/urlfetch"

	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/nlopes/slack"
)

var router *mux.Router
var slackOAuthConfig OAuthConfig
var sessionStore *sessions.CookieStore
var sessionConfig SessionConfig
var styles map[string]template.CSS
var templates map[string]*Template

func init() {
	styles = loadStyles()
	templates = loadTemplates()
	sessionStore, sessionConfig = initSession()
	slackOAuthConfig = initSlackOAuthConfig()

	router = mux.NewRouter()
	router.Handle("/", AppHandler(indexHandler)).Name("index")

	router.Handle("/session/sign-in", AppHandler(signInHandler)).Name("sign-in").Methods("POST")
	router.Handle("/session/sign-out", AppHandler(signOutHandler)).Name("sign-out").Methods("POST")
	router.Handle("/slack/callback", AppHandler(slackOAuthCallbackHandler)).Name("slack-callback")

	router.Handle("/archive/send", SignedInAppHandler(sendArchiveHandler)).Name("send-archive").Methods("POST")
	router.Handle("/archive/cron", AppHandler(archiveCronHandler))
	router.Handle("/archive/conversation/send", SignedInAppHandler(sendConversationArchiveHandler)).Name("send-conversation-archive").Methods("POST")
	router.Handle("/archive/conversation/{type}/{ref}", SignedInAppHandler(conversationArchiveHandler)).Name("conversation-archive")

	http.Handle("/", router)
}

func indexHandler(w http.ResponseWriter, r *http.Request) *AppError {
	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	userId, ok := session.Values[sessionConfig.UserIdKey].(string)
	if !ok {
		data := map[string]interface{}{
			"ContinueUrl": r.FormValue("continue_url"),
		}
		return templates["index-signed-out"].Render(w, data)
	}
	c := appengine.NewContext(r)
	account, err := getAccount(c, userId)
	if account == nil {
		// Can't look up the account, session cookie must be invalid, clear it.
		session.Options.MaxAge = -1
		session.Save(r, w)
		return RedirectToRoute("index")
	}
	if err != nil {
		return InternalError(err, "Could not look up account")
	}

	slackClient := slack.New(account.ApiToken)

	user, err := slackClient.GetUserInfo(account.SlackUserId)
	if err != nil {
		return SlackFetchError(err, "user")
	}
	team, err := slackClient.GetTeamInfo()
	if err != nil {
		return SlackFetchError(err, "team")
	}
	conversations, err := getConversations(slackClient, account)
	if err != nil {
		return SlackFetchError(err, "conversations")
	}

	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err != nil {
		return SlackFetchError(err, "emails")
	}

	var settingsSummary = map[string]interface{}{
		"EmailAddress": emailAddress,
	}
	var data = map[string]interface{}{
		"User":            user,
		"Team":            team,
		"Conversations":   conversations,
		"SettingsSummary": settingsSummary,
		"DetectTimezone":  !account.HasTimezoneSet,
	}
	return templates["index"].Render(w, data, &AppSignedInState{
		Account:        account,
		SlackClient:    slackClient,
		session:        session,
		responseWriter: w,
		request:        r,
	})
}

func signInHandler(w http.ResponseWriter, r *http.Request) *AppError {
	authCodeUrl, _ := url.Parse("https://slack.com/oauth/authorize")
	authCodeUrlQuery := authCodeUrl.Query()
	authCodeUrlQuery.Set("client_id", slackOAuthConfig.ClientId)
	authCodeUrlQuery.Set("scope",
		// Basic user info
		"users:read "+
			// Team info
			"team:read "+
			// Channel archive
			"channels:read channels:history "+
			// Private channel archive
			"groups:read groups:history "+
			// Direct message archive
			"im:read im:history "+
			// Multi-party direct mesage archive
			"mpim:read mpim:history")
	redirectUrlString, _ := AbsoluteRouteUrl("slack-callback")
	redirectUrl, _ := url.Parse(redirectUrlString)
	if continueUrl := r.FormValue("continue_url"); continueUrl != "" {
		redirectUrlQuery := redirectUrl.Query()
		redirectUrlQuery.Set("continue_url", continueUrl)
		redirectUrl.RawQuery = redirectUrlQuery.Encode()
	}
	authCodeUrlQuery.Set("redirect_uri", redirectUrl.String())
	authCodeUrl.RawQuery = authCodeUrlQuery.Encode()
	return RedirectToUrl(authCodeUrl.String())
}

func signOutHandler(w http.ResponseWriter, r *http.Request) *AppError {
	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	session.Options.MaxAge = -1
	session.Save(r, w)
	return RedirectToRoute("index")
}

func slackOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) *AppError {
	code := r.FormValue("code")
	redirectUrl := AbsolutePathUrl(r.URL.Path)
	token, _, err := slack.GetOAuthToken(
		slackOAuthConfig.ClientId, slackOAuthConfig.ClientSecret, code,
		redirectUrl, false)
	if err != nil {
		return InternalError(err, "Could not exchange OAuth code")
	}

	slackClient := slack.New(token)
	authTest, err := slackClient.AuthTest()
	if err != nil {
		return SlackFetchError(err, "user")
	}

	if authTest.Team != "Partyslack" {
		return templates["team-not-on-whitelist"].Render(w, map[string]interface{}{})
	}

	c := appengine.NewContext(r)
	account, err := getAccount(c, authTest.UserID)
	if err != nil && err != datastore.ErrNoSuchEntity {
		return InternalError(err, "Could not look up user")
	}
	if account == nil {
		account = &Account{
			SlackUserId:   authTest.UserID,
			SlackTeamName: authTest.Team,
			SlackTeamUrl:  authTest.URL,
		}
	}
	account.ApiToken = token
	// Persist the default email address now, both to avoid additional lookups
	// later and to have a way to contact the user if they ever revoke their
	// OAuth token.
	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err == nil && len(emailAddress) > 0 {
		account.DigestEmailAddress = emailAddress
	}
	err = account.Put(c)
	if err != nil {
		return InternalError(err, "Could not save user")
	}

	session, _ := sessionStore.Get(r, sessionConfig.CookieName)
	session.Values[sessionConfig.UserIdKey] = account.SlackUserId
	session.Save(r, w)
	continueUrl := r.FormValue("continue_url")
	if continueUrl != "" {
		continueUrlParsed, err := url.Parse(continueUrl)
		if err != nil || continueUrlParsed.Host != r.URL.Host {
			continueUrl = ""
		}
	}
	if continueUrl == "" {
		indexUrl, _ := router.Get("index").URL()
		continueUrl = indexUrl.String()
	}
	return RedirectToUrl(continueUrl)
}

func conversationArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	vars := mux.Vars(r)
	conversationType := vars["type"]
	ref := vars["ref"]
	conversation, err := getConversationFromRef(conversationType, ref, state.SlackClient)
	if err != nil {
		return SlackFetchError(err, "conversation")
	}

	archive, err := newConversationArchive(conversation, state.SlackClient, state.Account)
	if err != nil {
		return SlackFetchError(err, "archive")
	}

	var data = map[string]interface{}{
		"Conversation":        conversation,
		"ConversationType":    conversationType,
		"ConversationRef":     ref,
		"ConversationArchive": archive,
	}
	return templates["conversation-archive-page"].Render(w, data, state)
}

func sendArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	c := appengine.NewContext(r)
	sentCount, err := sendArchive(state.Account, c)
	if err != nil {
		return InternalError(err, "Could not send archive")
	}
	if sentCount > 0 {
		if sentCount == 1 {
			state.AddFlash("Emailed 1 archive!")
		} else {
			state.AddFlash(fmt.Sprintf("Emailed %d archives!", sentCount))
		}
	} else {
		state.AddFlash("No archives were sent, they were either all empty or disabled.")
	}
	return RedirectToRoute("index")
}

func archiveCronHandler(w http.ResponseWriter, r *http.Request) *AppError {
	c := appengine.NewContext(r)
	accounts, err := getAllAccounts(c)
	if err != nil {
		return InternalError(err, "Could not look up accounts")
	}
	for _, account := range accounts {
		c.Infof("Enqueing task for %s...", account.SlackUserId)
		sendArchiveFunc.Call(c, account.SlackUserId)
	}
	fmt.Fprint(w, "Done")
	return nil
}

var sendArchiveFunc = delay.Func(
	"sendArchive",
	func(c appengine.Context, slackUserId string) error {
		c.Infof("Sending digest for %s...", slackUserId)
		account, err := getAccount(c, slackUserId)
		if err != nil {
			c.Errorf("  Error looking up account: %s", err.Error())
			return err
		}
		// The Slack API uses the default HTTP transport, so we need to override
		// it to get it to work on App Engine. This is normally done for all
		// handlers, but since we're in a delay function that code has not run.
		appengineTransport := &urlfetch.Transport{Context: c}
		appengineTransport.Deadline = time.Second * 60
		http.DefaultTransport = &CachingTransport{
			Transport: appengineTransport,
			Context:   c,
		}
		slackClient := slack.New(account.ApiToken)
		conversations, err := getConversations(slackClient, account)
		if err != nil {
			c.Errorf("  Error looking up conversations: %s", err.Error())
			if !appengine.IsDevAppServer() {
				sendArchiveErrorMail(err, c, slackUserId)
			}
			return err
		}
		if len(conversations.AllConversations) > 0 {
			for _, conversation := range conversations.AllConversations {
				conversationType, ref := conversation.ToRef()
				sendConversationArchiveFunc.Call(
					c, account.SlackUserId, conversationType, ref)
			}
			c.Infof("  Enqueued %d conversation archives.", len(conversations.AllConversations))
		} else {
			c.Infof("  Not sent, no conversations found.")
		}
		return nil
	})

var sendConversationArchiveFunc = delay.Func(
	"sendConversationArchive",
	func(c appengine.Context, slackUserId string, conversationType string, ref string) error {
		c.Infof("Sending archive for %s conversation %s %s...",
			slackUserId, conversationType, ref)
		account, err := getAccount(c, slackUserId)
		if err != nil {
			c.Errorf("  Error looking up account: %s", err.Error())
			return err
		}
		// The Slack API uses the default HTTP transport, so we need to override
		// it to get it to work on App Engine. This is normally done for all
		// handlers, but since we're in a delay function that code has not run.
		appengineTransport := &urlfetch.Transport{Context: c}
		appengineTransport.Deadline = time.Second * 60
		http.DefaultTransport = &CachingTransport{
			Transport: appengineTransport,
			Context:   c,
		}
		slackClient := slack.New(account.ApiToken)
		conversation, err := getConversationFromRef(conversationType, ref, slackClient)
		if err != nil {
			c.Errorf("  Error looking up conversation: %s", err.Error())
			if !appengine.IsDevAppServer() {
				sendArchiveErrorMail(err, c, slackUserId)
			}
			return err
		}
		sent, err := sendConversationArchive(conversation, account, c)
		if err != nil {
			c.Errorf("  Error sending conversation archive: %s", err.Error())
			if !appengine.IsDevAppServer() {
				sendArchiveErrorMail(err, c, slackUserId)
			}
			return err
		}
		if sent {
			c.Infof("  Sent!")
		} else {
			c.Infof("  Not sent, archive was empty.")
		}
		return nil
	})

func sendArchive(account *Account, c appengine.Context) (int, error) {
	slackClient := slack.New(account.ApiToken)
	conversations, err := getConversations(slackClient, account)
	if err != nil {
		return 0, err
	}
	sentCount := 0
	for _, conversation := range conversations.AllConversations {
		sent, err := sendConversationArchive(conversation, account, c)
		if err != nil {
			return sentCount, err
		}
		if sent {
			sentCount++
		}
	}
	return sentCount, nil
}

func sendArchiveErrorMail(e error, c appengine.Context, slackUserId string) {
	errorMessage := &mail.Message{
		Sender:  "Slack Archive Admin <admin@slack-archive.appspotmail.com>",
		To:      []string{"mihai.parparita@gmail.com"},
		Subject: fmt.Sprintf("Slack Archive Send Error for %s", slackUserId),
		Body:    fmt.Sprintf("Error: %s", e),
	}
	err := mail.Send(c, errorMessage)
	if err != nil {
		c.Errorf("Error %s sending error email.", err.Error())
	}
}

func sendConversationArchiveHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError {
	conversationType := r.FormValue("conversation_type")
	ref := r.FormValue("conversation_ref")
	conversation, err := getConversationFromRef(conversationType, ref, state.SlackClient)
	if err != nil {
		return SlackFetchError(err, "conversation")
	}
	c := appengine.NewContext(r)
	sent, err := sendConversationArchive(conversation, state.Account, c)
	if err != nil {
		return InternalError(err, "Could not send conversation archive")
	}
	if sent {
		state.AddFlash("Emailed archive!")
	} else {
		state.AddFlash("No archive was sent, it was empty or disabled.")
	}
	return RedirectToRoute("conversation-archive", "type", conversationType, "ref", ref)
}

func sendConversationArchive(conversation Conversation, account *Account, c appengine.Context) (bool, error) {
	slackClient := slack.New(account.ApiToken)
	emailAddress, err := account.GetDigestEmailAddress(slackClient)
	if err != nil {
		return false, err
	}
	if emailAddress == "disabled" {
		return false, nil
	}
	archive, err := newConversationArchive(conversation, slackClient, account)
	if err != nil {
		return false, err
	}
	if archive.Empty() {
		return false, nil
	}
	var data = map[string]interface{}{
		"ConversationArchive": archive,
	}
	var archiveHtml bytes.Buffer
	if err := templates["conversation-archive-email"].Execute(&archiveHtml, data); err != nil {
		return false, err
	}
	team, err := slackClient.GetTeamInfo()
	if err != nil {
		return false, err
	}
	sender := fmt.Sprintf(
		"%s Slack Archive <archive@slack-archive.appspotmail.com>", team.Name)
	archiveMessage := &mail.Message{
		Sender:   sender,
		To:       []string{emailAddress},
		Subject:  fmt.Sprintf("%s Archive", conversation.Name()),
		HTMLBody: archiveHtml.String(),
	}
	err = mail.Send(c, archiveMessage)
	return true, err
}
<|endoftext|>


<commit_before>package main

import (
	"dokugen/sudoku"
	"flag"
)

//TODO: let people pass in a filename to export to.

var GENERATE bool
var HELP bool
var PUZZLE_TO_SOLVE string
var NUM int

func main() {

	flag.BoolVar(&GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&NUM, "n", 1, "Number of things to generate")
	flag.StringVar(&PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")

	flag.Parse()

	if HELP {
		flag.PrintDefaults()
		return
	}

	if GENERATE {
		for i := 0; i < NUM; i++ {
			grid := sudoku.GenerateGrid()
			print(grid.DataString())
			print("\n\n")
		}
		return
	}

	if PUZZLE_TO_SOLVE != "" {
		grid := sudoku.NewGrid()
		grid.LoadFromFile(PUZZLE_TO_SOLVE)
		//TODO: detect if the load failed.
		grid.Solve()
		print(grid.DataString())
		return
	}

	//If we get to here, print defaults.
	flag.PrintDefaults()

}
<commit_msg>Made it so we print difficult by default.<commit_after>package main

import (
	"dokugen/sudoku"
	"flag"
)

//TODO: let people pass in a filename to export to.

var GENERATE bool
var HELP bool
var PUZZLE_TO_SOLVE string
var NUM int

func main() {

	flag.BoolVar(&GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&NUM, "n", 1, "Number of things to generate")
	flag.StringVar(&PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")

	flag.Parse()

	if HELP {
		flag.PrintDefaults()
		return
	}

	if GENERATE {
		for i := 0; i < NUM; i++ {
			grid := sudoku.GenerateGrid()
			print(grid.DataString())
			print("\n\n")
			print(grid.Difficulty())
			print("\n\n")
		}
		return
	}

	if PUZZLE_TO_SOLVE != "" {
		grid := sudoku.NewGrid()
		grid.LoadFromFile(PUZZLE_TO_SOLVE)
		//TODO: detect if the load failed.
		grid.Solve()
		print(grid.DataString())
		return
	}

	//If we get to here, print defaults.
	flag.PrintDefaults()

}
<|endoftext|>


<commit_before>//
// Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package server

// Helper functions for handling queries.

import (
	"errors"
	"fmt"
	"log"
	"strings"
	"time"
	"unicode"

	"github.com/sysdb/go/proto"
	"github.com/sysdb/go/sysdb"
)

func listAll(req request, s *Server) (*page, error) {
	if len(req.args) != 0 {
		return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
	}

	res, err := s.query("LIST %s", identifier(req.cmd))
	if err != nil {
		return nil, err
	}
	// the template *must* exist
	return tmpl(s.results[req.cmd], res)
}

func lookup(req request, s *Server) (*page, error) {
	if req.r.Method != "POST" {
		return nil, errors.New("Method not allowed")
	}
	tokens, err := tokenize(req.r.PostForm.Get("query"))
	if err != nil {
		return nil, err
	}
	if len(tokens) == 0 {
		return nil, errors.New("Empty query")
	}

	typ := "hosts"
	var args string
	for i, tok := range tokens {
		if len(args) > 0 {
			args += " AND"
		}

		if fields := strings.SplitN(tok, ":", 2); len(fields) == 2 {
			if i == 0 && fields[1] == "" {
				typ = fields[0]
			} else {
				args += fmt.Sprintf(" attribute[%s] = %s",
					proto.EscapeString(fields[0]), proto.EscapeString(fields[1]))
			}
		} else {
			args += fmt.Sprintf(" name =~ %s", proto.EscapeString(tok))
		}
	}

	res, err := s.query("LOOKUP %s MATCHING"+args, identifier(typ))
	if err != nil {
		return nil, err
	}
	if t, ok := s.results[typ]; ok {
		return tmpl(t, res)
	}
	return nil, fmt.Errorf("Unsupported type %s", typ)
}

func fetch(req request, s *Server) (*page, error) {
	if len(req.args) == 0 {
		return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
	}

	var res interface{}
	var err error
	switch req.cmd {
	case "host":
		if len(req.args) != 1 {
			return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
		}
		res, err = s.query("FETCH host %s", req.args[0])
	case "service", "metric":
		if len(req.args) != 2 {
			return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
		}
		res, err = s.query("FETCH %s %s.%s", identifier(req.cmd), req.args[0], req.args[1])
		if err == nil && req.cmd == "metric" {
			return metric(req, res, s)
		}
	default:
		panic("Unknown request: fetch(" + req.cmd + ")")
	}
	if err != nil {
		return nil, err
	}
	return tmpl(s.results[req.cmd], res)
}

var datetime = "2006-01-02 15:04:05"

func metric(req request, res interface{}, s *Server) (*page, error) {
	start := time.Now().Add(-24 * time.Hour)
	end := time.Now()
	if req.r.Method == "POST" {
		var err error
		// Parse the values first to verify their format.
		if s := req.r.PostForm.Get("start_date"); s != "" {
			if start, err = time.Parse(datetime, s); err != nil {
				return nil, fmt.Errorf("Invalid start time %q", s)
			}
		}
		if e := req.r.PostForm.Get("end_date"); e != "" {
			if end, err = time.Parse(datetime, e); err != nil {
				return nil, fmt.Errorf("Invalid end time %q", e)
			}
		}
	}

	p := struct {
		StartTime string
		EndTime   string
		URLStart  string
		URLEnd    string
		Data      interface{}
	}{
		start.Format(datetime),
		end.Format(datetime),
		start.Format(urldate),
		end.Format(urldate),
		res,
	}
	return tmpl(s.results["metric"], &p)
}

// tokenize split the string s into its tokens where a token is either a quoted
// string or surrounded by one or more consecutive whitespace characters.
func tokenize(s string) ([]string, error) {
	scan := scanner{}
	tokens := []string{}
	start := -1
	for i, r := range s {
		if !scan.inField(r) {
			if start == -1 {
				// Skip leading and consecutive whitespace.
				continue
			}
			tok, err := unescape(s[start:i])
			if err != nil {
				return nil, err
			}
			tokens = append(tokens, tok)
			start = -1
		} else if start == -1 {
			// Found a new field.
			start = i
		}
	}
	if start >= 0 {
		// Last (or possibly only) field.
		tok, err := unescape(s[start:])
		if err != nil {
			return nil, err
		}
		tokens = append(tokens, tok)
	}

	if scan.inQuotes {
		return nil, errors.New("quoted string not terminated")
	}
	if scan.escaped {
		return nil, errors.New("illegal character escape at end of string")
	}
	return tokens, nil
}

func unescape(s string) (string, error) {
	var unescaped []byte
	var i, n int
	for i = 0; i < len(s); i++ {
		if s[i] != '\\' {
			n++
			continue
		}

		if i >= len(s) {
			return "", errors.New("illegal character escape at end of string")
		}
		if s[i+1] != ' ' && s[i+1] != '"' && s[i+1] != '\\' {
			// Allow simple escapes only for now.
			return "", fmt.Errorf("illegal character escape \\%c", s[i+1])
		}
		if unescaped == nil {
			unescaped = []byte(s)
		}
		copy(unescaped[n:], s[i+1:])
	}

	if unescaped != nil {
		return string(unescaped[:n]), nil
	}
	return s, nil
}

type scanner struct {
	inQuotes bool
	escaped  bool
}

func (s *scanner) inField(r rune) bool {
	if s.escaped {
		s.escaped = false
		return true
	}
	if r == '\\' {
		s.escaped = true
		return true
	}
	if s.inQuotes {
		if r == '"' {
			s.inQuotes = false
			return false
		}
		return true
	}
	if r == '"' {
		s.inQuotes = true
		return false
	}
	return !unicode.IsSpace(r)
}

type identifier string

func (s *Server) query(cmd string, args ...interface{}) (interface{}, error) {
	c := <-s.conns
	defer func() { s.conns <- c }()

	for i, arg := range args {
		switch v := arg.(type) {
		case identifier:
			// Nothing to do.
		case string:
			args[i] = proto.EscapeString(v)
		case time.Time:
			args[i] = v.Format(datetime)
		default:
			panic(fmt.Sprintf("query: invalid type %T", arg))
		}
	}

	cmd = fmt.Sprintf(cmd, args...)
	m := &proto.Message{
		Type: proto.ConnectionQuery,
		Raw:  []byte(cmd),
	}
	if err := c.Send(m); err != nil {
		return nil, fmt.Errorf("Query %q: %v", cmd, err)
	}

	for {
		m, err := c.Receive()
		if err != nil {
			return nil, fmt.Errorf("Failed to receive server response: %v", err)
		}
		if m.Type == proto.ConnectionLog {
			log.Println(string(m.Raw[4:]))
			continue
		} else if m.Type == proto.ConnectionError {
			return nil, errors.New(string(m.Raw))
		}

		t, err := m.DataType()
		if err != nil {
			return nil, fmt.Errorf("Failed to unmarshal response: %v", err)
		}

		var res interface{}
		switch t {
		case proto.HostList:
			var hosts []sysdb.Host
			err = proto.Unmarshal(m, &hosts)
			res = hosts
		case proto.Host:
			var host sysdb.Host
			err = proto.Unmarshal(m, &host)
			res = host
		case proto.Timeseries:
			var ts sysdb.Timeseries
			err = proto.Unmarshal(m, &ts)
			res = ts
		default:
			return nil, fmt.Errorf("Unsupported data type %d", t)
		}
		if err != nil {
			return nil, fmt.Errorf("Failed to unmarshal response: %v", err)
		}
		return res, nil
	}
}

// vim: set tw=78 sw=4 sw=4 noexpandtab :
<commit_msg>Add support for host.<attribute> queries.<commit_after>//
// Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package server

// Helper functions for handling queries.

import (
	"errors"
	"fmt"
	"log"
	"strings"
	"time"
	"unicode"

	"github.com/sysdb/go/proto"
	"github.com/sysdb/go/sysdb"
)

func listAll(req request, s *Server) (*page, error) {
	if len(req.args) != 0 {
		return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
	}

	res, err := s.query("LIST %s", identifier(req.cmd))
	if err != nil {
		return nil, err
	}
	// the template *must* exist
	return tmpl(s.results[req.cmd], res)
}

func lookup(req request, s *Server) (*page, error) {
	if req.r.Method != "POST" {
		return nil, errors.New("Method not allowed")
	}
	tokens, err := tokenize(req.r.PostForm.Get("query"))
	if err != nil {
		return nil, err
	}
	if len(tokens) == 0 {
		return nil, errors.New("Empty query")
	}

	typ := "hosts"
	var args string
	for i, tok := range tokens {
		if len(args) > 0 {
			args += " AND"
		}

		if fields := strings.SplitN(tok, ":", 2); len(fields) == 2 {
			// Query: [<type>:] [<sibling-type>.]<attribute>:<value> ...
			if i == 0 && fields[1] == "" {
				typ = fields[0]
			} else if elems := strings.Split(fields[0], "."); len(elems) > 1 {
				objs := elems[:len(elems)-1]
				for _, o := range objs {
					if o != "host" && o != "service" && o != "metric" {
						return nil, fmt.Errorf("Invalid object type %q", o)
					}
				}
				args += fmt.Sprintf(" %s.attribute[%s] = %s",
					strings.Join(objs, "."), proto.EscapeString(elems[len(elems)-1]),
					proto.EscapeString(fields[1]))
			} else {
				args += fmt.Sprintf(" attribute[%s] = %s",
					proto.EscapeString(fields[0]), proto.EscapeString(fields[1]))
			}
		} else {
			args += fmt.Sprintf(" name =~ %s", proto.EscapeString(tok))
		}
	}

	res, err := s.query("LOOKUP %s MATCHING"+args, identifier(typ))
	if err != nil {
		return nil, err
	}
	if t, ok := s.results[typ]; ok {
		return tmpl(t, res)
	}
	return nil, fmt.Errorf("Unsupported type %s", typ)
}

func fetch(req request, s *Server) (*page, error) {
	if len(req.args) == 0 {
		return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
	}

	var res interface{}
	var err error
	switch req.cmd {
	case "host":
		if len(req.args) != 1 {
			return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
		}
		res, err = s.query("FETCH host %s", req.args[0])
	case "service", "metric":
		if len(req.args) != 2 {
			return nil, fmt.Errorf("%s not found", strings.Title(req.cmd))
		}
		res, err = s.query("FETCH %s %s.%s", identifier(req.cmd), req.args[0], req.args[1])
		if err == nil && req.cmd == "metric" {
			return metric(req, res, s)
		}
	default:
		panic("Unknown request: fetch(" + req.cmd + ")")
	}
	if err != nil {
		return nil, err
	}
	return tmpl(s.results[req.cmd], res)
}

var datetime = "2006-01-02 15:04:05"

func metric(req request, res interface{}, s *Server) (*page, error) {
	start := time.Now().Add(-24 * time.Hour)
	end := time.Now()
	if req.r.Method == "POST" {
		var err error
		// Parse the values first to verify their format.
		if s := req.r.PostForm.Get("start_date"); s != "" {
			if start, err = time.Parse(datetime, s); err != nil {
				return nil, fmt.Errorf("Invalid start time %q", s)
			}
		}
		if e := req.r.PostForm.Get("end_date"); e != "" {
			if end, err = time.Parse(datetime, e); err != nil {
				return nil, fmt.Errorf("Invalid end time %q", e)
			}
		}
	}

	p := struct {
		StartTime string
		EndTime   string
		URLStart  string
		URLEnd    string
		Data      interface{}
	}{
		start.Format(datetime),
		end.Format(datetime),
		start.Format(urldate),
		end.Format(urldate),
		res,
	}
	return tmpl(s.results["metric"], &p)
}

// tokenize split the string s into its tokens where a token is either a quoted
// string or surrounded by one or more consecutive whitespace characters.
func tokenize(s string) ([]string, error) {
	scan := scanner{}
	tokens := []string{}
	start := -1
	for i, r := range s {
		if !scan.inField(r) {
			if start == -1 {
				// Skip leading and consecutive whitespace.
				continue
			}
			tok, err := unescape(s[start:i])
			if err != nil {
				return nil, err
			}
			tokens = append(tokens, tok)
			start = -1
		} else if start == -1 {
			// Found a new field.
			start = i
		}
	}
	if start >= 0 {
		// Last (or possibly only) field.
		tok, err := unescape(s[start:])
		if err != nil {
			return nil, err
		}
		tokens = append(tokens, tok)
	}

	if scan.inQuotes {
		return nil, errors.New("quoted string not terminated")
	}
	if scan.escaped {
		return nil, errors.New("illegal character escape at end of string")
	}
	return tokens, nil
}

func unescape(s string) (string, error) {
	var unescaped []byte
	var i, n int
	for i = 0; i < len(s); i++ {
		if s[i] != '\\' {
			n++
			continue
		}

		if i >= len(s) {
			return "", errors.New("illegal character escape at end of string")
		}
		if s[i+1] != ' ' && s[i+1] != '"' && s[i+1] != '\\' {
			// Allow simple escapes only for now.
			return "", fmt.Errorf("illegal character escape \\%c", s[i+1])
		}
		if unescaped == nil {
			unescaped = []byte(s)
		}
		copy(unescaped[n:], s[i+1:])
	}

	if unescaped != nil {
		return string(unescaped[:n]), nil
	}
	return s, nil
}

type scanner struct {
	inQuotes bool
	escaped  bool
}

func (s *scanner) inField(r rune) bool {
	if s.escaped {
		s.escaped = false
		return true
	}
	if r == '\\' {
		s.escaped = true
		return true
	}
	if s.inQuotes {
		if r == '"' {
			s.inQuotes = false
			return false
		}
		return true
	}
	if r == '"' {
		s.inQuotes = true
		return false
	}
	return !unicode.IsSpace(r)
}

type identifier string

func (s *Server) query(cmd string, args ...interface{}) (interface{}, error) {
	c := <-s.conns
	defer func() { s.conns <- c }()

	for i, arg := range args {
		switch v := arg.(type) {
		case identifier:
			// Nothing to do.
		case string:
			args[i] = proto.EscapeString(v)
		case time.Time:
			args[i] = v.Format(datetime)
		default:
			panic(fmt.Sprintf("query: invalid type %T", arg))
		}
	}

	cmd = fmt.Sprintf(cmd, args...)
	m := &proto.Message{
		Type: proto.ConnectionQuery,
		Raw:  []byte(cmd),
	}
	if err := c.Send(m); err != nil {
		return nil, fmt.Errorf("Query %q: %v", cmd, err)
	}

	for {
		m, err := c.Receive()
		if err != nil {
			return nil, fmt.Errorf("Failed to receive server response: %v", err)
		}
		if m.Type == proto.ConnectionLog {
			log.Println(string(m.Raw[4:]))
			continue
		} else if m.Type == proto.ConnectionError {
			return nil, errors.New(string(m.Raw))
		}

		t, err := m.DataType()
		if err != nil {
			return nil, fmt.Errorf("Failed to unmarshal response: %v", err)
		}

		var res interface{}
		switch t {
		case proto.HostList:
			var hosts []sysdb.Host
			err = proto.Unmarshal(m, &hosts)
			res = hosts
		case proto.Host:
			var host sysdb.Host
			err = proto.Unmarshal(m, &host)
			res = host
		case proto.Timeseries:
			var ts sysdb.Timeseries
			err = proto.Unmarshal(m, &ts)
			res = ts
		default:
			return nil, fmt.Errorf("Unsupported data type %d", t)
		}
		if err != nil {
			return nil, fmt.Errorf("Failed to unmarshal response: %v", err)
		}
		return res, nil
	}
}

// vim: set tw=78 sw=4 sw=4 noexpandtab :
<|endoftext|>


<commit_before>package bolt_test

import (
	"context"
	"reflect"
	"testing"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/bolt"
)

// Ensure an SourceStore can store, retrieve, update, and delete sources.
func TestSourceStore(t *testing.T) {
	c, err := NewTestClient()
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	s := c.SourcesStore

	srcs := []chronograf.Source{
		chronograf.Source{
			Name:         "Of Truth",
			Type:         "influx",
			Username:     "marty",
			Password:     "I❤  jennifer parker",
			URL:          "toyota-hilux.lyon-estates.local",
			Default:      true,
			Organization: "1337",
			DefaultRP:    "pineapple",
		},
		chronograf.Source{
			Name:         "HipToBeSquare",
			Type:         "influx",
			Username:     "calvinklein",
			Password:     "chuck b3rry",
			URL:          "toyota-hilux.lyon-estates.local",
			Default:      true,
			Organization: "1337",
		},
		chronograf.Source{
			Name:               "HipToBeSquare",
			Type:               "influx",
			Username:           "calvinklein",
			Password:           "chuck b3rry",
			URL:                "https://toyota-hilux.lyon-estates.local",
			InsecureSkipVerify: true,
			Default:            false,
			Organization:       "1337",
		},
	}

	ctx := context.Background()
	// Add new srcs.
	for i, src := range srcs {
		if srcs[i], err = s.Add(ctx, src); err != nil {
			t.Fatal(err)
		}
		// Confirm first src in the store is the same as the original.
		if actual, err := s.Get(ctx, srcs[i].ID); err != nil {
			t.Fatal(err)
		} else if !reflect.DeepEqual(actual, srcs[i]) {
			t.Fatalf("source loaded is different then source saved; actual: %v, expected %v", actual, srcs[i])
		}
	}

	// Update source.
	srcs[0].Username = "calvinklein"
	srcs[1].Name = "Enchantment Under the Sea Dance"
	mustUpdateSource(t, s, srcs[0])
	mustUpdateSource(t, s, srcs[1])

	// Confirm sources have updated.
	if src, err := s.Get(ctx, srcs[0].ID); err != nil {
		t.Fatal(err)
	} else if src.Username != "calvinklein" {
		t.Fatalf("source 0 update error: got %v, expected %v", src.Username, "calvinklein")
	}
	if src, err := s.Get(ctx, srcs[1].ID); err != nil {
		t.Fatal(err)
	} else if src.Name != "Enchantment Under the Sea Dance" {
		t.Fatalf("source 1 update error: got %v, expected %v", src.Name, "Enchantment Under the Sea Dance")
	}

	// Attempt to make two default sources
	srcs[0].Default = true
	srcs[1].Default = true
	mustUpdateSource(t, s, srcs[0])
	mustUpdateSource(t, s, srcs[1])

	if actual, err := s.Get(ctx, srcs[0].ID); err != nil {
		t.Fatal(err)
	} else if actual.Default == true {
		t.Fatal("Able to set two default sources when only one should be permitted")
	}

	// Attempt to add a new default source
	srcs = append(srcs, chronograf.Source{
		Name:         "Biff Tannen",
		Type:         "influx",
		Username:     "HELLO",
		Password:     "MCFLY",
		URL:          "anybody.in.there.local",
		Default:      true,
		Organization: "1892",
	})

	srcs[3] = mustAddSource(t, s, srcs[3])
	if srcs, err := s.All(ctx); err != nil {
		t.Fatal(err)
	} else {
		defaults := 0
		for _, src := range srcs {
			if src.Default {
				defaults++
			}
		}

		if defaults != 1 {
			t.Fatal("Able to add more than one default source")
		}
	}

	// Delete an source.
	if err := s.Delete(ctx, srcs[0]); err != nil {
		t.Fatal(err)
	}

	// Confirm source has been deleted.
	if _, err := s.Get(ctx, srcs[0].ID); err != chronograf.ErrSourceNotFound {
		t.Fatalf("source delete error: got %v, expected %v", err, chronograf.ErrSourceNotFound)
	}

	// Delete the other source we created
	if err := s.Delete(ctx, srcs[3]); err != nil {
		t.Fatal(err)
	}

	if bsrcs, err := s.All(ctx); err != nil {
		t.Fatal(err)
	} else if len(bsrcs) != 2 {
		t.Fatalf("After delete All returned incorrect number of srcs; got %d, expected %d", len(bsrcs), 2)
	} else if !reflect.DeepEqual(bsrcs[0], srcs[1]) {
		t.Fatalf("After delete All returned incorrect source; got %v, expected %v", bsrcs[0], srcs[1])
	}

	// Delete the final sources
	if err := s.Delete(ctx, srcs[1]); err != nil {
		t.Fatal(err)
	}
	if err := s.Delete(ctx, srcs[2]); err != nil {
		t.Fatal(err)
	}

	// Try to add one source as a non-default and ensure that it becomes a
	// default
	src := mustAddSource(t, s, chronograf.Source{
		Name:         "Biff Tannen",
		Type:         "influx",
		Username:     "HELLO",
		Password:     "MCFLY",
		URL:          "anybody.in.there.local",
		Default:      false,
		Organization: "1234",
	})

	if actual, err := s.Get(ctx, src.ID); err != nil {
		t.Fatal(err)
	} else if !actual.Default {
		t.Fatal("Expected first source added to be default but wasn't")
	}
}

func mustUpdateSource(t *testing.T, s *bolt.SourcesStore, src chronograf.Source) {
	ctx := context.Background()
	if err := s.Update(ctx, src); err != nil {
		t.Fatal(err)
	}
}

func mustAddSource(t *testing.T, s *bolt.SourcesStore, src chronograf.Source) chronograf.Source {
	ctx := context.Background()
	if src, err := s.Add(ctx, src); err != nil {
		t.Fatal(err)
		return src
	} else {
		return src
	}
}
<commit_msg>Test bolt  update defaultRP in source<commit_after>package bolt_test

import (
	"context"
	"reflect"
	"testing"

	"github.com/influxdata/chronograf"
	"github.com/influxdata/chronograf/bolt"
)

// Ensure an SourceStore can store, retrieve, update, and delete sources.
func TestSourceStore(t *testing.T) {
	c, err := NewTestClient()
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()

	s := c.SourcesStore

	srcs := []chronograf.Source{
		chronograf.Source{
			Name:         "Of Truth",
			Type:         "influx",
			Username:     "marty",
			Password:     "I❤  jennifer parker",
			URL:          "toyota-hilux.lyon-estates.local",
			Default:      true,
			Organization: "1337",
			DefaultRP:    "pineapple",
		},
		chronograf.Source{
			Name:         "HipToBeSquare",
			Type:         "influx",
			Username:     "calvinklein",
			Password:     "chuck b3rry",
			URL:          "toyota-hilux.lyon-estates.local",
			Default:      true,
			Organization: "1337",
		},
		chronograf.Source{
			Name:               "HipToBeSquare",
			Type:               "influx",
			Username:           "calvinklein",
			Password:           "chuck b3rry",
			URL:                "https://toyota-hilux.lyon-estates.local",
			InsecureSkipVerify: true,
			Default:            false,
			Organization:       "1337",
		},
	}

	ctx := context.Background()
	// Add new srcs.
	for i, src := range srcs {
		if srcs[i], err = s.Add(ctx, src); err != nil {
			t.Fatal(err)
		}
		// Confirm first src in the store is the same as the original.
		if actual, err := s.Get(ctx, srcs[i].ID); err != nil {
			t.Fatal(err)
		} else if !reflect.DeepEqual(actual, srcs[i]) {
			t.Fatalf("source loaded is different then source saved; actual: %v, expected %v", actual, srcs[i])
		}
	}

	// Update source.
	srcs[0].Username = "calvinklein"
	srcs[1].Name = "Enchantment Under the Sea Dance"
	srcs[2].DefaultRP = "cubeapple"
	mustUpdateSource(t, s, srcs[0])
	mustUpdateSource(t, s, srcs[1])
	mustUpdateSource(t, s, srcs[2])

	// Confirm sources have updated.
	if src, err := s.Get(ctx, srcs[0].ID); err != nil {
		t.Fatal(err)
	} else if src.Username != "calvinklein" {
		t.Fatalf("source 0 update error: got %v, expected %v", src.Username, "calvinklein")
	}
	if src, err := s.Get(ctx, srcs[1].ID); err != nil {
		t.Fatal(err)
	} else if src.Name != "Enchantment Under the Sea Dance" {
		t.Fatalf("source 1 update error: got %v, expected %v", src.Name, "Enchantment Under the Sea Dance")
	}
	if src, err := s.Get(ctx, srcs[2].ID); err != nil {
		t.Fatal(err)
	} else if src.DefaultRP != "cubeapple" {
		t.Fatalf("source 2 update error: got %v, expected %v", src.DefaultRP, "cubeapple")
	}

	// Attempt to make two default sources
	srcs[0].Default = true
	srcs[1].Default = true
	mustUpdateSource(t, s, srcs[0])
	mustUpdateSource(t, s, srcs[1])

	if actual, err := s.Get(ctx, srcs[0].ID); err != nil {
		t.Fatal(err)
	} else if actual.Default == true {
		t.Fatal("Able to set two default sources when only one should be permitted")
	}

	// Attempt to add a new default source
	srcs = append(srcs, chronograf.Source{
		Name:         "Biff Tannen",
		Type:         "influx",
		Username:     "HELLO",
		Password:     "MCFLY",
		URL:          "anybody.in.there.local",
		Default:      true,
		Organization: "1892",
	})

	srcs[3] = mustAddSource(t, s, srcs[3])
	if srcs, err := s.All(ctx); err != nil {
		t.Fatal(err)
	} else {
		defaults := 0
		for _, src := range srcs {
			if src.Default {
				defaults++
			}
		}

		if defaults != 1 {
			t.Fatal("Able to add more than one default source")
		}
	}

	// Delete an source.
	if err := s.Delete(ctx, srcs[0]); err != nil {
		t.Fatal(err)
	}

	// Confirm source has been deleted.
	if _, err := s.Get(ctx, srcs[0].ID); err != chronograf.ErrSourceNotFound {
		t.Fatalf("source delete error: got %v, expected %v", err, chronograf.ErrSourceNotFound)
	}

	// Delete the other source we created
	if err := s.Delete(ctx, srcs[3]); err != nil {
		t.Fatal(err)
	}

	if bsrcs, err := s.All(ctx); err != nil {
		t.Fatal(err)
	} else if len(bsrcs) != 2 {
		t.Fatalf("After delete All returned incorrect number of srcs; got %d, expected %d", len(bsrcs), 2)
	} else if !reflect.DeepEqual(bsrcs[0], srcs[1]) {
		t.Fatalf("After delete All returned incorrect source; got %v, expected %v", bsrcs[0], srcs[1])
	}

	// Delete the final sources
	if err := s.Delete(ctx, srcs[1]); err != nil {
		t.Fatal(err)
	}
	if err := s.Delete(ctx, srcs[2]); err != nil {
		t.Fatal(err)
	}

	// Try to add one source as a non-default and ensure that it becomes a
	// default
	src := mustAddSource(t, s, chronograf.Source{
		Name:         "Biff Tannen",
		Type:         "influx",
		Username:     "HELLO",
		Password:     "MCFLY",
		URL:          "anybody.in.there.local",
		Default:      false,
		Organization: "1234",
	})

	if actual, err := s.Get(ctx, src.ID); err != nil {
		t.Fatal(err)
	} else if !actual.Default {
		t.Fatal("Expected first source added to be default but wasn't")
	}
}

func mustUpdateSource(t *testing.T, s *bolt.SourcesStore, src chronograf.Source) {
	ctx := context.Background()
	if err := s.Update(ctx, src); err != nil {
		t.Fatal(err)
	}
}

func mustAddSource(t *testing.T, s *bolt.SourcesStore, src chronograf.Source) chronograf.Source {
	ctx := context.Background()
	if src, err := s.Add(ctx, src); err != nil {
		t.Fatal(err)
		return src
	} else {
		return src
	}
}
<|endoftext|>


<commit_before>package builtin

import (
	"github.com/oleiade/lane"
	"log"
	"math/rand"
	"strconv"
	"sync"
	"time"

	flow "github.com/wanliu/goflow"
)

func NewFinal() interface{} {
	return new(Final)
}

type Final struct {
	sync.RWMutex

	flow.Component

	ReplyQueue *lane.Queue

	delayMin int
	delayMax int

	In       <-chan ReplyData
	DelayMin <-chan float64
	DelayMax <-chan float64
}

func (s *Final) Init() {
	s.ReplyQueue = lane.NewQueue()
}

func (s *Final) OnIn(data ReplyData) {
	s.Lock()
	s.ReplyQueue.Enqueue(data)
	s.Unlock()

	s.SendReply()
}

func (s *Final) OnDelayMin(min float64) {
	s.delayMin = int(min)
}

func (s *Final) OnDelayMax(max float64) {
	s.delayMax = int(max)
}

func (s Final) DelayRange() int {
	rand.Seed(time.Now().UnixNano())

	if s.delayMin == 0 {
		return 3 + rand.Intn(2)
	} else {
		if s.delayMax > s.delayMin {
			return s.delayMin + rand.Intn(s.delayMax-s.delayMin)
		} else {
			return s.delayMin + rand.Intn(3)
		}
	}
}

func (s *Final) SendReply() {
	secs := s.DelayRange()

	s.RLock()
	for s.ReplyQueue.Head() != nil {
		data := s.ReplyQueue.Dequeue().(ReplyData)

		log.Printf("[Delay]Delay reply for " + strconv.Itoa(secs) + " seconds.")
		time.Sleep(time.Second * time.Duration(secs))

		data.Ctx.Post(data.Reply)
	}
	s.RUnlock()
}
<commit_msg>delay for 3 seconds<commit_after>package builtin

import (
	"github.com/oleiade/lane"
	"log"
	"math/rand"
	"strconv"
	"sync"
	"time"

	flow "github.com/wanliu/goflow"
)

func NewFinal() interface{} {
	return new(Final)
}

type Final struct {
	sync.RWMutex

	flow.Component

	ReplyQueue *lane.Queue

	delayMin int
	delayMax int

	In       <-chan ReplyData
	DelayMin <-chan float64
	DelayMax <-chan float64
}

func (s *Final) Init() {
	s.ReplyQueue = lane.NewQueue()
}

func (s *Final) OnIn(data ReplyData) {
	s.Lock()
	s.ReplyQueue.Enqueue(data)
	s.Unlock()

	s.SendReply()
}

func (s *Final) OnDelayMin(min float64) {
	s.delayMin = int(min)
}

func (s *Final) OnDelayMax(max float64) {
	s.delayMax = int(max)
}

func (s Final) DelayRange() int {
	rand.Seed(time.Now().UnixNano())

	if s.delayMin == 0 {
		return 3 + rand.Intn(2)
	} else {
		if s.delayMax > s.delayMin {
			return s.delayMin + rand.Intn(s.delayMax-s.delayMin)
		} else {
			return s.delayMin + rand.Intn(3)
		}
	}
}

func (s *Final) SendReply() {
	// secs := s.DelayRange()
	secs := 3

	s.RLock()
	for s.ReplyQueue.Head() != nil {
		data := s.ReplyQueue.Dequeue().(ReplyData)

		log.Printf("[Delay]Delay reply for " + strconv.Itoa(secs) + " seconds.")
		time.Sleep(time.Second * time.Duration(secs))

		data.Ctx.Post(data.Reply)
	}
	s.RUnlock()
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/ikravets/errs"

	"my/ev/packet"
	"my/ev/packet/bats"
	"my/ev/packet/miax"
	"my/ev/packet/nasdaq"
	"my/ev/sim"
)

type SimLogger struct {
	w               io.Writer
	tobOld, tobNew  []sim.PriceLevel
	efhLogger       EfhLogger
	supernodeLevels int
}

const SimLoggerDefaultSupernodeLevels = 256

func NewSimLogger(w io.Writer) *SimLogger {
	s := &SimLogger{
		w:               w,
		supernodeLevels: SimLoggerDefaultSupernodeLevels,
	}
	s.efhLogger = *NewEfhLogger(s)
	return s
}
func (s *SimLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	s.efhLogger.SetOutputMode(mode)
}
func (s *SimLogger) SetSupernodeLevels(levels int) {
	errs.Check(levels > 0)
	s.supernodeLevels = levels
}

func (s *SimLogger) printf(format string, vs ...interface{}) {
	_, err := fmt.Fprintf(s.w, format, vs...)
	errs.CheckE(err)
}
func (s *SimLogger) printfln(format string, vs ...interface{}) {
	f := format + "\n"
	s.printf(f, vs...)
}
func (s *SimLogger) MessageArrived(idm *sim.SimMessage) {
	outItto := func(name string, typ nasdaq.IttoMessageType, f string, vs ...interface{}) {
		s.printf("NORM %s %c ", name, typ)
		s.printfln(f, vs...)
	}
	outBats := func(f string, vs ...interface{}) {
		s.printf("NORM ORDER %02x ", idm.Pam.Layer().(bats.PitchMessage).Base().Type.ToInt())
		s.printfln(f, vs...)
	}
	outMiax := func(f string, vs ...interface{}) {
		s.printf("NORM TOM %02x ", idm.Pam.Layer().(miax.TomMessage).Base().Type.ToInt())
		s.printfln(f, vs...)
	}
	sideChar := func(s packet.MarketSide) byte {
		if s == packet.MarketSideAsk {
			return 'S'
		}
		return byte(s)
	}
	switch im := idm.Pam.Layer().(type) {
	case *nasdaq.IttoMessageAddOrder:
		outItto("ORDER", im.Type, "%c %08x %08x %08x %08x", sideChar(im.Side), im.OId, im.RefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageAddQuote:
		outItto("QBID", im.Type, "%08x %08x %08x %08x", im.OId, im.Bid.RefNumD.ToUint32(), im.Bid.Size, im.Bid.Price)
		outItto("QASK", im.Type, "%08x %08x %08x %08x", im.OId, im.Ask.RefNumD.ToUint32(), im.Ask.Size, im.Ask.Price)
	case *nasdaq.IttoMessageSingleSideExecuted:
		outItto("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageSingleSideExecutedWithPrice:
		outItto("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageOrderCancel:
		outItto("ORDER", im.Type, "%08x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageSingleSideReplace:
		outItto("ORDER", im.Type, "%08x %08x %08x %08x", im.RefNumD.ToUint32(), im.OrigRefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageSingleSideDelete:
		outItto("ORDER", im.Type, "%08x", im.OrigRefNumD.ToUint32())
	case *nasdaq.IttoMessageSingleSideUpdate:
		outItto("ORDER", im.Type, "%08x %08x %08x", im.RefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageQuoteReplace:
		outItto("QBID", im.Type, "%08x %08x %08x %08x", im.Bid.RefNumD.ToUint32(), im.Bid.OrigRefNumD.ToUint32(), im.Bid.Size, im.Bid.Price)
		outItto("QASK", im.Type, "%08x %08x %08x %08x", im.Ask.RefNumD.ToUint32(), im.Ask.OrigRefNumD.ToUint32(), im.Ask.Size, im.Ask.Price)
	case *nasdaq.IttoMessageQuoteDelete:
		outItto("QBID", im.Type, "%08x", im.BidOrigRefNumD.ToUint32())
		outItto("QASK", im.Type, "%08x", im.AskOrigRefNumD.ToUint32())
	case *nasdaq.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			outItto("ORDER", im.Type, "%08x", r.ToUint32())
		}

	case *bats.PitchMessageAddOrder:
		outBats("%c %012x %016x %08x %08x", sideChar(im.Side), im.Symbol.ToUint64(), im.OrderId.ToUint64(), im.Size, packet.PriceTo4Dec(im.Price))
	case *bats.PitchMessageDeleteOrder:
		outBats("%016x", im.OrderId.ToUint64())
	case *bats.PitchMessageOrderExecuted:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageOrderExecutedAtPriceSize:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageReduceSize:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageModifyOrder:
		outBats("%016x %08x %08x", im.OrderId.ToUint64(), im.Size, packet.PriceTo4Dec(im.Price))
	case *miax.TomMessageTom:
		outMiax("%c %08x %08x %08x %08x", sideChar(im.Side), im.ProductId.ToUint32(), packet.PriceTo4Dec(im.Price), im.Size, im.PriorityCustomerSize)
	}
	s.efhLogger.MessageArrived(idm)
}
func (s *SimLogger) OperationAppliedToOrders(operation sim.SimOperation) {
	type ordrespLogInfo struct {
		notFound, addOp   int
		orderId           packet.OrderId
		optionId          packet.OptionId
		side, price, size int
		ordlSuffix        string
	}
	type orduLogInfo struct {
		orderId           packet.OrderId
		optionId          packet.OptionId
		side, price, size int
	}

	var or ordrespLogInfo
	var ou orduLogInfo
	if _, ok := operation.(*sim.OperationTop); ok {
		return
	} else if op, ok := operation.(*sim.OperationAdd); ok {
		var oid packet.OptionId
		if op.Independent() {
			oid = op.GetOptionId()
		}
		or = ordrespLogInfo{
			addOp:      1,
			orderId:    op.OrderId,
			optionId:   oid,
			ordlSuffix: fmt.Sprintf(" %012x", oid.ToUint64()),
		}
		ou = orduLogInfo{
			orderId:  or.orderId,
			optionId: op.GetOptionId(),
			price:    op.GetPrice(),
			size:     op.GetNewSize(),
		}
		if op.GetSide() == packet.MarketSideAsk {
			ou.side = 1
		}
	} else {
		if operation.GetOptionId().Invalid() {
			or = ordrespLogInfo{notFound: 1}
		} else {
			or = ordrespLogInfo{
				optionId: operation.GetOptionId(),
				price:    operation.GetPrice(),
				size:     operation.GetNewSize() - operation.GetSizeDelta(),
			}
			if operation.GetSide() == packet.MarketSideAsk {
				or.side = 1
			}
			if operation.GetNewSize() != 0 {
				ou = orduLogInfo{
					optionId: or.optionId,
					side:     or.side,
					price:    or.price,
					size:     operation.GetNewSize(),
				}
			}
		}
		or.orderId = operation.GetOrigOrderId()
		ou.orderId = or.orderId
	}
	s.printfln("ORDL %d %016x%s", or.addOp, or.orderId.ToUint64(), or.ordlSuffix)
	s.printfln("ORDRESP %d %d %d %08x %08x %012x %016x", or.notFound, or.addOp, or.side, or.size, or.price, or.optionId.ToUint64(), or.orderId.ToUint64())
	if operation.GetOptionId().Valid() {
		s.printfln("ORDU %016x %012x %d %08x %08x", ou.orderId.ToUint64(), ou.optionId.ToUint64(), ou.side, ou.price, ou.size)
	}
}
func (s *SimLogger) BeforeBookUpdate(book sim.Book, operation sim.SimOperation) {
	s.tobOld = book.GetTop(operation.GetOptionId(), operation.GetSide(), s.supernodeLevels)
	s.efhLogger.BeforeBookUpdate(book, operation)
}
func (s *SimLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if operation.GetOptionId().Valid() {
		s.tobNew = book.GetTop(operation.GetOptionId(), operation.GetSide(), s.supernodeLevels)
		empty := sim.PriceLevel{}
		if operation.GetSide() == packet.MarketSideAsk {
			empty.Price = -1
		}
		for i := 0; i < s.supernodeLevels; i++ {
			plo, pln := empty, empty
			if i < len(s.tobOld) {
				plo = s.tobOld[i]
			}
			if i < len(s.tobNew) {
				pln = s.tobNew[i]
			}
			s.printfln("SN_OLD_NEW %02d %08x %08x  %08x %08x", i,
				plo.Size, uint32(plo.Price),
				pln.Size, uint32(pln.Price),
			)
		}
	}
	s.efhLogger.AfterBookUpdate(book, operation)
}

func (s *SimLogger) PrintOrder(m efhm_order) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintQuote(m efhm_quote) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintTrade(m efhm_trade) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintDefinitionNom(m efhm_definition_nom) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintDefinitionBats(m efhm_definition_bats) error {
	return s.genAppUpdate(m)
}

func (s *SimLogger) genAppUpdate(appMessage interface{}) (err error) {
	defer errs.PassE(&err)
	var bb bytes.Buffer
	errs.CheckE(binary.Write(&bb, binary.LittleEndian, appMessage))
	if r := bb.Len() % 8; r > 0 {
		// pad to  multiple of 8 bytes
		z := make([]byte, 8)
		_, err = bb.Write(z[0 : 8-r])
		errs.CheckE(err)
	}

	for {
		var qw uint64
		if err := binary.Read(&bb, binary.LittleEndian, &qw); err != nil {
			if err == io.EOF {
				break
			}
			errs.CheckE(err)
		} else {
			s.printfln("DMATOHOST_DATA %016x", qw)
		}
	}
	s.printfln("DMATOHOST_TRAILER 00656e696c616b45")
	return
}
<commit_msg>rec:SimLogger: fix print format<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/ikravets/errs"

	"my/ev/packet"
	"my/ev/packet/bats"
	"my/ev/packet/miax"
	"my/ev/packet/nasdaq"
	"my/ev/sim"
)

type SimLogger struct {
	w               io.Writer
	tobOld, tobNew  []sim.PriceLevel
	efhLogger       EfhLogger
	supernodeLevels int
}

const SimLoggerDefaultSupernodeLevels = 256

func NewSimLogger(w io.Writer) *SimLogger {
	s := &SimLogger{
		w:               w,
		supernodeLevels: SimLoggerDefaultSupernodeLevels,
	}
	s.efhLogger = *NewEfhLogger(s)
	return s
}
func (s *SimLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	s.efhLogger.SetOutputMode(mode)
}
func (s *SimLogger) SetSupernodeLevels(levels int) {
	errs.Check(levels > 0)
	s.supernodeLevels = levels
}

func (s *SimLogger) printf(format string, vs ...interface{}) {
	_, err := fmt.Fprintf(s.w, format, vs...)
	errs.CheckE(err)
}
func (s *SimLogger) printfln(format string, vs ...interface{}) {
	f := format + "\n"
	s.printf(f, vs...)
}
func (s *SimLogger) MessageArrived(idm *sim.SimMessage) {
	outItto := func(name string, typ nasdaq.IttoMessageType, f string, vs ...interface{}) {
		s.printf("NORM %s %c ", name, typ)
		s.printfln(f, vs...)
	}
	outBats := func(f string, vs ...interface{}) {
		s.printf("NORM ORDER %02x ", idm.Pam.Layer().(bats.PitchMessage).Base().Type.ToInt())
		s.printfln(f, vs...)
	}
	outMiax := func(f string, vs ...interface{}) {
		s.printf("NORM TOM %02x ", idm.Pam.Layer().(miax.TomMessage).Base().Type.ToInt())
		s.printfln(f, vs...)
	}
	sideChar := func(s packet.MarketSide) byte {
		if s == packet.MarketSideAsk {
			return 'S'
		}
		return byte(s)
	}
	switch im := idm.Pam.Layer().(type) {
	case *nasdaq.IttoMessageAddOrder:
		outItto("ORDER", im.Type, "%c %012x %016x %08x %08x", sideChar(im.Side), im.OId.ToUint64(), im.RefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageAddQuote:
		outItto("QBID", im.Type, "%012x %016x %08x %08x", im.OId.ToUint64(), im.Bid.RefNumD.ToUint32(), im.Bid.Size, im.Bid.Price)
		outItto("QASK", im.Type, "%012x %016x %08x %08x", im.OId.ToUint64(), im.Ask.RefNumD.ToUint32(), im.Ask.Size, im.Ask.Price)
	case *nasdaq.IttoMessageSingleSideExecuted:
		outItto("ORDER", im.Type, "%016x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageSingleSideExecutedWithPrice:
		outItto("ORDER", im.Type, "%016x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageOrderCancel:
		outItto("ORDER", im.Type, "%016x %08x", im.OrigRefNumD.ToUint32(), im.Size)
	case *nasdaq.IttoMessageSingleSideReplace:
		outItto("ORDER", im.Type, "%016x %016x %08x %08x", im.RefNumD.ToUint32(), im.OrigRefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageSingleSideDelete:
		outItto("ORDER", im.Type, "%016x", im.OrigRefNumD.ToUint32())
	case *nasdaq.IttoMessageSingleSideUpdate:
		outItto("ORDER", im.Type, "%016x %08x %08x", im.RefNumD.ToUint32(), im.Size, im.Price)
	case *nasdaq.IttoMessageQuoteReplace:
		outItto("QBID", im.Type, "%016x %016x %08x %08x", im.Bid.RefNumD.ToUint32(), im.Bid.OrigRefNumD.ToUint32(), im.Bid.Size, im.Bid.Price)
		outItto("QASK", im.Type, "%016x %016x %08x %08x", im.Ask.RefNumD.ToUint32(), im.Ask.OrigRefNumD.ToUint32(), im.Ask.Size, im.Ask.Price)
	case *nasdaq.IttoMessageQuoteDelete:
		outItto("QBID", im.Type, "%016x", im.BidOrigRefNumD.ToUint32())
		outItto("QASK", im.Type, "%016x", im.AskOrigRefNumD.ToUint32())
	case *nasdaq.IttoMessageBlockSingleSideDelete:
		for _, r := range im.RefNumDs {
			outItto("ORDER", im.Type, "%016x", r.ToUint32())
		}

	case *bats.PitchMessageAddOrder:
		outBats("%c %012x %016x %08x %08x", sideChar(im.Side), im.Symbol.ToUint64(), im.OrderId.ToUint64(), im.Size, packet.PriceTo4Dec(im.Price))
	case *bats.PitchMessageDeleteOrder:
		outBats("%016x", im.OrderId.ToUint64())
	case *bats.PitchMessageOrderExecuted:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageOrderExecutedAtPriceSize:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageReduceSize:
		outBats("%016x %08x", im.OrderId.ToUint64(), im.Size)
	case *bats.PitchMessageModifyOrder:
		outBats("%016x %08x %08x", im.OrderId.ToUint64(), im.Size, packet.PriceTo4Dec(im.Price))
	case *miax.TomMessageTom:
		outMiax("%c %08x %08x %08x %08x", sideChar(im.Side), im.ProductId.ToUint32(), packet.PriceTo4Dec(im.Price), im.Size, im.PriorityCustomerSize)
	}
	s.efhLogger.MessageArrived(idm)
}
func (s *SimLogger) OperationAppliedToOrders(operation sim.SimOperation) {
	type ordrespLogInfo struct {
		notFound, addOp   int
		orderId           packet.OrderId
		optionId          packet.OptionId
		side, price, size int
		ordlSuffix        string
	}
	type orduLogInfo struct {
		orderId           packet.OrderId
		optionId          packet.OptionId
		side, price, size int
	}

	var or ordrespLogInfo
	var ou orduLogInfo
	if _, ok := operation.(*sim.OperationTop); ok {
		return
	} else if op, ok := operation.(*sim.OperationAdd); ok {
		var oid packet.OptionId
		if op.Independent() {
			oid = op.GetOptionId()
		}
		or = ordrespLogInfo{
			addOp:      1,
			orderId:    op.OrderId,
			optionId:   oid,
			ordlSuffix: fmt.Sprintf(" %012x", oid.ToUint64()),
		}
		ou = orduLogInfo{
			orderId:  or.orderId,
			optionId: op.GetOptionId(),
			price:    op.GetPrice(),
			size:     op.GetNewSize(),
		}
		if op.GetSide() == packet.MarketSideAsk {
			ou.side = 1
		}
	} else {
		if operation.GetOptionId().Invalid() {
			or = ordrespLogInfo{notFound: 1}
		} else {
			or = ordrespLogInfo{
				optionId: operation.GetOptionId(),
				price:    operation.GetPrice(),
				size:     operation.GetNewSize() - operation.GetSizeDelta(),
			}
			if operation.GetSide() == packet.MarketSideAsk {
				or.side = 1
			}
			if operation.GetNewSize() != 0 {
				ou = orduLogInfo{
					optionId: or.optionId,
					side:     or.side,
					price:    or.price,
					size:     operation.GetNewSize(),
				}
			}
		}
		or.orderId = operation.GetOrigOrderId()
		ou.orderId = or.orderId
	}
	s.printfln("ORDL %d %016x%s", or.addOp, or.orderId.ToUint64(), or.ordlSuffix)
	s.printfln("ORDRESP %d %d %d %08x %08x %012x %016x", or.notFound, or.addOp, or.side, or.size, or.price, or.optionId.ToUint64(), or.orderId.ToUint64())
	if operation.GetOptionId().Valid() {
		s.printfln("ORDU %016x %012x %d %08x %08x", ou.orderId.ToUint64(), ou.optionId.ToUint64(), ou.side, ou.price, ou.size)
	}
}
func (s *SimLogger) BeforeBookUpdate(book sim.Book, operation sim.SimOperation) {
	s.tobOld = book.GetTop(operation.GetOptionId(), operation.GetSide(), s.supernodeLevels)
	s.efhLogger.BeforeBookUpdate(book, operation)
}
func (s *SimLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if operation.GetOptionId().Valid() {
		s.tobNew = book.GetTop(operation.GetOptionId(), operation.GetSide(), s.supernodeLevels)
		empty := sim.PriceLevel{}
		if operation.GetSide() == packet.MarketSideAsk {
			empty.Price = -1
		}
		for i := 0; i < s.supernodeLevels; i++ {
			plo, pln := empty, empty
			if i < len(s.tobOld) {
				plo = s.tobOld[i]
			}
			if i < len(s.tobNew) {
				pln = s.tobNew[i]
			}
			s.printfln("SN_OLD_NEW %02d %08x %08x  %08x %08x", i,
				plo.Size, uint32(plo.Price),
				pln.Size, uint32(pln.Price),
			)
		}
	}
	s.efhLogger.AfterBookUpdate(book, operation)
}

func (s *SimLogger) PrintOrder(m efhm_order) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintQuote(m efhm_quote) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintTrade(m efhm_trade) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintDefinitionNom(m efhm_definition_nom) error {
	return s.genAppUpdate(m)
}
func (s *SimLogger) PrintDefinitionBats(m efhm_definition_bats) error {
	return s.genAppUpdate(m)
}

func (s *SimLogger) genAppUpdate(appMessage interface{}) (err error) {
	defer errs.PassE(&err)
	var bb bytes.Buffer
	errs.CheckE(binary.Write(&bb, binary.LittleEndian, appMessage))
	if r := bb.Len() % 8; r > 0 {
		// pad to  multiple of 8 bytes
		z := make([]byte, 8)
		_, err = bb.Write(z[0 : 8-r])
		errs.CheckE(err)
	}

	for {
		var qw uint64
		if err := binary.Read(&bb, binary.LittleEndian, &qw); err != nil {
			if err == io.EOF {
				break
			}
			errs.CheckE(err)
		} else {
			s.printfln("DMATOHOST_DATA %016x", qw)
		}
	}
	s.printfln("DMATOHOST_TRAILER 00656e696c616b45")
	return
}
<|endoftext|>


<commit_before>package calc

import "testing"

func TestDivision(t *testing.T) {
	var a, b int
	a = 10
	b = 5

	div, err := Division(a, b)

	if err != nil {
		t.Errorf("err want nil.")
	}

	if div != 2 {
		t.Errorf("sum want (%d).", 2)
	}
}
<commit_msg>add skip error.<commit_after>package calc

import "testing"

func TestDivision(t *testing.T) {
	var a, b int
	a = 10
	b = 5

	div, err := Division(a, b)

	if err != nil {
		t.Errorf("err want nil.")
	}

	if div != 2 {
		t.Errorf("sum want (%d).", 2)
	}
}

func TestDivisionNoErr(t *testing.T) {
	var a, b int
	a = 20
	b = 5

	div, _ := Division(a, b)

	if div != 4 {
		t.Errorf("sum want (%d).", 4)
	}
}
<|endoftext|>


<commit_before>package backends

import (
  "time"
  "fmt"
  "github.com/docker/libswarm/beam"
)

type ec2Client struct {
  Server *beam.Server
}

func (c *ec2Client) get(ctx *beam.Message) error {
  fmt.Println("*** ec2 Get ***")
  body := `{}`
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{body}})
  return nil
}

func (c *ec2Client) start(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStart ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) log(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLog ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) spawn(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnSpawn ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) ls(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLs ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{}})
  return nil
}

func (c *ec2Client) error(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnError ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) stop(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStop ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) attach(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnAttach ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})

  for {
     time.Sleep(1 * time.Second)
     (&beam.Object{ctx.Ret}).Log("ec2: heartbeat")
  }
  return nil
}

func Ec2() beam.Sender {
  backend := beam.NewServer()
  backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
    fmt.Println("*** init ***")
    client := &ec2Client{beam.NewServer()}
    client.Server.OnSpawn(beam.Handler(client.spawn))
    client.Server.OnStart(beam.Handler(client.start))
    client.Server.OnStop(beam.Handler(client.stop))
    client.Server.OnAttach(beam.Handler(client.attach))
    client.Server.OnLog(beam.Handler(client.log))
    client.Server.OnError(beam.Handler(client.error))
    client.Server.OnLs(beam.Handler(client.ls))
    client.Server.OnGet(beam.Handler(client.get))
    _, err := ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})
    return err
  }))
  return backend
}
<commit_msg>basic ec2 config<commit_after>package backends

import (
  "time"
  "fmt"
  "strings"
  "github.com/docker/libswarm/beam"
)

type ec2Config struct {
  access_key     string
  secret_key     string
  security_group string
  instance_type  string
  keypair        string
  region         string
  zone           string
  ami            string
  tag            string
}

type ec2Client struct {
  config *ec2Config
  Server *beam.Server
}

func (c *ec2Client) get(ctx *beam.Message) error {
  fmt.Println("*** ec2 Get ***")
  body := `{}`
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{body}})
  return nil
}

func (c *ec2Client) start(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStart ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) log(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLog ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) spawn(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnSpawn ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) ls(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnLs ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Set, Args: []string{}})
  return nil
}

func (c *ec2Client) error(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnError ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) stop(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnStop ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})
  return nil
}

func (c *ec2Client) attach(ctx *beam.Message) error {
  fmt.Println("*** ec2 OnAttach ***")
  ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: c.Server})

  for {
     time.Sleep(1 * time.Second)
     (&beam.Object{ctx.Ret}).Log("ec2: heartbeat")
  }
  return nil
}

func newConfig(args []string) (config *ec2Config, err error) {
  // TODO (aaron): fail fast on incorrect number of args

  var optValPair []string
  var opt, val string

  config = new(ec2Config)
  for _, value := range args {
    optValPair = strings.Split(value, "=")
    opt = optValPair[0]
    val = optValPair[1]

    switch opt {
      case "--region":
        config.region = val
      case "--zone":
        config.zone = val
      case "--tag":
        config.tag = val
      case "--ami":
        config.ami = val
      case "--keypair":
        config.keypair = val
      case "--security_group":
        config.security_group = val
      case "--instance_type":
        config.instance_type = val
      default:
        fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
    }
  }
  return config, nil
}

func Ec2() beam.Sender {
  backend := beam.NewServer()
  backend.OnSpawn(beam.Handler(func(ctx *beam.Message) error {
    fmt.Println("*** init ***")

    var config, err = newConfig(ctx.Args)

    if (err != nil) {
      return err
    }

    client := &ec2Client{config, beam.NewServer()}
    client.Server.OnSpawn(beam.Handler(client.spawn))
    client.Server.OnStart(beam.Handler(client.start))
    client.Server.OnStop(beam.Handler(client.stop))
    client.Server.OnAttach(beam.Handler(client.attach))
    client.Server.OnLog(beam.Handler(client.log))
    client.Server.OnError(beam.Handler(client.error))
    client.Server.OnLs(beam.Handler(client.ls))
    client.Server.OnGet(beam.Handler(client.get))
    _, err = ctx.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: client.Server})
    return err
  }))
  return backend
}
<|endoftext|>


<commit_before>// Copyright (c) - Damien Fontaine <damien.fontaine@lineolia.net>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>

package security

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

	"github.com/DamienFontaine/lunarc/web"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
)

//TokenHandler manage authorizations
func TokenHandler(next http.Handler, cnf web.Config) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				//TODO: On ne passe jamais à l'intérieur
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(cnf.Jwt.Key), nil
		})
		if err == nil && token.Valid {
			next.ServeHTTP(w, r)
		} else {
			if r.URL.String() == "/" {
				next.ServeHTTP(w, r)
			} else {
				w.WriteHeader(http.StatusUnauthorized)
			}
		}
	})
}

//Oauth2 manage authorizations
func Oauth2(next http.Handler, cnf web.Config) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(cnf.Jwt.Key), nil
		})
		if err == nil && token.Valid {
			next.ServeHTTP(w, r)
		} else {
			log.Printf("Problem %v", err)
			w.WriteHeader(http.StatusUnauthorized)
		}
	})
}
<commit_msg>Delete unused log<commit_after>// Copyright (c) - Damien Fontaine <damien.fontaine@lineolia.net>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>

package security

import (
	"fmt"
	"net/http"

	"github.com/DamienFontaine/lunarc/web"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
)

//TokenHandler manage authorizations
func TokenHandler(next http.Handler, cnf web.Config) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				//TODO: On ne passe jamais à l'intérieur
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(cnf.Jwt.Key), nil
		})
		if err == nil && token.Valid {
			next.ServeHTTP(w, r)
		} else {
			if r.URL.String() == "/" {
				next.ServeHTTP(w, r)
			} else {
				w.WriteHeader(http.StatusUnauthorized)
			}
		}
	})
}

//Oauth2 manage authorizations
func Oauth2(next http.Handler, cnf web.Config) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(cnf.Jwt.Key), nil
		})
		if err == nil && token.Valid {
			next.ServeHTTP(w, r)
		} else {
			w.WriteHeader(http.StatusUnauthorized)
		}
	})
}
<|endoftext|>


<commit_before>package eventexporter

import "github.com/sendgrid/sendgrid-go"

const (
	DefaultFromName    = "Koding"
	DefaultFromAddress = "hello@koding.com"
)

type SendgridExporter struct {
	Client *sendgrid.SGClient
}

func NewSendgridExporter(username, password string) *SendgridExporter {
	return &SendgridExporter{
		Client: sendgrid.NewSendGridClient(username, password),
	}
}

func (s *SendgridExporter) Send(event *Event) error {
	var err error

	mail := sendgrid.NewMail()
	if mail, err = setTo(mail, event); err != nil {
		return err
	}

	if mail, err = setFrom(mail, event); err != nil {
		return err
	}

	if mail, err = setBody(mail, event); err != nil {
		return err
	}

	if mail, err = setSubject(mail, event); err != nil {
		return err
	}

	return s.Client.Send(mail)
}

func setTo(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	err := mail.AddTo(event.User.Email)
	if err != nil {
		return nil, err
	}

	return mail, nil
}

func setFrom(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	from, ok := event.Properties["from"]
	if !ok {
		from = DefaultFromAddress
	}

	if err := mail.SetFrom(from.(string)); err != nil {
		return nil, err
	}

	fromName, ok := event.Properties["fromName"]
	if !ok {
		from = DefaultFromName
	}

	mail.SetFromName(fromName.(string))

	return mail, nil
}

func setBody(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	if event.Body == nil {
		return nil, ErrSendgridBodyEmpty
	}

	bodyType := event.Body.Type
	switch bodyType {
	case HtmlBodyType:
		mail.SetHTML(event.Body.Content)
	case TextBodyType:
		mail.SetText(event.Body.Content)
	}

	return mail, nil
}

func setSubject(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	mail.SetSubject(event.Name)
	return mail, nil
}
<commit_msg>build sendgrid with flags<commit_after>// +build segment

package eventexporter

import sendgrid "github.com/sendgrid/sendgrid-go"

const (
	DefaultFromName    = "Koding"
	DefaultFromAddress = "hello@koding.com"
)

type SendgridExporter struct {
	Client *sendgrid.SGClient
}

func NewSendgridExporter(username, password string) *SendgridExporter {
	return &SendgridExporter{
		Client: sendgrid.NewSendGridClient(username, password),
	}
}

func (s *SendgridExporter) Send(event *Event) error {
	var err error

	mail := sendgrid.NewMail()
	if mail, err = setTo(mail, event); err != nil {
		return err
	}

	if mail, err = setFrom(mail, event); err != nil {
		return err
	}

	if mail, err = setBody(mail, event); err != nil {
		return err
	}

	if mail, err = setSubject(mail, event); err != nil {
		return err
	}

	return s.Client.Send(mail)
}

func setTo(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	err := mail.AddTo(event.User.Email)
	if err != nil {
		return nil, err
	}

	return mail, nil
}

func setFrom(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	from, ok := event.Properties["from"]
	if !ok {
		from = DefaultFromAddress
	}

	if err := mail.SetFrom(from.(string)); err != nil {
		return nil, err
	}

	fromName, ok := event.Properties["fromName"]
	if !ok {
		from = DefaultFromName
	}

	mail.SetFromName(fromName.(string))

	return mail, nil
}

func setBody(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	if event.Body == nil {
		return nil, ErrSendgridBodyEmpty
	}

	bodyType := event.Body.Type
	switch bodyType {
	case HtmlBodyType:
		mail.SetHTML(event.Body.Content)
	case TextBodyType:
		mail.SetText(event.Body.Content)
	}

	return mail, nil
}

func setSubject(mail *sendgrid.SGMail, event *Event) (*sendgrid.SGMail, error) {
	mail.SetSubject(event.Name)
	return mail, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/rs/cors"
)

func main() {
	store := make(map[uint64][]byte)
	var n uint64
	var lck sync.Mutex
	http.Handle("/add", cors.New(cors.Options{
		AllowedMethods:   []string{"PUT"},
		AllowCredentials: true,
	}).Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPut {
			http.Error(w, "Not a put", http.StatusBadRequest)
			log.Printf("Incorrect method %s\n", r.Method)
			return
		}
		buf := bytes.NewBuffer(nil)
		_, err := io.Copy(buf, r.Body)
		if err != nil {
			return
		}
		lck.Lock()
		defer lck.Unlock()
		store[n] = buf.Bytes()
		go func() {
			time.Sleep(time.Minute)
			lck.Lock()
			defer lck.Unlock()
			delete(store, n)
		}()
		w.Write([]byte(fmt.Sprint(n)))
		n++
	})))
	http.Handle("/get", cors.New(cors.Options{
		AllowedMethods:   []string{"GET"},
		AllowCredentials: true,
	}).Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Form parse error", http.StatusBadRequest)
			return
		}
		ids := r.FormValue("id")
		if ids == "" {
			http.Error(w, "No id in request", http.StatusBadRequest)
			return
		}
		id, err := strconv.ParseUint(ids, 10, 64)
		if err != nil {
			http.Error(w, "Id is not an int", http.StatusBadRequest)
			return
		}
		dat := func() []byte {
			lck.Lock()
			defer lck.Unlock()
			return store[id]
		}()
		if dat == nil {
			http.Error(w, "Data gone", http.StatusGone)
			return
		}
		io.Copy(w, bytes.NewBuffer(dat))
	})))
	http.ListenAndServe(":80", nil)
}
<commit_msg>more debugging<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/rs/cors"
)

func main() {
	store := make(map[uint64][]byte)
	var n uint64
	var lck sync.Mutex
	http.Handle("/add", cors.New(cors.Options{
		AllowedMethods:   []string{"PUT"},
		AllowCredentials: true,
	}).Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPut {
			http.Error(w, "Not a put", http.StatusBadRequest)
			log.Printf("Incorrect method %s\n", r.Method)
			return
		}
		buf := bytes.NewBuffer(nil)
		_, err := io.Copy(buf, r.Body)
		if err != nil {
			return
		}
		lck.Lock()
		defer lck.Unlock()
		store[n] = buf.Bytes()
		go func() {
			time.Sleep(time.Minute)
			log.Printf("deleting: %d\n", n)
			lck.Lock()
			defer lck.Unlock()
			delete(store, n)
		}()
		w.Write([]byte(fmt.Sprint(n)))
		n++
	})))
	http.Handle("/get", cors.New(cors.Options{
		AllowedMethods:   []string{"GET"},
		AllowCredentials: true,
	}).Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Form parse error", http.StatusBadRequest)
			return
		}
		ids := r.FormValue("id")
		if ids == "" {
			http.Error(w, "No id in request", http.StatusBadRequest)
			return
		}
		id, err := strconv.ParseUint(ids, 10, 64)
		if err != nil {
			http.Error(w, "Id is not an int", http.StatusBadRequest)
			return
		}
		dat := func() []byte {
			lck.Lock()
			defer lck.Unlock()
			return store[id]
		}()
		if dat == nil {
			http.Error(w, "Data gone", http.StatusGone)
			return
		}
		io.Copy(w, bytes.NewBuffer(dat))
	})))
	http.ListenAndServe(":80", nil)
}
<|endoftext|>