<commit_before>// Package ircclient provides the main interface for library users
// It manages a single connection to the server and the associated
// configuration and plugins.
package ircclient

import (
	"os"
	"log"
	"strings"
	"fmt"
)

type IRCClient struct {
	conn       *IRCConn
	plugins    *pluginStack
	handlers   map[string]handler
	disconnect chan bool
}

type handler struct {
	handler   Plugin
	minparams int
	minaccess int
}

// Returns a new IRCClient connection with the given configuration options.
// It will not connect to the given server until Connect() has been called,
// so you can register plugins before connecting
func NewIRCClient(configfile string) *IRCClient {
	c := &IRCClient{nil, newPluginStack(), make(map[string]handler), make(chan bool)}
	c.RegisterPlugin(&basicProtocol{})
	c.RegisterPlugin(NewConfigPlugin(configfile))
	c.RegisterPlugin(new(authPlugin))
	return c
}

// Registers a new plugin. Plugins can be registered at any time, even before
// the actual connection attempt. The plugin's Unregister() function will already
// be called when the connection is lost.
func (ic *IRCClient) RegisterPlugin(p Plugin) os.Error {
	if _, ok := ic.plugins.GetPlugin(p.String()); ok == true {
		return os.NewError("Plugin already exists")
	}
	p.Register(ic)
	ic.plugins.Push(p)
	return nil
}

// Registers a command handler. Plugin callbacks will only be called if
// the command matches. Note that only a single plugin per command may
// be registered. This function is not synchronized, e.g., it shall only
// be called during registration (as Plugin.Register()-calls are currently
// sequential).
func (ic *IRCClient) RegisterCommandHandler(command string, minparams int, minaccess int, plugin Plugin) os.Error {
	if plug, err := ic.handlers[command]; err {
		return os.NewError("Handler is already registered by plugin: " + plug.handler.String())
	}
	ic.handlers[command] = handler{plugin, minparams, minaccess}
	return nil
}

// Gets one of the configuration options stored in the config object. Valid config
// options for section "Server" usually include:
//  - nick
//  - hostport (colon-seperated host and port to connect to)
//  - realname (the real name)
//  - ident
//  - trigger
func (ic *IRCClient) GetStringOption(section, option string) string {
	c, _ := ic.GetPlugin("conf")
	if c == nil {
		log.Fatal("wtf?")
	}
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	retval, _ := cf.Conf.String(section, option)
	cf.Unlock()
	return retval
}

func (ic *IRCClient) SetStringOption(section, option, value string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	if cf.Conf.HasOption(section, option) {
		cf.Conf.RemoveOption(section, option)
	}
	cf.Conf.AddOption(section, option, value)
	cf.Unlock()
}

func (ic *IRCClient) DelOption(section, option string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()

	if ! cf.Conf.HasSection(section) {
		// nothing to do
		return
	}
	cf.Conf.RemoveOption(section, option)
}

func (ic *IRCClient) GetOptions(section string) []string {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	opts, err := cf.Conf.Options(section)
	if err != nil {
		return []string{ "" }
	}
	return opts
}

func (ic *IRCClient) GetIntOption(section, option string) (int, os.Error) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	v, err := cf.Conf.Int(section, option)
	if err != nil {
		return -1, err
	}
	return v, nil
}

func (ic *IRCClient) SetIntOption(section, option string, value int) {
	//
}

func (ic *IRCClient) GetAccessLevel(host string) int {
	// TODO
	return 0
}

func (ic *IRCClient) SetAccessLevel(host string, level int) {
	// TODO
}

func (ic *IRCClient) DelAccessLevel(host string) {
	// TODO
}

// Connects to the server specified on object creation. If the chosen nickname is
// already in use, it will automatically be suffixed with an single underscore until
// an unused nickname is found. This function blocks until the connection attempt
// has been finished.
func (ic *IRCClient) Connect() os.Error {
	ic.conn = NewIRCConn()
	e := ic.conn.Connect(ic.GetStringOption("Server", "host"))
	if e != nil {
		return e
	}
	ic.conn.Output <- "NICK " + ic.GetStringOption("Server", "nick")
	ic.conn.Output <- "USER " + ic.GetStringOption("Server", "ident") + " * Q :" + ic.GetStringOption("Server", "realname")
	nick := ic.GetStringOption("Server", "nick")
	for {
		line, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}

		// Invoke plugin line handlers.
		// At this point, it makes no sense to
		// process "commands". If a plugin needs
		// interaction in this state, it should be
		// low-level.
		s := ParseServerLine(line)
		if s == nil {
			continue
		}
		for p := range ic.plugins.Iter() {
			go p.ProcessLine(s)
		}

		switch s.Command {
		case "433":
			// Nickname already in use
			nick = nick + "_"
			ic.SetStringOption("Server", "nick", nick)
			ic.conn.Output <- "NICK " + nick
		case "001":
			// Successfully registered
			return nil
		}
	}
	return nil
}

func (ic *IRCClient) dispatchHandlers(in string) {
	var c *IRCCommand = nil

	s := ParseServerLine(in)
	if s == nil {
		return
	}
	if (s.Command == "PRIVMSG" || s.Command == "NOTICE") && (s.Target == ic.GetStringOption("Server", "nick") || strings.Index(s.Args[0], ic.GetStringOption("Server", "trigger")) == 0) {
		c = ParseCommand(s)
		// Strip trigger, if necessary
		if c != nil && s.Target != ic.GetStringOption("Server", "nick") && len(c.Command) != 0 {
			c.Command = c.Command[len(ic.GetStringOption("Server", "trigger")):len(c.Command)]
		}
	}

	// Call line handlers
	for p := range ic.plugins.Iter() {
		go p.ProcessLine(s)
	}

	// Call command handler
	if c == nil {
		return
	}
	if handler, err := ic.handlers[c.Command]; err == true {
		if ic.GetAccessLevel(c.Source) < handler.minaccess {
			ic.Reply(c, "You are not authorized to do that.")
			return
		}
		if len(c.Args) < handler.minparams {
			ic.Reply(c, "This command requires at least " + fmt.Sprintf("%d", handler.minparams)+" parameters")
			return
		}
		go handler.handler.ProcessCommand(c)
	}
}

// Starts the actual command processing. This function will block until the connection
// has either been lost or Disconnect() has been called (by a plugin or by the library
// user).
func (ic *IRCClient) InputLoop() os.Error {
	for {
		in, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}
		ic.dispatchHandlers(in)
	}
	panic("This never happens")
}

// Disconnects from the server with the given quit message. All plugins wil be unregistered
// and pending messages in queue (e.g. because of floodprotection) will be flushed. This will
// also make InputLoop() return.
func (ic *IRCClient) Disconnect(quitmsg string) {
	ic.shutdown()
	ic.conn.Output <- "QUIT :" + quitmsg
	ic.conn.Quit()
}

// Dumps a raw line to the server socket. This is usually called by plugins, but may also
// be used by the library user.
func (ic *IRCClient) SendLine(line string) {
	ic.conn.Output <- line
}

func (ic *IRCClient) shutdown() {
	for ic.plugins.Size() != 0 {
		p := ic.plugins.Pop()
		p.Unregister()
	}
}

// Returns a channel on which all plugins will be sent. Use it to iterate over all registered
// plugins.
func (ic *IRCClient) IterPlugins() <-chan Plugin {
	return ic.plugins.Iter()
}

// Get the pointer to a specific plugin that has been registered using RegisterPlugin()
// Name is the name the plugin identifies itself with when String() is called on it.
func (ic *IRCClient) GetPlugin(name string) (Plugin, bool) {
	return ic.plugins.GetPlugin(name)
}

// Sends a reply to a parsed message from a user. This is mostly intended for plugins
// and will automatically distinguish between channel and query messages. Note: Notice
// replies will currently be sent to the client using PRIVMSG, this may change in the
// future.
func (ic *IRCClient) Reply(cmd *IRCCommand, message string) {
	var target string
	if cmd.Target != ic.GetStringOption("Server", "nick") {
		target = cmd.Target
	} else {
		target = strings.SplitN(cmd.Source, "!", 2)[0]
	}
	ic.SendLine("PRIVMSG " + target + " :" + message)
}
<commit_msg>ircclient: implemented setIntOpt stub<commit_after>// Package ircclient provides the main interface for library users
// It manages a single connection to the server and the associated
// configuration and plugins.
package ircclient

import (
	"os"
	"log"
	"strings"
	"fmt"
)

type IRCClient struct {
	conn       *IRCConn
	plugins    *pluginStack
	handlers   map[string]handler
	disconnect chan bool
}

type handler struct {
	handler   Plugin
	minparams int
	minaccess int
}

// Returns a new IRCClient connection with the given configuration options.
// It will not connect to the given server until Connect() has been called,
// so you can register plugins before connecting
func NewIRCClient(configfile string) *IRCClient {
	c := &IRCClient{nil, newPluginStack(), make(map[string]handler), make(chan bool)}
	c.RegisterPlugin(&basicProtocol{})
	c.RegisterPlugin(NewConfigPlugin(configfile))
	c.RegisterPlugin(new(authPlugin))
	return c
}

// Registers a new plugin. Plugins can be registered at any time, even before
// the actual connection attempt. The plugin's Unregister() function will already
// be called when the connection is lost.
func (ic *IRCClient) RegisterPlugin(p Plugin) os.Error {
	if _, ok := ic.plugins.GetPlugin(p.String()); ok == true {
		return os.NewError("Plugin already exists")
	}
	p.Register(ic)
	ic.plugins.Push(p)
	return nil
}

// Registers a command handler. Plugin callbacks will only be called if
// the command matches. Note that only a single plugin per command may
// be registered. This function is not synchronized, e.g., it shall only
// be called during registration (as Plugin.Register()-calls are currently
// sequential).
func (ic *IRCClient) RegisterCommandHandler(command string, minparams int, minaccess int, plugin Plugin) os.Error {
	if plug, err := ic.handlers[command]; err {
		return os.NewError("Handler is already registered by plugin: " + plug.handler.String())
	}
	ic.handlers[command] = handler{plugin, minparams, minaccess}
	return nil
}

// Gets one of the configuration options stored in the config object. Valid config
// options for section "Server" usually include:
//  - nick
//  - hostport (colon-seperated host and port to connect to)
//  - realname (the real name)
//  - ident
//  - trigger
func (ic *IRCClient) GetStringOption(section, option string) string {
	c, _ := ic.GetPlugin("conf")
	if c == nil {
		log.Fatal("wtf?")
	}
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	retval, _ := cf.Conf.String(section, option)
	cf.Unlock()
	return retval
}

func (ic *IRCClient) SetStringOption(section, option, value string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	if ! cf.Conf.HasSection(section) {
		cf.Conf.AddSection(section)
	}
	if cf.Conf.HasOption(section, option) {
		cf.Conf.RemoveOption(section, option)
	}
	cf.Conf.AddOption(section, option, value)
	cf.Unlock()
}

func (ic *IRCClient) RemoveOption(section, option string) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()

	if ! cf.Conf.HasSection(section) {
		// nothing to do
		return
	}
	cf.Conf.RemoveOption(section, option)
}

func (ic *IRCClient) GetOptions(section string) []string {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	opts, err := cf.Conf.Options(section)
	if err != nil {
		return []string{ "" }
	}
	return opts
}

func (ic *IRCClient) GetIntOption(section, option string) (int, os.Error) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	v, err := cf.Conf.Int(section, option)
	if err != nil {
		return -1, err
	}
	return v, nil
}

func (ic *IRCClient) SetIntOption(section, option string, value int) {
	c, _ := ic.GetPlugin("conf")
	cf, _ := c.(*ConfigPlugin)
	cf.Lock()
	defer cf.Unlock()
	stropt := fmt.Sprintf("%d", value)
	if ! cf.HasSection(section) {
		cf.AddSection(section)
	}
	cf.AddOption(section, option, stropt)
}

func (ic *IRCClient) GetAccessLevel(host string) int {
	// TODO
	return 0
}

func (ic *IRCClient) SetAccessLevel(host string, level int) {
	// TODO
}

func (ic *IRCClient) DelAccessLevel(host string) {
	// TODO
}

// Connects to the server specified on object creation. If the chosen nickname is
// already in use, it will automatically be suffixed with an single underscore until
// an unused nickname is found. This function blocks until the connection attempt
// has been finished.
func (ic *IRCClient) Connect() os.Error {
	ic.conn = NewIRCConn()
	e := ic.conn.Connect(ic.GetStringOption("Server", "host"))
	if e != nil {
		return e
	}
	ic.conn.Output <- "NICK " + ic.GetStringOption("Server", "nick")
	ic.conn.Output <- "USER " + ic.GetStringOption("Server", "ident") + " * Q :" + ic.GetStringOption("Server", "realname")
	nick := ic.GetStringOption("Server", "nick")
	for {
		line, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}

		// Invoke plugin line handlers.
		// At this point, it makes no sense to
		// process "commands". If a plugin needs
		// interaction in this state, it should be
		// low-level.
		s := ParseServerLine(line)
		if s == nil {
			continue
		}
		for p := range ic.plugins.Iter() {
			go p.ProcessLine(s)
		}

		switch s.Command {
		case "433":
			// Nickname already in use
			nick = nick + "_"
			ic.SetStringOption("Server", "nick", nick)
			ic.conn.Output <- "NICK " + nick
		case "001":
			// Successfully registered
			return nil
		}
	}
	return nil
}

func (ic *IRCClient) dispatchHandlers(in string) {
	var c *IRCCommand = nil

	s := ParseServerLine(in)
	if s == nil {
		return
	}
	if (s.Command == "PRIVMSG" || s.Command == "NOTICE") && (s.Target == ic.GetStringOption("Server", "nick") || strings.Index(s.Args[0], ic.GetStringOption("Server", "trigger")) == 0) {
		c = ParseCommand(s)
		// Strip trigger, if necessary
		if c != nil && s.Target != ic.GetStringOption("Server", "nick") && len(c.Command) != 0 {
			c.Command = c.Command[len(ic.GetStringOption("Server", "trigger")):len(c.Command)]
		}
	}

	// Call line handlers
	for p := range ic.plugins.Iter() {
		go p.ProcessLine(s)
	}

	// Call command handler
	if c == nil {
		return
	}
	if handler, err := ic.handlers[c.Command]; err == true {
		if ic.GetAccessLevel(c.Source) < handler.minaccess {
			ic.Reply(c, "You are not authorized to do that.")
			return
		}
		if len(c.Args) < handler.minparams {
			ic.Reply(c, "This command requires at least " + fmt.Sprintf("%d", handler.minparams)+" parameters")
			return
		}
		go handler.handler.ProcessCommand(c)
	}
}

// Starts the actual command processing. This function will block until the connection
// has either been lost or Disconnect() has been called (by a plugin or by the library
// user).
func (ic *IRCClient) InputLoop() os.Error {
	for {
		in, ok := <-ic.conn.Input
		if !ok {
			return <-ic.conn.Err
		}
		ic.dispatchHandlers(in)
	}
	panic("This never happens")
}

// Disconnects from the server with the given quit message. All plugins wil be unregistered
// and pending messages in queue (e.g. because of floodprotection) will be flushed. This will
// also make InputLoop() return.
func (ic *IRCClient) Disconnect(quitmsg string) {
	ic.shutdown()
	ic.conn.Output <- "QUIT :" + quitmsg
	ic.conn.Quit()
}

// Dumps a raw line to the server socket. This is usually called by plugins, but may also
// be used by the library user.
func (ic *IRCClient) SendLine(line string) {
	ic.conn.Output <- line
}

func (ic *IRCClient) shutdown() {
	for ic.plugins.Size() != 0 {
		p := ic.plugins.Pop()
		p.Unregister()
	}
}

// Returns a channel on which all plugins will be sent. Use it to iterate over all registered
// plugins.
func (ic *IRCClient) IterPlugins() <-chan Plugin {
	return ic.plugins.Iter()
}

// Get the pointer to a specific plugin that has been registered using RegisterPlugin()
// Name is the name the plugin identifies itself with when String() is called on it.
func (ic *IRCClient) GetPlugin(name string) (Plugin, bool) {
	return ic.plugins.GetPlugin(name)
}

// Sends a reply to a parsed message from a user. This is mostly intended for plugins
// and will automatically distinguish between channel and query messages. Note: Notice
// replies will currently be sent to the client using PRIVMSG, this may change in the
// future.
func (ic *IRCClient) Reply(cmd *IRCCommand, message string) {
	var target string
	if cmd.Target != ic.GetStringOption("Server", "nick") {
		target = cmd.Target
	} else {
		target = strings.SplitN(cmd.Source, "!", 2)[0]
	}
	ic.SendLine("PRIVMSG " + target + " :" + message)
}
<|endoftext|>


<commit_before>package render

import (
	"image"
	"image/color"
	"math"

	"github.com/oakmound/oak/alg"
	"github.com/oakmound/oak/physics"
)

// DrawCircle draws a circle on the input rgba, of color c.
func DrawCircle(rgba *image.RGBA, c color.Color, radius, thickness float64, offsets ...float64) {
	DrawCurve(rgba, c, radius, thickness, 0, 1, offsets...)
}

// DrawCurve draws a curve inward on the input rgba, of color c.
func DrawCurve(rgba *image.RGBA, c color.Color, radius, thickness, initialAngle, circlePercentage float64, offsets ...float64) {
	offX := 0.0
	offY := 0.0
	if len(offsets) > 0 {
		offX = offsets[0]
		if len(offsets) > 1 {
			offY = offsets[1]
		}
	}
	// Todo: use floatgeom not vectors
	rVec := physics.NewVector(radius+offX, radius+offY)
	delta := physics.AngleVector(initialAngle)
	circum := 2 * radius * math.Pi
	rotation := 180 / circum
	for j := 0.0; j < circum*2*circlePercentage; j++ {
		delta.Rotate(rotation)
		// We add rVec to move from -1->1 to 0->2 in terms of radius scale
		start := delta.Copy().Scale(radius).Add(rVec)
		for i := 0.0; i <= thickness; i++ {
			// this pixel is radius minus the delta, to move inward
			cur := start.Add(delta.Copy().Scale(-1))
			rgba.Set(alg.RoundF64(cur.X()), alg.RoundF64(cur.Y()), c)
		}
	}
}
<commit_msg>Add render.NewCircle<commit_after>package render

import (
	"image"
	"image/color"
	"math"

	"github.com/oakmound/oak/alg"
	"github.com/oakmound/oak/physics"
)

// NewCircle creates a sprite and draws a circle onto it
func NewCircle(c color.Color, radius, thickness float64, offsets ...float64) *Sprite {
	sp := NewEmptySprite(0, 0, int(radius)*2, int(radius)*2)
	DrawCircle(sp.GetRGBA(), c, radius, thickness, offsets...)
	return sp
}

// DrawCircle draws a circle on the input rgba, of color c.
func DrawCircle(rgba *image.RGBA, c color.Color, radius, thickness float64, offsets ...float64) {
	DrawCurve(rgba, c, radius, thickness, 0, 1, offsets...)
}

// DrawCurve draws a curve inward on the input rgba, of color c.
func DrawCurve(rgba *image.RGBA, c color.Color, radius, thickness, initialAngle, circlePercentage float64, offsets ...float64) {
	offX := 0.0
	offY := 0.0
	if len(offsets) > 0 {
		offX = offsets[0]
		if len(offsets) > 1 {
			offY = offsets[1]
		}
	}
	// Todo: use floatgeom not vectors
	rVec := physics.NewVector(radius+offX, radius+offY)
	delta := physics.AngleVector(initialAngle)
	circum := 2 * radius * math.Pi
	rotation := 180 / circum
	for j := 0.0; j < circum*2*circlePercentage; j++ {
		delta.Rotate(rotation)
		// We add rVec to move from -1->1 to 0->2 in terms of radius scale
		start := delta.Copy().Scale(radius).Add(rVec)
		for i := 0.0; i <= thickness; i++ {
			// this pixel is radius minus the delta, to move inward
			cur := start.Add(delta.Copy().Scale(-1))
			rgba.Set(alg.RoundF64(cur.X()), alg.RoundF64(cur.Y()), c)
		}
	}
}
<|endoftext|>


<commit_before>package repo

import (
	"fmt"
	"testing"
)

type User struct {
	Jid      string
	Password string
	Mid      string
}

func encrypt(jid, password, secretMsg, filename string, selfenc bool, mid ...string) (string, error) {
	fmt.Printf("%s encrypts for %s \n", jid, mid)
	ciphertext, err := EncryptMSG(jid, password, secretMsg, filename, selfenc, mid...)
	return ciphertext, err
}

func decrypt(jid, password, ciphertext string) (string, error) {
	fmt.Printf("%s decrypts for %s \n", jid, ciphertext[:20])
	plaintext, err := DecryptMSG(jid, password, ciphertext)
	return plaintext, err
}

func maliciousUserHasDecrypted(decryptedText, originalText string, user User, maliciousUsers ...User) bool {
	for _, maliciousUser := range maliciousUsers {
		// message successfully decrypted by a malicious user?
		if decryptedText == originalText && user == maliciousUser {
			return true
		}
	}
	return false
}

func TestID(t *testing.T) {

	// Testusers with valid mids generated by deadlock.
	alice := User{"alice@jabber.de/laptop", "3lrj;2lq3rj;lkqjwflkjwf", "Jw7xyd3jrG4d4TkQmUzDKLwbH9RPcEV47SAFRJtCEFY6c"}
	bob := User{"bob@jabber.de/work", "lk23j4lk2jlk3j4l2k3j12333", "2JHpZWEypyBNxN1pe6mptBa4uFsNwj54r3DXegdLGuKanh"}
	bruce := User{"bruce@jabber.de/rsa", "l3kjr;l33;)JLJK90092", "j9VD7e2vgrxbxJX4i3ut4AGg47S8yoyJN5793ti1NNdWc"}
	micrathene := User{"micrathene@jabber.de/forest", "lijk3lk*(3l#KJ8#:Lk#", "cewNAcGCRoqbB95JfgAyHFpXv4ka7hroUUkqQEx6vpdVE"}

	originalText := "This is a very secret message."
	ciphertext, err := encrypt(alice.Jid, alice.Password, originalText, "0xDEADBEEF", false, bob.Mid, bruce.Mid)
	if err != nil {
		t.Log("Error enctypting plaintext.", err)
	}
	for _, user := range []User{alice, bob, bruce, micrathene} {
		decryptedtext, _ := DecryptMSG(user.Jid, user.Password, ciphertext)
		if maliciousUserHasDecrypted(decryptedtext, originalText, user, micrathene, alice /* malicious users*/) {
			t.Errorf("%s souldn't be able to decrypt the ciphertext.\n", user.Jid)
		}
		t.Logf("User %s tries to encrypt: %t\n", user.Jid, decryptedtext == originalText)
	}
}
<commit_msg>id_test.go: Some code cleanup.<commit_after>package repo

import (
	"fmt"
	"testing"
)

type User struct {
	Name     string
	Jid      string
	Password string
	Mid      string
}

func encrypt(jid, password, secretMsg, filename string, selfenc bool, mid ...string) (string, error) {
	ciphertext, err := EncryptMSG(jid, password, secretMsg, filename, selfenc, mid...)
	return ciphertext, err
}

func maliciousUserHasDecrypted(decryptedText, originalText string, user *User, maliciousUsers ...*User) bool {
	for _, maliciousUser := range maliciousUsers {
		// message successfully decrypted by a malicious user?
		if decryptedText == originalText && user == maliciousUser {
			return true
		}
	}
	return false
}

func (u *User) String() string {
	return fmt.Sprintf("%s", u.Name)
}

func TestID(t *testing.T) {

	// sender
	alice := &User{
		"Alice",
		"alice@jabber.de/laptop",
		"3lrj;2lq3rj;lkqjwflkjwf",
		"Jw7xyd3jrG4d4TkQmUzDKLwbH9RPcEV47SAFRJtCEFY6c",
	}

	// receivers
	bob := &User{
		"Bob,",
		"bob@jabber.de/work",
		"lk23j4lk2jlk3j4l2k3j12333",
		"2JHpZWEypyBNxN1pe6mptBa4uFsNwj54r3DXegdLGuKanh",
	}
	bruce := &User{
		"Bruce",
		"bruce@jabber.de/rsa",
		"l3kjr;l33;)JLJK90092",
		"j9VD7e2vgrxbxJX4i3ut4AGg47S8yoyJN5793ti1NNdWc",
	}

	// indruder
	micrathene := &User{
		"Micrathene",
		"micrathene@jabber.de/forest",
		"lijk3lk*(3l#KJ8#:Lk#",
		"cewNAcGCRoqbB95JfgAyHFpXv4ka7hroUUkqQEx6vpdVE",
	}

	originalText := "This is a very secret message."
	receivers := []*User{bob, bruce}
	receiverMids := []string{}
	for _, receiver := range receivers {
		receiverMids = append(receiverMids, receiver.Mid)
	}
	fmt.Printf("%s encrypts for %s\n", alice, receivers)
	ciphertext, err := encrypt(alice.Jid, alice.Password, originalText, "0xDEADBEEF", false, receiverMids...)
	if err != nil {
		t.Log("Error enctypting plaintext.", err)
	}
	for _, user := range []*User{alice, bob, bruce, micrathene} {
		decryptedtext, _ := DecryptMSG(user.Jid, user.Password, ciphertext)
		if maliciousUserHasDecrypted(decryptedtext, originalText, user, micrathene, alice /* malicious users*/) {
			t.Errorf("%s souldn't be able to decrypt the ciphertext.\n", user.Jid)
		}
		fmt.Printf("User %s tries to encrypt: %t\n", user, decryptedtext == originalText)
	}
}
<|endoftext|>


<commit_before>package ws

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"reflect"
	"strings"
	"testing"
)

func TestRequestReset(t *testing.T) {
	for i, test := range []struct {
		url        string
		expHost    string
		expPath    string
		protocols  []string
		extensions []string
		headers    http.Header
		err        bool
	}{
		{
			url:        "wss://websocket.com/chat",
			expHost:    "websocket.com",
			expPath:    "/chat",
			protocols:  []string{"subproto", "hello"},
			extensions: []string{"foo; bar=1", "baz"},
			headers: http.Header{
				"Origin": []string{"https://websocket.com"},
			},
		},
		{
			url: "websocket.com/chat",
			err: true,
		},
	} {
		commonHeaders := map[string]string{
			headerConnection: "Upgrade",
			headerUpgrade:    "websocket",
			headerSecVersion: "13",
		}

		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
			req := getRequest()
			err := req.Reset(test.url, test.headers, test.protocols, test.extensions)
			if test.err && err == nil {
				t.Errorf("expected error; got nil")
			}
			if !test.err && err != nil {
				t.Errorf("unexpected error: %s", err)
			}
			if test.err {
				return
			}

			buf := &bytes.Buffer{}
			if err = req.Write(buf); err != nil {
				t.Errorf("dumping request error: %s", err)
				return
			}

			r, err := http.ReadRequest(bufio.NewReader(buf))
			if err != nil {
				t.Errorf("read request error: %s", err)
				return
			}

			if r.Method != "GET" {
				t.Errorf("http method is %s; want GET", r.Method)
			}
			if r.ProtoMinor != 1 {
				t.Errorf("http proto minor is %d; want 1", r.ProtoMinor)
			}
			if r.ProtoMajor != 1 {
				t.Errorf("http proto major is %d; want 1", r.ProtoMajor)
			}
			if r.URL.Path != test.expPath {
				t.Errorf("http path is %s; want %s", r.URL.Path, test.expPath)
			}

			key := r.Header.Get(headerSecKey)
			bts, err := base64.StdEncoding.DecodeString(key)
			if err != nil {
				t.Errorf("bad %q header: %s", headerSecKey, err)
			}
			if n := len(bts); n != 16 {
				t.Errorf("nonce len is %d; want 16", n)
			}
			r.Header.Del(headerSecKey)

			sub := r.Header.Get(headerSecProtocol)
			protocols := strings.Split(sub, ",")
			for i, p := range protocols {
				protocols[i] = strings.TrimSpace(p)
			}
			if !reflect.DeepEqual(protocols, test.protocols) {
				t.Errorf("%q headers is %v; want %s", headerSecProtocol, protocols, test.protocols)
			}
			r.Header.Del(headerSecProtocol)

			ext := r.Header.Get(headerSecExtensions)
			extensions := strings.Split(ext, ",")
			for i, e := range extensions {
				extensions[i] = strings.TrimSpace(e)
			}
			if !reflect.DeepEqual(extensions, test.extensions) {
				t.Errorf("%q headers is %v; want %s", headerSecExtensions, extensions, test.extensions)
			}
			r.Header.Del(headerSecExtensions)

			for key, exp := range commonHeaders {
				if act := r.Header.Get(key); act != exp {
					t.Errorf("http %q header is %q; want %q", key, act, exp)
				}
				r.Header.Del(key)
			}
			for key, exp := range test.headers {
				if act := r.Header.Get(key); act != exp[0] {
					t.Errorf("http %q custom header is %q; want %q", key, act, exp[0])
				}
				r.Header.Del(key)
			}
			if len(r.Header) != 0 {
				t.Errorf("http request has extra headers:\n\t%v", r.Header)
			}
		})
	}
}

func makeAccept(nonce [nonceSize]byte) string {
	accept := make([]byte, acceptSize)
	putAccept(nonce, accept)
	return string(accept)
}

func BenchmarkMakeAccept(b *testing.B) {
	var nonce [nonceSize]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		b.Fatal(err)
	}
	p := make([]byte, acceptSize)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		putAccept(nonce, p)
	}
}

func BenchmarkCheckNonce(b *testing.B) {
	var nonce [nonceSize]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		b.Fatal(err)
	}

	accept := makeAccept(nonce)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = checkNonce(accept, nonce)
	}
}
<commit_msg>rename benchmark<commit_after>package ws

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"reflect"
	"strings"
	"testing"
)

func TestRequestReset(t *testing.T) {
	for i, test := range []struct {
		url        string
		expHost    string
		expPath    string
		protocols  []string
		extensions []string
		headers    http.Header
		err        bool
	}{
		{
			url:        "wss://websocket.com/chat",
			expHost:    "websocket.com",
			expPath:    "/chat",
			protocols:  []string{"subproto", "hello"},
			extensions: []string{"foo; bar=1", "baz"},
			headers: http.Header{
				"Origin": []string{"https://websocket.com"},
			},
		},
		{
			url: "websocket.com/chat",
			err: true,
		},
	} {
		commonHeaders := map[string]string{
			headerConnection: "Upgrade",
			headerUpgrade:    "websocket",
			headerSecVersion: "13",
		}

		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
			req := getRequest()
			err := req.Reset(test.url, test.headers, test.protocols, test.extensions)
			if test.err && err == nil {
				t.Errorf("expected error; got nil")
			}
			if !test.err && err != nil {
				t.Errorf("unexpected error: %s", err)
			}
			if test.err {
				return
			}

			buf := &bytes.Buffer{}
			if err = req.Write(buf); err != nil {
				t.Errorf("dumping request error: %s", err)
				return
			}

			r, err := http.ReadRequest(bufio.NewReader(buf))
			if err != nil {
				t.Errorf("read request error: %s", err)
				return
			}

			if r.Method != "GET" {
				t.Errorf("http method is %s; want GET", r.Method)
			}
			if r.ProtoMinor != 1 {
				t.Errorf("http proto minor is %d; want 1", r.ProtoMinor)
			}
			if r.ProtoMajor != 1 {
				t.Errorf("http proto major is %d; want 1", r.ProtoMajor)
			}
			if r.URL.Path != test.expPath {
				t.Errorf("http path is %s; want %s", r.URL.Path, test.expPath)
			}

			key := r.Header.Get(headerSecKey)
			bts, err := base64.StdEncoding.DecodeString(key)
			if err != nil {
				t.Errorf("bad %q header: %s", headerSecKey, err)
			}
			if n := len(bts); n != 16 {
				t.Errorf("nonce len is %d; want 16", n)
			}
			r.Header.Del(headerSecKey)

			sub := r.Header.Get(headerSecProtocol)
			protocols := strings.Split(sub, ",")
			for i, p := range protocols {
				protocols[i] = strings.TrimSpace(p)
			}
			if !reflect.DeepEqual(protocols, test.protocols) {
				t.Errorf("%q headers is %v; want %s", headerSecProtocol, protocols, test.protocols)
			}
			r.Header.Del(headerSecProtocol)

			ext := r.Header.Get(headerSecExtensions)
			extensions := strings.Split(ext, ",")
			for i, e := range extensions {
				extensions[i] = strings.TrimSpace(e)
			}
			if !reflect.DeepEqual(extensions, test.extensions) {
				t.Errorf("%q headers is %v; want %s", headerSecExtensions, extensions, test.extensions)
			}
			r.Header.Del(headerSecExtensions)

			for key, exp := range commonHeaders {
				if act := r.Header.Get(key); act != exp {
					t.Errorf("http %q header is %q; want %q", key, act, exp)
				}
				r.Header.Del(key)
			}
			for key, exp := range test.headers {
				if act := r.Header.Get(key); act != exp[0] {
					t.Errorf("http %q custom header is %q; want %q", key, act, exp[0])
				}
				r.Header.Del(key)
			}
			if len(r.Header) != 0 {
				t.Errorf("http request has extra headers:\n\t%v", r.Header)
			}
		})
	}
}

func makeAccept(nonce [nonceSize]byte) string {
	accept := make([]byte, acceptSize)
	putAccept(nonce, accept)
	return string(accept)
}

func BenchmarkPutAccept(b *testing.B) {
	var nonce [nonceSize]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		b.Fatal(err)
	}
	p := make([]byte, acceptSize)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		putAccept(nonce, p)
	}
}

func BenchmarkCheckNonce(b *testing.B) {
	var nonce [nonceSize]byte
	_, err := rand.Read(nonce[:])
	if err != nil {
		b.Fatal(err)
	}

	accept := makeAccept(nonce)

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		_ = checkNonce(accept, nonce)
	}
}
<|endoftext|>


<commit_before>// Simple log replacement for go with Verbosity and Debug levels, and
// multi-stream output support.
//
// (C) by Marco Paganini <paganini AT paganini DOT net>

package logger

import (
	"fmt"
	"io"
	"os"
)

// Logger represents a logger object
type Logger struct {
	verbose      int
	debug        int
	outputs      []io.Writer
	mirrorOutput io.Writer
}

// New Creates a new Logger instance.
func New(prefix string) *Logger {
	return &Logger{
		verbose:      0,
		debug:        0,
		outputs:      []io.Writer{os.Stderr},
		mirrorOutput: nil}
}

// SetVerboseLevel sets the verbosity level for this log instance.
func (o *Logger) SetVerboseLevel(n int) {
	o.verbose = n
}

// SetDebugLevel sets the debugging level for this log instance.
func (o *Logger) SetDebugLevel(n int) {
	o.debug = n
}

// SetOutputs sets all logging outputs to the outputs presented
// in the slice of io.Writers.
func (o *Logger) SetOutputs(outputs []io.Writer) {
	o.outputs = outputs
}

// SetMirrorOutput sets the mirror output stream to the writers.
func (o *Logger) SetMirrorOutput(output io.Writer) {
	o.mirrorOutput = output
}

// writeString sends the string to all defined outputs if the requested level
// is less than or equal to the configured verbose level. Note that if the
// mirrorOutput stream is non nil, the message is always written to it,
// independent of the error level.
func (o *Logger) writeString(level int, s string) {
	// Conditionally output to all streams
	if level <= o.verbose {
		for _, w := range o.outputs {
			io.WriteString(w, s)
		}
	}
	// Output to mirror output if non-nil
	if o.mirrorOutput != nil {
		io.WriteString(o.mirrorOutput, s)
	}
}

// Println prints the message to the output streams followed by a newline.
func (o *Logger) Println(v ...interface{}) {
	o.writeString(0, fmt.Sprintln(v...))
}

// Printf uses the formatting string and variables to print a message to the
// output streams.
func (o *Logger) Printf(format string, v ...interface{}) {
	o.writeString(0, fmt.Sprintf(format, v...))
}

// Fatalln prints the message to the output streams followed by a newline
// and calls os.Exit(1).
func (o *Logger) Fatalln(v ...interface{}) {
	o.writeString(0, fmt.Sprintln(v...))
	os.Exit(1)
}

// Fatal is a convenience alias for Fatalln.
func (o *Logger) Fatal(v ...interface{}) {
	o.Fatalln(v...)
}

// Fatalf prints a formatted message to the output streams and calls os.Exit(1).
func (o *Logger) Fatalf(format string, v ...interface{}) {
	o.writeString(0, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Verboseln prints the message to the output streams, followed by a newline,
// if the current verbose level is greater than or equal the specified
// verbosity level.
func (o *Logger) Verboseln(level int, v ...interface{}) {
	o.writeString(level, fmt.Sprintln(v...))
}

// Verbosef uses the formatting string and variables to print a message to the
// output streams if the current verbose level is greater than or equal to the
// specified verbose level.
func (o *Logger) Verbosef(level int, format string, v ...interface{}) {
	o.writeString(level, fmt.Sprintf(format, v...))
}

// Debugln prints the message to the output streams, followed by a newline,
// if the current debugging level is greater than or equal the specified
// debugging level.
func (o *Logger) Debugln(level int, v ...interface{}) {
	o.writeString(level, fmt.Sprintln(v...))
}

// Debugf uses the formatting string and variables to print a message to the
// output streams if the current debugging level is greater than or equal to the
// specified debugging level.
func (o *Logger) Debugf(level int, format string, v ...interface{}) {
	o.writeString(level, fmt.Sprintf(format, v...))
}
<commit_msg>Add WithLogger/Logf support (log on contexts).<commit_after>// Simple log replacement for go with Verbosity and Debug levels, and
// multi-stream output support.
//
// (C) by Marco Paganini <paganini AT paganini DOT net>

package logger

import (
	"context"
	"fmt"
	"io"
	"os"
)

// Logger represents a logger object
type Logger struct {
	verbose      int
	debug        int
	outputs      []io.Writer
	mirrorOutput io.Writer
}

// New Creates a new Logger instance.
func New(prefix string) *Logger {
	return &Logger{
		verbose:      0,
		debug:        0,
		outputs:      []io.Writer{os.Stderr},
		mirrorOutput: nil}
}

// key for Context use.
type key int

const (
	keyLogger = key(iota)
)

// SetVerboseLevel sets the verbosity level for this log instance.
func (o *Logger) SetVerboseLevel(n int) {
	o.verbose = n
}

// SetDebugLevel sets the debugging level for this log instance.
func (o *Logger) SetDebugLevel(n int) {
	o.debug = n
}

// SetOutputs sets all logging outputs to the outputs presented
// in the slice of io.Writers.
func (o *Logger) SetOutputs(outputs []io.Writer) {
	o.outputs = outputs
}

// SetMirrorOutput sets the mirror output stream to the writers.
func (o *Logger) SetMirrorOutput(output io.Writer) {
	o.mirrorOutput = output
}

// writeString sends the string to all defined outputs if the requested level
// is less than or equal to the configured verbose level. Note that if the
// mirrorOutput stream is non nil, the message is always written to it,
// independent of the error level.
func (o *Logger) writeString(level int, s string) {
	// Conditionally output to all streams
	if level <= o.verbose {
		for _, w := range o.outputs {
			io.WriteString(w, s)
		}
	}
	// Output to mirror output if non-nil
	if o.mirrorOutput != nil {
		io.WriteString(o.mirrorOutput, s)
	}
}

// Println prints the message to the output streams followed by a newline.
func (o *Logger) Println(v ...interface{}) {
	o.writeString(0, fmt.Sprintln(v...))
}

// Printf uses the formatting string and variables to print a message to the
// output streams.
func (o *Logger) Printf(format string, v ...interface{}) {
	o.writeString(0, fmt.Sprintf(format, v...))
}

// Fatalln prints the message to the output streams followed by a newline
// and calls os.Exit(1).
func (o *Logger) Fatalln(v ...interface{}) {
	o.writeString(0, fmt.Sprintln(v...))
	os.Exit(1)
}

// Fatal is a convenience alias for Fatalln.
func (o *Logger) Fatal(v ...interface{}) {
	o.Fatalln(v...)
}

// Fatalf prints a formatted message to the output streams and calls os.Exit(1).
func (o *Logger) Fatalf(format string, v ...interface{}) {
	o.writeString(0, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Verboseln prints the message to the output streams, followed by a newline,
// if the current verbose level is greater than or equal the specified
// verbosity level.
func (o *Logger) Verboseln(level int, v ...interface{}) {
	o.writeString(level, fmt.Sprintln(v...))
}

// Verbosef uses the formatting string and variables to print a message to the
// output streams if the current verbose level is greater than or equal to the
// specified verbose level.
func (o *Logger) Verbosef(level int, format string, v ...interface{}) {
	o.writeString(level, fmt.Sprintf(format, v...))
}

// Debugln prints the message to the output streams, followed by a newline,
// if the current debugging level is greater than or equal the specified
// debugging level.
func (o *Logger) Debugln(level int, v ...interface{}) {
	o.writeString(level, fmt.Sprintln(v...))
}

// Debugf uses the formatting string and variables to print a message to the
// output streams if the current debugging level is greater than or equal to the
// specified debugging level.
func (o *Logger) Debugf(level int, format string, v ...interface{}) {
	o.writeString(level, fmt.Sprintf(format, v...))
}

// WithLogger returns a new context with the logger object added to it.
func WithLogger(ctx context.Context, log Logger) context.Context {
	return context.WithValue(ctx, keyLogger, log)
}

// Logf returns the logger function from the context. If no logger function has
// been set, create a new logger object and return it. Users should not rely on
// this behavior and set their own logger functions.
func Logf(ctx context.Context, log Logger) *Logger {
	ret, ok := ctx.Value(keyLogger).(*Logger)
	if !ok {
		panic("internal error: No logger function set or wrong type.")
	}
	return ret
}
<|endoftext|>


<commit_before>package fluent

import (
	"errors"
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config   Config
	postCh   chan message
	buffer   []byte
	conn     net.Conn
	ticker   *time.Ticker
	logError bool
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config:   config,
		postCh:   make(chan message, config.ChannelLength),
		buffer:   make([]byte, config.BufferLength),
		ticker:   time.NewTicker(config.BufferingTimeout),
		logError: true,
	}
	go logger.loop()
	defer logger.sendMessage()

	return logger
}

// You can send message to logger's goroutine via channel.
// This logging is executed asynchronously.
func (l *Logger) Post(tag string, data interface{}) {
	tag = l.prependTagPrefix(tag)
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

// You can send message immediately to fluentd.
func (l *Logger) Log(tag string, data interface{}) error {
	tag = l.prependTagPrefix(tag)
	msg := &message{tag: tag, time: time.Now(), data: data}
	pack, err := msg.toMsgpack()
	if err != nil {
		return err
	}

	l.buffer = append(l.buffer, pack...)
	return l.sendMessage()
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() error {
	if len(l.buffer) == 0 {
		return errors.New("Buffer is empty")
	}

	l.connect()
	if l.conn == nil {
		return errors.New("Failed to establish connection with fluentd")
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
	return err
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			l.logError = true
			return
		}
	}

	if l.logError {
		log.Printf("failed to establish connection with fluentd: " + err.Error())
		l.logError = false
	}
}

func (l *Logger) prependTagPrefix(tag string) string {
	if l.config.TagPrefix != "" {
		tag = l.config.TagPrefix + "." + tag
	}
	return tag
}
<commit_msg>Drop unnecessary defer and establish connection<commit_after>package fluent

import (
	"errors"
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config   Config
	postCh   chan message
	buffer   []byte
	conn     net.Conn
	ticker   *time.Ticker
	logError bool
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config:   config,
		postCh:   make(chan message, config.ChannelLength),
		buffer:   make([]byte, config.BufferLength),
		ticker:   time.NewTicker(config.BufferingTimeout),
		logError: true,
	}
	logger.connect()
	go logger.loop()

	return logger
}

// You can send message to logger's goroutine via channel.
// This logging is executed asynchronously.
func (l *Logger) Post(tag string, data interface{}) {
	tag = l.prependTagPrefix(tag)
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

// You can send message immediately to fluentd.
func (l *Logger) Log(tag string, data interface{}) error {
	tag = l.prependTagPrefix(tag)
	msg := &message{tag: tag, time: time.Now(), data: data}
	pack, err := msg.toMsgpack()
	if err != nil {
		return err
	}

	l.buffer = append(l.buffer, pack...)
	return l.sendMessage()
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() error {
	if len(l.buffer) == 0 {
		return errors.New("Buffer is empty")
	}

	l.connect()
	if l.conn == nil {
		return errors.New("Failed to establish connection with fluentd")
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
	return err
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			l.logError = true
			return
		}
	}

	if l.logError {
		log.Printf("failed to establish connection with fluentd: " + err.Error())
		l.logError = false
	}
}

func (l *Logger) prependTagPrefix(tag string) string {
	if l.config.TagPrefix != "" {
		tag = l.config.TagPrefix + "." + tag
	}
	return tag
}
<|endoftext|>


<commit_before>package fluent

import (
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config Config
	postCh chan message
	buffer []byte
	conn   net.Conn
	ticker *time.Ticker
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config: config,
		postCh: make(chan message, config.ChannelLength),
		ticker: time.NewTicker(config.BufferingTimeout),
	}
	go logger.loop()
	defer logger.sendMessage()

	return logger
}

// You can send message to logger's goroutine via channel.
func (l *Logger) Post(tag string, data interface{}) {
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() {
	if len(l.buffer) == 0 {
		return
	}

	l.connect()
	if l.conn == nil {
		return
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			return
		}
	}
	log.Printf("failed to establish connection with fluentd: " + err.Error())
}
<commit_msg>Stop writing duplicate error logs<commit_after>package fluent

import (
	"log"
	"net"
	"strconv"
	"time"
)

// Logger owns asynchronous logging to fluentd.
type Logger struct {
	config   Config
	postCh   chan message
	buffer   []byte
	conn     net.Conn
	ticker   *time.Ticker
	logError bool
}

// NewLogger() launches a goroutine to log and returns logger.
// Logger has a channel to interact with the goroutine.
func NewLogger(config Config) *Logger {
	config.applyDefaultValues()

	logger := &Logger{
		config:   config,
		postCh:   make(chan message, config.ChannelLength),
		ticker:   time.NewTicker(config.BufferingTimeout),
		logError: true,
	}
	go logger.loop()
	defer logger.sendMessage()

	return logger
}

// You can send message to logger's goroutine via channel.
func (l *Logger) Post(tag string, data interface{}) {
	l.postCh <- message{tag: tag, time: time.Now(), data: data}
}

func (l *Logger) loop() {
	for {
		select {
		case msg := <-l.postCh:
			pack, err := msg.toMsgpack()
			if err != nil {
				log.Printf("message pack dump error: " + err.Error())
				continue
			}

			l.buffer = append(l.buffer, pack...)
			if len(l.buffer) > l.config.BufferLength {
				l.sendMessage()
			}
		case <-l.ticker.C:
			l.sendMessage()
		}
	}
}

func (l *Logger) sendMessage() {
	if len(l.buffer) == 0 {
		return
	}

	l.connect()
	if l.conn == nil {
		return
	}

	_, err := l.conn.Write(l.buffer)

	if err == nil {
		l.buffer = l.buffer[0:0]
	} else {
		log.Printf("failed to send message: " + err.Error())
		l.conn.Close()
		l.conn = nil
	}
}

func (l *Logger) connect() {
	if l.conn != nil {
		return
	}

	var err error
	for i := 0; i < l.config.MaxTrialForConnection; i++ {
		l.conn, err = net.DialTimeout(
			"tcp",
			l.config.FluentHost+":"+strconv.Itoa(l.config.FluentPort),
			l.config.ConnectionTimeout,
		)

		if err == nil {
			l.logError = true
			return
		}
	}

	if l.logError {
		log.Printf("failed to establish connection with fluentd: " + err.Error())
		l.logError = false
	}
}
<|endoftext|>


<commit_before>package common

import (
	"errors"
	"time"
)

// Layouts suitable for passing to time.Parse.
var dateLayouts []string

func init() {
	// Generate layouts based on RFC 5322, section 3.3.
	dows := []string{"", "Mon, "}   // day-of-week
	days := []string{"2", "02"}     // day = 1*2DIGIT
	years := []string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
	seconds := []string{":05", ""}  // second
	// "-0700 (MST)" is not in RFC 5322, but is common.
	zones := []string{"-0700", "MST", "-0700 (MST)"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...

	for _, dow := range dows {
		for _, day := range days {
			for _, year := range years {
				for _, second := range seconds {
					for _, zone := range zones {
						s := dow + day + " Jan " + year + " 15:04" + second + " " + zone
						dateLayouts = append(dateLayouts, s)
					}
				}
			}
		}
	}
}

// Parse an IMAP date.
// Borrowed from https://golang.org/pkg/net/mail/#Header.Date
func ParseDate(date string) (*time.Time, error) {
	for _, layout := range dateLayouts {
		t, err := time.Parse(layout, date)
		if err == nil {
			return &t, nil
		}
	}
	return nil, errors.New("Cannot parse date")
}

// A message.
type Message struct {
	// The message identifier. Can be either a sequence number or a UID, depending
	// of how this message has been retrieved.
	Id uint32
	// The message envelope.
	Envelope *Envelope
	// The message body parts.
	Body map[string]*Literal
	// The message body structure.
	BodyStructure *BodyStructure
	// The message flags.
	Flags []string
	// The date the message was received by th server.
	InternalDate *time.Time
	// The message size.
	Size uint32
	// The message UID.
	Uid uint32
}

// Parse a message from fields.
func (m *Message) Parse(fields []interface{}) error {
	var key string
	for i, f := range fields {
		if i % 2 == 0 { // It's a key
			var ok bool
			if key, ok = f.(string); !ok {
				return errors.New("Key is not a string")
			}
		} else { // It's a value
			switch key {
			case "ENVELOPE":
				env, ok := f.([]interface{})
				if !ok {
					return errors.New("ENVELOPE is not a list")
				}

				m.Envelope = &Envelope{}
				if err := m.Envelope.Parse(env); err != nil {
					return err
				}
			case "BODYSTRUCTURE", "BODY":
				bs, ok := f.([]interface{})
				if !ok {
					return errors.New("BODYSTRUCTURE is not a list")
				}

				m.BodyStructure = &BodyStructure{}
				if err := m.BodyStructure.Parse(bs); err != nil {
					return err
				}
			case "FLAGS":
				flags, ok := f.([]interface{})
				if !ok {
					return errors.New("FLAGS is not a list")
				}

				m.Flags = make([]string, len(flags))
				for i, flag := range flags {
					m.Flags[i], _ = flag.(string)
				}
			case "INTERNALDATE":
				date, _ := f.(string)
				m.InternalDate, _ = ParseDate(date)
			case "SIZE":
				m.Size = ParseNumber(f)
			case "UID":
				m.Uid = ParseNumber(f)
			}
		}
	}
	return nil
}

// A message envelope, ie. message metadata from its headers.
type Envelope struct {
	// The message date.
	Date *time.Time
	// The message subject.
	Subject string
	// The From header addresses.
	From []*Address
	// The message senders.
	Sender []*Address
	// The Reply-To header addresses.
	ReplyTo []*Address
	// The To header addresses.
	To []*Address
	// The Cc header addresses.
	Cc []*Address
	// The Bcc header addresses.
	Bcc []*Address
	// The In-Reply-To header. Contains the parent Message-Id.
	InReplyTo string
	// The Message-Id header.
	MessageId string
}

// Parse an envelope from fields.
func (e *Envelope) Parse(fields []interface{}) error {
	if len(fields) < 10 {
		return errors.New("ENVELOPE doesn't contain 10 fields")
	}

	if date, ok := fields[0].(string); ok {
		e.Date, _ = ParseDate(date)
	}
	if subject, ok := fields[1].(string); ok {
		e.Subject = subject
	}
	if from, ok := fields[2].([]interface{}); ok {
		e.From = ParseAddressList(from)
	}
	if sender, ok := fields[3].([]interface{}); ok {
		e.Sender = ParseAddressList(sender)
	}
	if replyTo, ok := fields[4].([]interface{}); ok {
		e.ReplyTo = ParseAddressList(replyTo)
	}
	if to, ok := fields[5].([]interface{}); ok {
		e.To = ParseAddressList(to)
	}
	if cc, ok := fields[6].([]interface{}); ok {
		e.Cc = ParseAddressList(cc)
	}
	if bcc, ok := fields[7].([]interface{}); ok {
		e.Bcc = ParseAddressList(bcc)
	}
	if inReplyTo, ok := fields[8].(string); ok {
		e.InReplyTo = inReplyTo
	}
	if msgId, ok := fields[9].(string); ok {
		e.MessageId = msgId
	}

	return nil
}

// An address.
type Address struct {
	// The personal name.
	PersonalName string
	// The SMTP at-domain-list (source route).
	AtDomainList string
	// The mailbox name.
	MailboxName string
	// The host name.
	HostName string
}

func (addr *Address) String() string {
	return addr.MailboxName + "@" + addr.HostName
}

// Parse an address from fields.
func (addr *Address) Parse(fields []interface{}) error {
	if len(fields) < 4 {
		return errors.New("Address doesn't contain 4 fields")
	}

	if f, ok := fields[0].(string); ok {
		addr.PersonalName = f
	}
	if f, ok := fields[1].(string); ok {
		addr.AtDomainList = f
	}
	if f, ok := fields[2].(string); ok {
		addr.MailboxName = f
	}
	if f, ok := fields[3].(string); ok {
		addr.HostName = f
	}

	return nil
}

// Parse an address list from fields.
func ParseAddressList(fields []interface{}) (addrs []*Address) {
	for _, f := range fields {
		if addrFields, ok := f.([]interface{}); ok {
			addr := &Address{}
			if err := addr.Parse(addrFields); err == nil {
				addrs = append(addrs, addr)
			}
		}
	}
	return
}

// A body structure.
type BodyStructure struct {
	// The MIME type.
	MimeType string
	// The MIME subtype.
	MimeSubType string
	// The MIME parameters.
	Params map[string]string

	// The Content-Id header.
	Id string
	// The Content-Description header.
	Description string
	// The Content-Encoding header.
	Encoding string
	// The Content-Length header.
	Size uint32

	// The children parts, if multipart.
	Parts []*BodyStructure
}

// (("text" "plain" ("charset" "UTF-8") NIL NIL "quoted-printable" 2215 74)("text" "html" ("charset" "UTF-8") NIL NIL "quoted-printable" 4062 53) "alternative")

func (bs *BodyStructure) Parse(fields []interface{}) error {
	if len(fields) == 0 {
		return nil
	}

	switch fields[0].(type) {
	case []interface{}: // A multipart body part
		bs.MimeType = "multipart"

		end := 0
		for i, fi := range fields {
			switch f := fi.(type) {
			case []interface{}: // A part
				part := &BodyStructure{}
				if err := part.Parse(f); err != nil {
					return err
				}
				bs.Parts = append(bs.Parts, part)
			case string:
				end = i
			}

			if end > 0 {
				break
			}
		}

		bs.MimeSubType, _ = fields[end].(string)

		// TODO: extension data
	case string: // A non-multipart body part
		if len(fields) < 7 {
			return errors.New("Non-multipart body part doesn't have 7 fields")
		}

		bs.MimeType, _ = fields[0].(string)
		bs.MimeSubType, _ = fields[1].(string)

		params, _ := fields[2].([]interface{})
		bs.Params = map[string]string{}

		var key string
		for i, f := range params {
			p, ok := f.(string)
			if !ok {
				return errors.New("Parameter list contains a non-string")
			}

			if i % 2 == 0 {
				key = p
			} else {
				bs.Params[key] = p
			}
		}

		bs.Id, _ = fields[3].(string)
		bs.Description, _ = fields[4].(string)
		bs.Encoding, _ = fields[5].(string)
		bs.Size = ParseNumber(fields[6])

		// TODO: extension data
	}

	return nil
}
<commit_msg>Adds complete BODYSTRUCTURE support<commit_after>package common

import (
	"errors"
	"time"
)

// Layouts suitable for passing to time.Parse.
var dateLayouts []string

func init() {
	// Generate layouts based on RFC 5322, section 3.3.
	dows := []string{"", "Mon, "}   // day-of-week
	days := []string{"2", "02"}     // day = 1*2DIGIT
	years := []string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
	seconds := []string{":05", ""}  // second
	// "-0700 (MST)" is not in RFC 5322, but is common.
	zones := []string{"-0700", "MST", "-0700 (MST)"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...

	for _, dow := range dows {
		for _, day := range days {
			for _, year := range years {
				for _, second := range seconds {
					for _, zone := range zones {
						s := dow + day + " Jan " + year + " 15:04" + second + " " + zone
						dateLayouts = append(dateLayouts, s)
					}
				}
			}
		}
	}
}

// Parse an IMAP date.
// Borrowed from https://golang.org/pkg/net/mail/#Header.Date
func ParseDate(date string) (*time.Time, error) {
	for _, layout := range dateLayouts {
		t, err := time.Parse(layout, date)
		if err == nil {
			return &t, nil
		}
	}
	return nil, errors.New("Cannot parse date")
}

// A message.
type Message struct {
	// The message identifier. Can be either a sequence number or a UID, depending
	// of how this message has been retrieved.
	Id uint32
	// The message envelope.
	Envelope *Envelope
	// The message body parts.
	Body map[string]*Literal
	// The message body structure.
	BodyStructure *BodyStructure
	// The message flags.
	Flags []string
	// The date the message was received by th server.
	InternalDate *time.Time
	// The message size.
	Size uint32
	// The message UID.
	Uid uint32
}

// Parse a message from fields.
func (m *Message) Parse(fields []interface{}) error {
	var key string
	for i, f := range fields {
		if i % 2 == 0 { // It's a key
			var ok bool
			if key, ok = f.(string); !ok {
				return errors.New("Key is not a string")
			}
		} else { // It's a value
			switch key {
			case "ENVELOPE":
				env, ok := f.([]interface{})
				if !ok {
					return errors.New("ENVELOPE is not a list")
				}

				m.Envelope = &Envelope{}
				if err := m.Envelope.Parse(env); err != nil {
					return err
				}
			case "BODYSTRUCTURE", "BODY":
				bs, ok := f.([]interface{})
				if !ok {
					return errors.New("BODYSTRUCTURE is not a list")
				}

				m.BodyStructure = &BodyStructure{}
				if err := m.BodyStructure.Parse(bs); err != nil {
					return err
				}
			case "FLAGS":
				flags, ok := f.([]interface{})
				if !ok {
					return errors.New("FLAGS is not a list")
				}

				m.Flags = make([]string, len(flags))
				for i, flag := range flags {
					m.Flags[i], _ = flag.(string)
				}
			case "INTERNALDATE":
				date, _ := f.(string)
				m.InternalDate, _ = ParseDate(date)
			case "SIZE":
				m.Size = ParseNumber(f)
			case "UID":
				m.Uid = ParseNumber(f)
			}
		}
	}
	return nil
}

// A message envelope, ie. message metadata from its headers.
type Envelope struct {
	// The message date.
	Date *time.Time
	// The message subject.
	Subject string
	// The From header addresses.
	From []*Address
	// The message senders.
	Sender []*Address
	// The Reply-To header addresses.
	ReplyTo []*Address
	// The To header addresses.
	To []*Address
	// The Cc header addresses.
	Cc []*Address
	// The Bcc header addresses.
	Bcc []*Address
	// The In-Reply-To header. Contains the parent Message-Id.
	InReplyTo string
	// The Message-Id header.
	MessageId string
}

// Parse an envelope from fields.
func (e *Envelope) Parse(fields []interface{}) error {
	if len(fields) < 10 {
		return errors.New("ENVELOPE doesn't contain 10 fields")
	}

	if date, ok := fields[0].(string); ok {
		e.Date, _ = ParseDate(date)
	}
	if subject, ok := fields[1].(string); ok {
		e.Subject = subject
	}
	if from, ok := fields[2].([]interface{}); ok {
		e.From = ParseAddressList(from)
	}
	if sender, ok := fields[3].([]interface{}); ok {
		e.Sender = ParseAddressList(sender)
	}
	if replyTo, ok := fields[4].([]interface{}); ok {
		e.ReplyTo = ParseAddressList(replyTo)
	}
	if to, ok := fields[5].([]interface{}); ok {
		e.To = ParseAddressList(to)
	}
	if cc, ok := fields[6].([]interface{}); ok {
		e.Cc = ParseAddressList(cc)
	}
	if bcc, ok := fields[7].([]interface{}); ok {
		e.Bcc = ParseAddressList(bcc)
	}
	if inReplyTo, ok := fields[8].(string); ok {
		e.InReplyTo = inReplyTo
	}
	if msgId, ok := fields[9].(string); ok {
		e.MessageId = msgId
	}

	return nil
}

// An address.
type Address struct {
	// The personal name.
	PersonalName string
	// The SMTP at-domain-list (source route).
	AtDomainList string
	// The mailbox name.
	MailboxName string
	// The host name.
	HostName string
}

func (addr *Address) String() string {
	return addr.MailboxName + "@" + addr.HostName
}

// Parse an address from fields.
func (addr *Address) Parse(fields []interface{}) error {
	if len(fields) < 4 {
		return errors.New("Address doesn't contain 4 fields")
	}

	if f, ok := fields[0].(string); ok {
		addr.PersonalName = f
	}
	if f, ok := fields[1].(string); ok {
		addr.AtDomainList = f
	}
	if f, ok := fields[2].(string); ok {
		addr.MailboxName = f
	}
	if f, ok := fields[3].(string); ok {
		addr.HostName = f
	}

	return nil
}

// Parse an address list from fields.
func ParseAddressList(fields []interface{}) (addrs []*Address) {
	for _, f := range fields {
		if addrFields, ok := f.([]interface{}); ok {
			addr := &Address{}
			if err := addr.Parse(addrFields); err == nil {
				addrs = append(addrs, addr)
			}
		}
	}
	return
}

// A body structure.
type BodyStructure struct {
	// Basic fields

	// The MIME type.
	MimeType string
	// The MIME subtype.
	MimeSubType string
	// The MIME parameters.
	Params map[string]string

	// The Content-Id header.
	Id string
	// The Content-Description header.
	Description string
	// The Content-Encoding header.
	Encoding string
	// The Content-Length header.
	Size uint32

	// Type-specific fields

	// The children parts, if multipart.
	Parts []*BodyStructure
	// The envelope, if message/rfc822.
	Envelope *Envelope
	// The body structure, if message/rfc822.
	BodyStructure *BodyStructure
	// The number of lines, if text or message/rfc822.
	Lines uint32

	// Extension data

	// The Content-Disposition header.
	Disposition string
	// The Content-Language header, if multipart.
	Language []string
	// The content URI, if multipart.
	Location []string

	// The MD5 checksum.
	Md5 string
}

// (("text" "plain" ("charset" "UTF-8") NIL NIL "quoted-printable" 2215 74)("text" "html" ("charset" "UTF-8") NIL NIL "quoted-printable" 4062 53) "alternative")

func ParseParameters(fields []interface{}) (params map[string]string, err error) {
	params = map[string]string{}

	var key string
	for i, f := range fields {
		p, ok := f.(string)
		if !ok {
			err = errors.New("Parameter list contains a non-string")
			return
		}

		if i % 2 == 0 {
			key = p
		} else {
			params[key] = p
		}
	}

	return
}

func ParseStringList(fields []interface{}) ([]string, error) {
	list := make([]string, len(fields))
	for i, f := range fields {
		var ok bool
		if list[i], ok = f.(string); !ok {
			return nil, errors.New("String list contains a non-string")
		}
	}
	return list, nil
}

func (bs *BodyStructure) Parse(fields []interface{}) error {
	if len(fields) == 0 {
		return nil
	}

	switch fields[0].(type) {
	case []interface{}: // A multipart body part
		bs.MimeType = "multipart"

		end := 0
		for i, fi := range fields {
			switch f := fi.(type) {
			case []interface{}: // A part
				part := &BodyStructure{}
				if err := part.Parse(f); err != nil {
					return err
				}
				bs.Parts = append(bs.Parts, part)
			case string:
				end = i
			}

			if end > 0 {
				break
			}
		}

		bs.MimeSubType, _ = fields[end].(string)

		if len(fields) - end + 1 >= 4 { // Contains extension data
			params, _ := fields[end].([]interface{})
			bs.Params, _ = ParseParameters(params)

			bs.Disposition, _ = fields[end+1].(string)

			switch langs := fields[end+2].(type) {
			case string:
				bs.Language = []string{langs}
			case []interface{}:
				bs.Language, _ = ParseStringList(langs)
			}

			location, _ := fields[end+3].([]interface{})
			bs.Location, _ = ParseStringList(location)
		}
	case string: // A non-multipart body part
		if len(fields) < 7 {
			return errors.New("Non-multipart body part doesn't have 7 fields")
		}

		bs.MimeType, _ = fields[0].(string)
		bs.MimeSubType, _ = fields[1].(string)

		params, _ := fields[2].([]interface{})
		bs.Params, _ = ParseParameters(params)

		bs.Id, _ = fields[3].(string)
		bs.Description, _ = fields[4].(string)
		bs.Encoding, _ = fields[5].(string)
		bs.Size = ParseNumber(fields[6])

		end := 7

		// Type-specific fields
		if bs.MimeType == "message" && bs.MimeSubType == "rfc822" {
			envelope, _ := fields[end].([]interface{})
			bs.Envelope = &Envelope{}
			bs.Envelope.Parse(envelope)

			structure, _ := fields[end+1].([]interface{})
			bs.BodyStructure = &BodyStructure{}
			bs.BodyStructure.Parse(structure)

			bs.Lines = ParseNumber(fields[end+2])

			end += 3
		}
		if bs.MimeType == "text" {
			bs.Lines = ParseNumber(fields[end])
			end++
		}

		if len(fields) - end + 1 >= 4 { // Contains extension data
			bs.Md5, _ = fields[end].(string)
			bs.Disposition, _ = fields[end+1].(string)

			switch langs := fields[end+2].(type) {
			case string:
				bs.Language = []string{langs}
			case []interface{}:
				bs.Language, _ = ParseStringList(langs)
			}

			location, _ := fields[end+3].([]interface{})
			bs.Location, _ = ParseStringList(location)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package immortal

import (
	"github.com/immortal/logrotate"
	"github.com/immortal/multiwriter"
	"io"
	"log"
	"os/exec"
	"strings"
	"time"
)

func (self *Daemon) Log(msg string) {
	self.logger.Print(msg)
}

func (self *Daemon) Logger() {
	var (
		ch      chan error
		err     error
		file, w io.WriteCloser
	)

	ch = make(chan error)

	// create a multiwriter
	multi := multiwriter.New()
	var m *multiwriter.MultiWriter = multi.(*multiwriter.MultiWriter)

	if self.run.Logfile != "" {
		self.log = true
		file, err = logrotate.New(self.run.Logfile)
		if err != nil {
			log.Printf("Failed to open log file %q: %s\n", self.run.Logfile, err)
			return
		}
		m.Append(file)
	}

	runLogger := func() {
		command := strings.Fields(self.run.Logger)
		cmd := exec.Command(command[0], command[1:]...)
		w, err = cmd.StdinPipe()
		if err != nil {
			log.Printf("logger PIPE error: %s", err)
			ch <- err
			return
		}
		go func() {
			if err := cmd.Start(); err != nil {
				ch <- err
			}
			ch <- cmd.Wait()
		}()
	}

	if self.run.Logger != "" {
		self.log = true
		runLogger()

		go func() {
			for {
				select {
				case err = <-ch:
					log.Print("logger exited ", err.Error())
					m.Remove(w)
					time.Sleep(time.Second)
					runLogger()
					m.Append(w)
					//self.logger = log.New(multi, "", 0)
				}
			}
		}()
		m.Append(w)
	}

	// create the logger
	if self.log {
		self.logger = log.New(multi, "", 0)
	}
}
<commit_msg>	modified:   logger.go<commit_after>package immortal

import (
	"github.com/immortal/logrotate"
	"github.com/immortal/multiwriter"
	"io"
	"log"
	"os/exec"
	"strings"
	"time"
)

func (self *Daemon) Log(msg string) {
	self.logger.Print(msg)
}

func (self *Daemon) Logger() {
	var (
		ch      chan error
		err     error
		file, w io.WriteCloser
	)

	ch = make(chan error)

	// create a multiwriter
	multi := multiwriter.New()
	var m *multiwriter.MultiWriter = multi.(*multiwriter.MultiWriter)

	if self.run.Logfile != "" {
		self.log = true
		file, err = logrotate.New(self.run.Logfile)
		if err != nil {
			log.Printf("Failed to open log file %q: %s\n", self.run.Logfile, err)
			return
		}
		m.Append(file)
	}

	runLogger := func() {
		command := strings.Fields(self.run.Logger)
		cmd := exec.Command(command[0], command[1:]...)
		w, err = cmd.StdinPipe()
		if err != nil {
			log.Printf("logger PIPE error: %s", err)
			ch <- err
			return
		}
		go func() {
			if err := cmd.Start(); err != nil {
				ch <- err
			}
			ch <- cmd.Wait()
		}()
	}

	if self.run.Logger != "" {
		self.log = true
		runLogger()

		go func() {
			for {
				select {
				case err = <-ch:
					log.Print("logger exited ", err.Error())
					m.Remove(w)
					time.Sleep(time.Second)
					runLogger()
					m.Append(w)
				}
			}
		}()
		m.Append(w)
	}

	// create the logger
	if self.log {
		self.logger = log.New(multi, "", 0)
	}
}
<|endoftext|>


<commit_before>package qlog

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

type Logger struct {
	*logrus.Logger
}

var v *viper.Viper

func logLevels(baseLevel logrus.Level) (level []logrus.Level) {
	level = make([]logrus.Level, 0)
	for i := baseLevel; i > logrus.PanicLevel; i-- {
		level = append(level, i)
	}
	return
}

var DefaultLogger *Logger
var gDefaultLogLevel logrus.Level
var gReportCaller bool

func initViper() error {
	v = viper.New()
	v.AddConfigPath(".")
	v.AddConfigPath("/etc/qlog")
	v.AddConfigPath("./conf/")
	v.SetConfigName("logger")
	v.SetConfigType("yaml")

	v.SetDefault("logger.level", "debug")
	v.SetDefault("logger.reportcaller", false)

	if err := v.ReadInConfig(); err != nil {
		return err
	}

	return nil
}

func init() {
	var err error
	if err = initViper(); err != nil {
		panic(fmt.Sprint("[qlog] init viper error:", err))
	}

	if gDefaultLogLevel, err = logrus.ParseLevel(v.GetString("logger.level")); err != nil {
		panic(fmt.Sprint("[qlog] get default log level error:", err))
	}

	gReportCaller = v.GetBool("logger.reportcaller")

	if err = initFormatters(); err != nil {
		panic(fmt.Sprint("[qlog] init default formatter:", err))
	}

	if err = initHooks(); err != nil {
		panic(fmt.Sprint("[qlog] init default formatter:", err))
	}

	if len(gActivedHooks) > 0 {
		DefaultLogger = &Logger{
			Logger: &logrus.Logger{
				Out:          ioutil.Discard,
				Formatter:    gDefaultFormatter,
				Hooks:        gActivedHooks,
				Level:        gDefaultLogLevel,
				ExitFunc:     os.Exit,
				ReportCaller: gReportCaller,
			},
		}
	} else {
		DefaultLogger = &Logger{
			Logger: &logrus.Logger{
				Out:          os.Stderr,
				Formatter:    gDefaultFormatter,
				Hooks:        nil,
				Level:        gDefaultLogLevel,
				ExitFunc:     os.Exit,
				ReportCaller: gReportCaller,
			},
		}
	}
}
<commit_msg>add some system params<commit_after>package qlog

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

type Logger struct {
	*logrus.Logger
}

var v *viper.Viper

func logLevels(baseLevel logrus.Level) (level []logrus.Level) {
	level = make([]logrus.Level, 0)
	for i := baseLevel; i > logrus.PanicLevel; i-- {
		level = append(level, i)
	}
	return
}

var (
	// default logger object
	DefaultLogger *Logger

	// default logger settings
	gDefaultLogLevel logrus.Level
	gReportCaller    bool

	// system param
	gPid      = os.Getpid()
	gProgram  = filepath.Base(os.Args[0])
	gHost     = "unknownhost"
	gUserName = "unknownuser"
)

// shortHostname returns its argument, truncating at the first period.
// For instance, given "www.google.com" it returns "www".
func shortHostname(hostname string) string {
	if i := strings.Index(hostname, "."); i >= 0 {
		return hostname[:i]
	}
	return hostname
}

func initSysParams() error {
	h, err := os.Hostname()
	if err == nil {
		gHost = shortHostname(h)
	}

	current, err := user.Current()
	if err == nil {
		gUserName = current.Username
	}

	// Sanitize userName since it may contain filepath separators on Windows.
	gUserName = strings.Replace(gUserName, `\`, "_", -1)

	return nil
}

func initViper() error {
	v = viper.New()
	v.AddConfigPath(".")
	v.AddConfigPath("/etc/qlog")
	v.AddConfigPath("./conf/")
	v.SetConfigName("logger")
	v.SetConfigType("yaml")

	v.SetDefault("logger.level", "debug")
	v.SetDefault("logger.reportcaller", false)

	if err := v.ReadInConfig(); err != nil {
		return err
	}

	return nil
}

func init() {
	var err error

	if err = initSysParams(); err != nil {
		panic(fmt.Sprint("[qlog] init system param error:", err))
	}

	if err = initViper(); err != nil {
		panic(fmt.Sprint("[qlog] init viper error:", err))
	}

	if gDefaultLogLevel, err = logrus.ParseLevel(v.GetString("logger.level")); err != nil {
		panic(fmt.Sprint("[qlog] get default log level error:", err))
	}

	gReportCaller = v.GetBool("logger.reportcaller")

	if err = initFormatters(); err != nil {
		panic(fmt.Sprint("[qlog] init default formatter:", err))
	}

	if err = initHooks(); err != nil {
		panic(fmt.Sprint("[qlog] init default formatter:", err))
	}

	if len(gActivedHooks) > 0 {
		DefaultLogger = &Logger{
			Logger: &logrus.Logger{
				Out:          ioutil.Discard,
				Formatter:    gDefaultFormatter,
				Hooks:        gActivedHooks,
				Level:        gDefaultLogLevel,
				ExitFunc:     os.Exit,
				ReportCaller: gReportCaller,
			},
		}
	} else {
		DefaultLogger = &Logger{
			Logger: &logrus.Logger{
				Out:          os.Stderr,
				Formatter:    gDefaultFormatter,
				Hooks:        nil,
				Level:        gDefaultLogLevel,
				ExitFunc:     os.Exit,
				ReportCaller: gReportCaller,
			},
		}
	}
}
<|endoftext|>


<commit_before>package kiwi

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

// Logger keeps context and log record. There are many loggers initialized
// in different places of application. Loggers are safe for
// concurrent usage.
type (
	Logger struct {
		sync.RWMutex
		contextSrc map[interface{}]interface{}
		context    map[string]recVal
		pairs      map[string]recVal
	}
	Record interface {
		fmt.Stringer
		IsQuoted() bool
	}
	recVal struct {
		Val    string
		Type   uint8
		Quoted bool
	}
	fnVal struct { // вычислять при вызове log
		fn func() interface{}
	}
)

// obsoleted by recVal iface
const (
	emptyVal uint8 = iota
	stringVal
	integerVal
	floatVal
	booleanVal
	customVal // for use with `func() string`
)

// NewLogger creates logger instance.
func NewLogger() *Logger {
	return &Logger{
		contextSrc: make(map[interface{}]interface{}),
		context:    make(map[string]recVal),
		pairs:      make(map[string]recVal)}
}

// Log is the most common method for flushing previously added key-val pairs to an output.
// After current record is flushed all pairs removed from a record except contextSrc pairs.
func (l *Logger) Log(keyVals ...interface{}) {
	if len(keyVals) > 0 {
		l.Add(keyVals...)
	}
	l.Lock()

	record := l.pairs
	l.pairs = make(map[string]recVal)
	for key, val := range l.context {
		// pairs override context
		if _, ok := record[key]; !ok {
			record[key] = val
		}
	}
	l.Unlock()
	passRecordToOutput(record)
}

// Add a new key-recVal pairs to the log record. If a key already added then value will be
// updated. If a key already exists in a contextSrc then it will be overriden by a new
// recVal for a current record only. After flushing a record with Log() old context value
// will be restored.
func (l *Logger) Add(keyVals ...interface{}) *Logger {
	var key string
	l.Lock()
	for i, val := range keyVals {
		if i%2 == 0 {
			key = toRecordKey(val)
			continue
		}
		l.pairs[key] = toRecordValue(val)
	}
	// for odd number of key-val pairs just add label without recVal
	if len(keyVals)%2 == 1 {
		l.pairs[key] = recVal{"", emptyVal, false}
	}
	l.Unlock()
	return l
}

// With defines a context for the logger.
func (l *Logger) With(keyVals ...interface{}) *Logger {
	var (
		keySrc interface{}
		key    string
	)
	l.Lock()
	for i, val := range keyVals {
		if i%2 == 0 {
			keySrc = val
			key = toRecordKey(val)
			continue
		}
		l.contextSrc[keySrc] = val
		l.context[key] = toRecordValue(val)
	}
	// for odd number of key-val pairs just add label without recVal
	if len(keyVals)%2 == 1 {
		l.contextSrc[keySrc] = nil
		l.context[key] = recVal{"", emptyVal, false}
	}
	l.Unlock()
	return l
}

// Without drops some keys from a context for the logger.
func (l *Logger) Without(keys ...interface{}) *Logger {
	l.Lock()
	for _, key := range keys {
		if _, ok := l.contextSrc[key]; ok {
			delete(l.contextSrc, key)
			delete(l.context, toRecordKey(key))
		}
	}
	l.Unlock()
	return l
}

// WithTimestamp adds "timestamp" field to a context.
func (l *Logger) WithTimestamp(format string) *Logger {
	l.Lock()
	// TODO think about offer fmt.Stringer here instead of custom func?
	l.contextSrc["timestamp"] = func() string { return time.Now().Format(format) }
	l.context["timestamp"] = recVal{time.Now().Format(format), customVal, true}
	l.Unlock()
	return l
}

// Reset logger values added after last Log() call. It keeps contextSrc untouched.
func (l *Logger) Reset() *Logger {
	l.Lock()
	l.pairs = make(map[string]recVal)
	l.Unlock()
	return l
}

// ResetContext resets the context of the logger.
func (l *Logger) ResetContext() *Logger {
	l.Lock()
	l.contextSrc = make(map[interface{}]interface{})
	l.context = make(map[string]recVal)
	l.Unlock()
	return l
}

// GetContext returns copy of context saved in the logger.
func (l *Logger) GetContext() map[interface{}]interface{} {
	var contextSrc = make(map[interface{}]interface{})
	l.RLock()
	for k, v := range l.contextSrc {
		contextSrc[k] = v
	}
	l.RUnlock()
	return contextSrc
}

// GetRecord returns copy of current set of keys and values prepared for logging
// as strings. With context key-vals included.
// The most of Logger operations return *Logger itself but it made for operations
// chaining only. If you need get log pairs use GelRecord() for it.
func (l *Logger) GetRecord() map[string]string {
	var merged = make(map[string]string)
	l.RLock()
	for k, v := range l.context {
		merged[k] = v.Val
	}
	for k, v := range l.pairs {
		merged[k] = v.Val
	}
	l.RUnlock()
	return merged
}

func toRecordKey(val interface{}) string {
	if val == nil {
		return ""
	}
	switch val.(type) {
	case bool:
		if val.(bool) {
			return "true"
		}
		return "false"
	case int:
		return strconv.Itoa(val.(int))
	case int8:
		return strconv.FormatInt(int64(val.(int8)), 10)
	case int16:
		return strconv.FormatInt(int64(val.(int16)), 10)
	case int32:
		return strconv.FormatInt(int64(val.(int32)), 10)
	case int64:
		return strconv.FormatInt(int64(val.(int64)), 10)
	case uint8:
		return strconv.FormatUint(uint64(val.(uint8)), 10)
	case uint16:
		return strconv.FormatUint(uint64(val.(uint16)), 10)
	case uint32:
		return strconv.FormatUint(uint64(val.(uint32)), 10)
	case uint64:
		return strconv.FormatUint(uint64(val.(uint64)), 10)
	case fmt.Stringer:
		return val.(fmt.Stringer).String()
	default:
		return fmt.Sprintf("%v", val)
	}
}

func toRecordValue(val interface{}) recVal {
	if val == nil {
		return recVal{"", emptyVal, false}
	}
	switch val.(type) {
	case bool:
		if val.(bool) {
			return recVal{"true", booleanVal, false}
		}
		return recVal{"false", booleanVal, false}
	case int:
		return recVal{strconv.Itoa(val.(int)), integerVal, false}
	case int8:
		return recVal{strconv.FormatInt(int64(val.(int8)), 10), integerVal, false}
	case int16:
		return recVal{strconv.FormatInt(int64(val.(int16)), 10), integerVal, false}
	case int32:
		return recVal{strconv.FormatInt(int64(val.(int32)), 10), integerVal, false}
	case int64:
		return recVal{strconv.FormatInt(int64(val.(int64)), 10), integerVal, false}
	case uint8:
		return recVal{strconv.FormatUint(uint64(val.(uint8)), 10), integerVal, false}
	case uint16:
		return recVal{strconv.FormatUint(uint64(val.(uint16)), 10), integerVal, false}
	case uint32:
		return recVal{strconv.FormatUint(uint64(val.(uint32)), 10), integerVal, false}
	case uint64:
		return recVal{strconv.FormatUint(uint64(val.(uint64)), 10), integerVal, false}
	case Record:
		return recVal{val.(Record).String(), stringVal, true}
	case fmt.Stringer:
		return recVal{val.(fmt.Stringer).String(), stringVal, true}
	default:
		return recVal{fmt.Sprintf("%v", val), stringVal, true}
	}
}
<commit_msg>Simplify interface definition.<commit_after>package kiwi

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

// Logger keeps context and log record. There are many loggers initialized
// in different places of application. Loggers are safe for
// concurrent usage.
type (
	Logger struct {
		sync.RWMutex
		contextSrc map[interface{}]interface{}
		context    map[string]recVal
		pairs      map[string]recVal
	}
	Record interface {
		String() string
		IsQuoted() bool
	}
	recVal struct {
		Val    string
		Type   uint8
		Quoted bool
	}
	fnVal struct { // вычислять при вызове log
		fn func() interface{}
	}
)

// obsoleted by recVal iface
const (
	emptyVal uint8 = iota
	stringVal
	integerVal
	floatVal
	booleanVal
	customVal // for use with `func() string`
)

// NewLogger creates logger instance.
func NewLogger() *Logger {
	return &Logger{
		contextSrc: make(map[interface{}]interface{}),
		context:    make(map[string]recVal),
		pairs:      make(map[string]recVal)}
}

// Log is the most common method for flushing previously added key-val pairs to an output.
// After current record is flushed all pairs removed from a record except contextSrc pairs.
func (l *Logger) Log(keyVals ...interface{}) {
	if len(keyVals) > 0 {
		l.Add(keyVals...)
	}
	l.Lock()

	record := l.pairs
	l.pairs = make(map[string]recVal)
	for key, val := range l.context {
		// pairs override context
		if _, ok := record[key]; !ok {
			record[key] = val
		}
	}
	l.Unlock()
	passRecordToOutput(record)
}

// Add a new key-recVal pairs to the log record. If a key already added then value will be
// updated. If a key already exists in a contextSrc then it will be overriden by a new
// recVal for a current record only. After flushing a record with Log() old context value
// will be restored.
func (l *Logger) Add(keyVals ...interface{}) *Logger {
	var key string
	l.Lock()
	for i, val := range keyVals {
		if i%2 == 0 {
			key = toRecordKey(val)
			continue
		}
		l.pairs[key] = toRecordValue(val)
	}
	// for odd number of key-val pairs just add label without recVal
	if len(keyVals)%2 == 1 {
		l.pairs[key] = recVal{"", emptyVal, false}
	}
	l.Unlock()
	return l
}

// With defines a context for the logger.
func (l *Logger) With(keyVals ...interface{}) *Logger {
	var (
		keySrc interface{}
		key    string
	)
	l.Lock()
	for i, val := range keyVals {
		if i%2 == 0 {
			keySrc = val
			key = toRecordKey(val)
			continue
		}
		l.contextSrc[keySrc] = val
		l.context[key] = toRecordValue(val)
	}
	// for odd number of key-val pairs just add label without recVal
	if len(keyVals)%2 == 1 {
		l.contextSrc[keySrc] = nil
		l.context[key] = recVal{"", emptyVal, false}
	}
	l.Unlock()
	return l
}

// Without drops some keys from a context for the logger.
func (l *Logger) Without(keys ...interface{}) *Logger {
	l.Lock()
	for _, key := range keys {
		if _, ok := l.contextSrc[key]; ok {
			delete(l.contextSrc, key)
			delete(l.context, toRecordKey(key))
		}
	}
	l.Unlock()
	return l
}

// WithTimestamp adds "timestamp" field to a context.
func (l *Logger) WithTimestamp(format string) *Logger {
	l.Lock()
	// TODO think about offer fmt.Stringer here instead of custom func?
	l.contextSrc["timestamp"] = func() string { return time.Now().Format(format) }
	l.context["timestamp"] = recVal{time.Now().Format(format), customVal, true}
	l.Unlock()
	return l
}

// Reset logger values added after last Log() call. It keeps contextSrc untouched.
func (l *Logger) Reset() *Logger {
	l.Lock()
	l.pairs = make(map[string]recVal)
	l.Unlock()
	return l
}

// ResetContext resets the context of the logger.
func (l *Logger) ResetContext() *Logger {
	l.Lock()
	l.contextSrc = make(map[interface{}]interface{})
	l.context = make(map[string]recVal)
	l.Unlock()
	return l
}

// GetContext returns copy of context saved in the logger.
func (l *Logger) GetContext() map[interface{}]interface{} {
	var contextSrc = make(map[interface{}]interface{})
	l.RLock()
	for k, v := range l.contextSrc {
		contextSrc[k] = v
	}
	l.RUnlock()
	return contextSrc
}

// GetRecord returns copy of current set of keys and values prepared for logging
// as strings. With context key-vals included.
// The most of Logger operations return *Logger itself but it made for operations
// chaining only. If you need get log pairs use GelRecord() for it.
func (l *Logger) GetRecord() map[string]string {
	var merged = make(map[string]string)
	l.RLock()
	for k, v := range l.context {
		merged[k] = v.Val
	}
	for k, v := range l.pairs {
		merged[k] = v.Val
	}
	l.RUnlock()
	return merged
}

func toRecordKey(val interface{}) string {
	if val == nil {
		return ""
	}
	switch val.(type) {
	case bool:
		if val.(bool) {
			return "true"
		}
		return "false"
	case int:
		return strconv.Itoa(val.(int))
	case int8:
		return strconv.FormatInt(int64(val.(int8)), 10)
	case int16:
		return strconv.FormatInt(int64(val.(int16)), 10)
	case int32:
		return strconv.FormatInt(int64(val.(int32)), 10)
	case int64:
		return strconv.FormatInt(int64(val.(int64)), 10)
	case uint8:
		return strconv.FormatUint(uint64(val.(uint8)), 10)
	case uint16:
		return strconv.FormatUint(uint64(val.(uint16)), 10)
	case uint32:
		return strconv.FormatUint(uint64(val.(uint32)), 10)
	case uint64:
		return strconv.FormatUint(uint64(val.(uint64)), 10)
	case fmt.Stringer:
		return val.(fmt.Stringer).String()
	default:
		return fmt.Sprintf("%v", val)
	}
}

func toRecordValue(val interface{}) recVal {
	if val == nil {
		return recVal{"", emptyVal, false}
	}
	switch val.(type) {
	case bool:
		if val.(bool) {
			return recVal{"true", booleanVal, false}
		}
		return recVal{"false", booleanVal, false}
	case int:
		return recVal{strconv.Itoa(val.(int)), integerVal, false}
	case int8:
		return recVal{strconv.FormatInt(int64(val.(int8)), 10), integerVal, false}
	case int16:
		return recVal{strconv.FormatInt(int64(val.(int16)), 10), integerVal, false}
	case int32:
		return recVal{strconv.FormatInt(int64(val.(int32)), 10), integerVal, false}
	case int64:
		return recVal{strconv.FormatInt(int64(val.(int64)), 10), integerVal, false}
	case uint8:
		return recVal{strconv.FormatUint(uint64(val.(uint8)), 10), integerVal, false}
	case uint16:
		return recVal{strconv.FormatUint(uint64(val.(uint16)), 10), integerVal, false}
	case uint32:
		return recVal{strconv.FormatUint(uint64(val.(uint32)), 10), integerVal, false}
	case uint64:
		return recVal{strconv.FormatUint(uint64(val.(uint64)), 10), integerVal, false}
	case Record:
		return recVal{val.(Record).String(), stringVal, true}
	case fmt.Stringer:
		return recVal{val.(fmt.Stringer).String(), stringVal, true}
	default:
		return recVal{fmt.Sprintf("%v", val), stringVal, true}
	}
}
<|endoftext|>