<commit_before>// Copyright (c) 2012-2014 Jeremy Latt
// Copyright (c) 2014-2015 Edmund Huber
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"fmt"
	"log"
	"net"
	"strconv"
	"time"

	"github.com/DanielOaks/girc-go/ircmsg"
	"github.com/DanielOaks/go-ident"
)

const (
	IDLE_TIMEOUT        = time.Minute + time.Second*30 // how long before a client is considered idle
	QUIT_TIMEOUT        = time.Minute                  // how long after idle before a client is kicked
	IdentTimeoutSeconds = 8
)

var (
	TIMEOUT_STATED_SECONDS = strconv.Itoa(int((IDLE_TIMEOUT + QUIT_TIMEOUT).Seconds()))
)

type Client struct {
	account            *ClientAccount
	atime              time.Time
	authorized         bool
	awayMessage        string
	capabilities       CapabilitySet
	capState           CapState
	certfp             string
	channels           ChannelSet
	ctime              time.Time
	flags              map[UserMode]bool
	isDestroyed        bool
	isQuitting         bool
	hasQuit            bool
	hops               uint
	hostname           string
	idleTimer          *time.Timer
	nick               string
	nickCasefolded     string
	nickMaskString     string // cache for nickmask string since it's used with lots of replies
	nickMaskCasefolded string
	quitTimer          *time.Timer
	realname           string
	registered         bool
	saslInProgress     bool
	saslMechanism      string
	saslValue          string
	server             *Server
	socket             *Socket
	username           string
}

func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
	now := time.Now()
	socket := NewSocket(conn)
	client := &Client{
		atime:          now,
		authorized:     server.password == nil,
		capState:       CapNone,
		capabilities:   make(CapabilitySet),
		channels:       make(ChannelSet),
		ctime:          now,
		flags:          make(map[UserMode]bool),
		server:         server,
		socket:         &socket,
		account:        &NoAccount,
		nick:           "*", // * is used until actual nick is given
		nickCasefolded: "*",
		nickMaskString: "*", // * is used until actual nick is given
	}
	if isTLS {
		client.flags[TLS] = true

		// error is not useful to us here anyways so we can ignore it
		client.certfp, _ = client.socket.CertFP()
	}
	if server.checkIdent {
		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
		serverPort, _ := strconv.Atoi(serverPortString)
		if err != nil {
			log.Fatal(err)
		}
		clientHost, clientPortString, err := net.SplitHostPort(conn.RemoteAddr().String())
		clientPort, _ := strconv.Atoi(clientPortString)
		if err != nil {
			log.Fatal(err)
		}

		client.Notice("*** Looking up your username")
		resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
		if err == nil {
			username := resp.Identifier
			_, err := CasefoldName(username) // ensure it's a valid username
			if err == nil {
				client.Notice("*** Found your username")
				client.username = username
				// we don't need to updateNickMask here since nickMask is not used for anything yet
			} else {
				client.Notice("*** Got a malformed username, ignoring")
			}
		} else {
			client.Notice("*** Could not find your username")
		}
	}
	client.Touch()
	go client.run()

	return client
}

//
// command goroutine
//

func (client *Client) run() {
	var err error
	var isExiting bool
	var line string
	var msg ircmsg.IrcMessage

	// Set the hostname for this client. The client may later send a PROXY
	// command from stunnel that sets the hostname to something more accurate.
	client.hostname = AddrLookupHostname(client.socket.conn.RemoteAddr())

	//TODO(dan): Make this a socketreactor from ircbnc
	for {
		line, err = client.socket.Read()
		if err != nil {
			client.Quit("connection closed")
			break
		}

		msg, err = ircmsg.ParseLine(line)
		if err != nil {
			client.Quit("received malformed line")
			break
		}

		cmd, exists := Commands[msg.Command]
		if !exists {
			client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, "Unknown command")
			continue
		}

		isExiting = cmd.Run(client.server, client, msg)
		if isExiting || client.isQuitting {
			break
		}
	}

	// ensure client connection gets closed
	client.destroy()
}

//
// quit timer goroutine
//

func (client *Client) connectionTimeout() {
	client.Quit(fmt.Sprintf("Ping timeout: %s seconds", TIMEOUT_STATED_SECONDS))
	client.isQuitting = true
}

//
// idle timer goroutine
//

func (client *Client) connectionIdle() {
	client.server.idle <- client
}

//
// server goroutine
//

func (client *Client) Active() {
	client.atime = time.Now()
}

func (client *Client) Touch() {
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	if client.idleTimer == nil {
		client.idleTimer = time.AfterFunc(IDLE_TIMEOUT, client.connectionIdle)
	} else {
		client.idleTimer.Reset(IDLE_TIMEOUT)
	}
}

func (client *Client) Idle() {
	client.Send(nil, "", "PING", client.nick)

	if client.quitTimer == nil {
		client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout)
	} else {
		client.quitTimer.Reset(QUIT_TIMEOUT)
	}
}

func (client *Client) Register() {
	if client.registered {
		return
	}
	client.registered = true
	client.Touch()
}

func (client *Client) IdleTime() time.Duration {
	return time.Since(client.atime)
}

func (client *Client) SignonTime() int64 {
	return client.ctime.Unix()
}

func (client *Client) IdleSeconds() uint64 {
	return uint64(client.IdleTime().Seconds())
}

func (client *Client) HasNick() bool {
	return client.nick != "" && client.nick != "*"
}

func (client *Client) HasUsername() bool {
	return client.username != "" && client.username != "*"
}

// <mode>
func (c *Client) ModeString() (str string) {
	str = "+"

	for flag := range c.flags {
		str += flag.String()
	}

	return
}

func (c *Client) UserHost() string {
	return fmt.Sprintf("%s!%s@%s", c.nick, c.username, c.hostname)
}

func (c *Client) Id() string {
	return c.UserHost()
}

// Friends refers to clients that share a channel with this client.
func (client *Client) Friends() ClientSet {
	friends := make(ClientSet)
	friends.Add(client)
	for channel := range client.channels {
		for member := range channel.members {
			friends.Add(member)
		}
	}
	return friends
}

func (client *Client) updateNickMask() {
	casefoldedName, err := CasefoldName(client.nick)
	if err != nil {
		log.Println(fmt.Sprintf("ERROR: Nick [%s] couldn't be casefolded... this should never happen.", client.nick))
	}
	client.nickCasefolded = casefoldedName

	client.nickMaskString = fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)

	nickMaskCasefolded, err := Casefold(client.nickMaskString)
	if err != nil {
		log.Println(fmt.Sprintf("ERROR: Nickmask [%s] couldn't be casefolded... this should never happen.", client.nickMaskString))
	}
	client.nickMaskCasefolded = nickMaskCasefolded
}

func (client *Client) SetNickname(nickname string) {
	if client.HasNick() {
		Log.error.Printf("%s nickname already set!", client.nickMaskString)
		return
	}
	fmt.Println("Setting nick to:", nickname, "from", client.nick)
	client.nick = nickname
	client.updateNickMask()
	client.server.clients.Add(client)
}

func (client *Client) ChangeNickname(nickname string) {
	origNickMask := client.nickMaskString
	client.server.clients.Remove(client)
	client.server.whoWas.Append(client)
	client.nick = nickname
	client.updateNickMask()
	client.server.clients.Add(client)
	client.Send(nil, origNickMask, "NICK", nickname)
	for friend := range client.Friends() {
		friend.Send(nil, origNickMask, "NICK", nickname)
	}
}

func (client *Client) Reply(reply string) error {
	//TODO(dan): We'll be passing around real message objects instead of raw strings
	return client.socket.WriteLine(reply)
}

func (client *Client) Quit(message string) {
	client.Send(nil, client.nickMaskString, "QUIT", message)
	client.Send(nil, client.nickMaskString, "ERROR", message)
}

func (client *Client) destroy() {
	if client.isDestroyed {
		return
	}

	client.isDestroyed = true
	client.server.whoWas.Append(client)
	friends := client.Friends()
	friends.Remove(client)

	// clean up channels
	for channel := range client.channels {
		channel.Quit(client)
	}

	// clean up server
	client.server.clients.Remove(client)

	// clean up self
	if client.idleTimer != nil {
		client.idleTimer.Stop()
	}
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	client.socket.Close()
	for friend := range client.Friends() {
		//TODO(dan): store quit message in user, if exists use that instead here
		friend.Send(nil, client.nickMaskString, "QUIT", "Exited")
	}
}

// SendFromClient sends an IRC line coming from a specific client.
// Adds account-tag to the line as well.
func (client *Client) SendFromClient(from *Client, tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
	// attach account-tag
	if client.capabilities[AccountTag] && from.account != &NoAccount {
		if tags == nil {
			tags = ircmsg.MakeTags("account", from.account.Name)
		} else {
			(*tags)["account"] = ircmsg.MakeTagValue(from.account.Name)
		}
	}

	return client.Send(tags, prefix, command, params...)
}

// Send sends an IRC line to the client.
func (client *Client) Send(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
	// attach server-time
	if client.capabilities[ServerTime] {
		if tags == nil {
			tags = ircmsg.MakeTags("time", time.Now().Format("2006-01-02T15:04:05.999Z"))
		} else {
			(*tags)["time"] = ircmsg.MakeTagValue(time.Now().Format("2006-01-02T15:04:05.999Z"))
		}
	}

	// send out the message
	message := ircmsg.MakeMessage(tags, prefix, command, params...)
	line, err := message.Line()
	if err != nil {
		// try not to fail quietly - especially useful when running tests, as a note to dig deeper
		message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending")
		line, _ := message.Line()
		client.socket.Write(line)
		return err
	}
	client.socket.Write(line)
	return nil
}

// Notice sends the client a notice from the server.
func (client *Client) Notice(text string) {
	client.Send(nil, client.server.name, "NOTICE", client.nick, text)
}
<commit_msg>client: Remove silly testing Println<commit_after>// Copyright (c) 2012-2014 Jeremy Latt
// Copyright (c) 2014-2015 Edmund Huber
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"fmt"
	"log"
	"net"
	"strconv"
	"time"

	"github.com/DanielOaks/girc-go/ircmsg"
	"github.com/DanielOaks/go-ident"
)

const (
	IDLE_TIMEOUT        = time.Minute + time.Second*30 // how long before a client is considered idle
	QUIT_TIMEOUT        = time.Minute                  // how long after idle before a client is kicked
	IdentTimeoutSeconds = 8
)

var (
	TIMEOUT_STATED_SECONDS = strconv.Itoa(int((IDLE_TIMEOUT + QUIT_TIMEOUT).Seconds()))
)

type Client struct {
	account            *ClientAccount
	atime              time.Time
	authorized         bool
	awayMessage        string
	capabilities       CapabilitySet
	capState           CapState
	certfp             string
	channels           ChannelSet
	ctime              time.Time
	flags              map[UserMode]bool
	isDestroyed        bool
	isQuitting         bool
	hasQuit            bool
	hops               uint
	hostname           string
	idleTimer          *time.Timer
	nick               string
	nickCasefolded     string
	nickMaskString     string // cache for nickmask string since it's used with lots of replies
	nickMaskCasefolded string
	quitTimer          *time.Timer
	realname           string
	registered         bool
	saslInProgress     bool
	saslMechanism      string
	saslValue          string
	server             *Server
	socket             *Socket
	username           string
}

func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
	now := time.Now()
	socket := NewSocket(conn)
	client := &Client{
		atime:          now,
		authorized:     server.password == nil,
		capState:       CapNone,
		capabilities:   make(CapabilitySet),
		channels:       make(ChannelSet),
		ctime:          now,
		flags:          make(map[UserMode]bool),
		server:         server,
		socket:         &socket,
		account:        &NoAccount,
		nick:           "*", // * is used until actual nick is given
		nickCasefolded: "*",
		nickMaskString: "*", // * is used until actual nick is given
	}
	if isTLS {
		client.flags[TLS] = true

		// error is not useful to us here anyways so we can ignore it
		client.certfp, _ = client.socket.CertFP()
	}
	if server.checkIdent {
		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
		serverPort, _ := strconv.Atoi(serverPortString)
		if err != nil {
			log.Fatal(err)
		}
		clientHost, clientPortString, err := net.SplitHostPort(conn.RemoteAddr().String())
		clientPort, _ := strconv.Atoi(clientPortString)
		if err != nil {
			log.Fatal(err)
		}

		client.Notice("*** Looking up your username")
		resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
		if err == nil {
			username := resp.Identifier
			_, err := CasefoldName(username) // ensure it's a valid username
			if err == nil {
				client.Notice("*** Found your username")
				client.username = username
				// we don't need to updateNickMask here since nickMask is not used for anything yet
			} else {
				client.Notice("*** Got a malformed username, ignoring")
			}
		} else {
			client.Notice("*** Could not find your username")
		}
	}
	client.Touch()
	go client.run()

	return client
}

//
// command goroutine
//

func (client *Client) run() {
	var err error
	var isExiting bool
	var line string
	var msg ircmsg.IrcMessage

	// Set the hostname for this client. The client may later send a PROXY
	// command from stunnel that sets the hostname to something more accurate.
	client.hostname = AddrLookupHostname(client.socket.conn.RemoteAddr())

	//TODO(dan): Make this a socketreactor from ircbnc
	for {
		line, err = client.socket.Read()
		if err != nil {
			client.Quit("connection closed")
			break
		}

		msg, err = ircmsg.ParseLine(line)
		if err != nil {
			client.Quit("received malformed line")
			break
		}

		cmd, exists := Commands[msg.Command]
		if !exists {
			client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, "Unknown command")
			continue
		}

		isExiting = cmd.Run(client.server, client, msg)
		if isExiting || client.isQuitting {
			break
		}
	}

	// ensure client connection gets closed
	client.destroy()
}

//
// quit timer goroutine
//

func (client *Client) connectionTimeout() {
	client.Quit(fmt.Sprintf("Ping timeout: %s seconds", TIMEOUT_STATED_SECONDS))
	client.isQuitting = true
}

//
// idle timer goroutine
//

func (client *Client) connectionIdle() {
	client.server.idle <- client
}

//
// server goroutine
//

func (client *Client) Active() {
	client.atime = time.Now()
}

func (client *Client) Touch() {
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	if client.idleTimer == nil {
		client.idleTimer = time.AfterFunc(IDLE_TIMEOUT, client.connectionIdle)
	} else {
		client.idleTimer.Reset(IDLE_TIMEOUT)
	}
}

func (client *Client) Idle() {
	client.Send(nil, "", "PING", client.nick)

	if client.quitTimer == nil {
		client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout)
	} else {
		client.quitTimer.Reset(QUIT_TIMEOUT)
	}
}

func (client *Client) Register() {
	if client.registered {
		return
	}
	client.registered = true
	client.Touch()
}

func (client *Client) IdleTime() time.Duration {
	return time.Since(client.atime)
}

func (client *Client) SignonTime() int64 {
	return client.ctime.Unix()
}

func (client *Client) IdleSeconds() uint64 {
	return uint64(client.IdleTime().Seconds())
}

func (client *Client) HasNick() bool {
	return client.nick != "" && client.nick != "*"
}

func (client *Client) HasUsername() bool {
	return client.username != "" && client.username != "*"
}

// <mode>
func (c *Client) ModeString() (str string) {
	str = "+"

	for flag := range c.flags {
		str += flag.String()
	}

	return
}

func (c *Client) UserHost() string {
	return fmt.Sprintf("%s!%s@%s", c.nick, c.username, c.hostname)
}

func (c *Client) Id() string {
	return c.UserHost()
}

// Friends refers to clients that share a channel with this client.
func (client *Client) Friends() ClientSet {
	friends := make(ClientSet)
	friends.Add(client)
	for channel := range client.channels {
		for member := range channel.members {
			friends.Add(member)
		}
	}
	return friends
}

func (client *Client) updateNickMask() {
	casefoldedName, err := CasefoldName(client.nick)
	if err != nil {
		log.Println(fmt.Sprintf("ERROR: Nick [%s] couldn't be casefolded... this should never happen.", client.nick))
	}
	client.nickCasefolded = casefoldedName

	client.nickMaskString = fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)

	nickMaskCasefolded, err := Casefold(client.nickMaskString)
	if err != nil {
		log.Println(fmt.Sprintf("ERROR: Nickmask [%s] couldn't be casefolded... this should never happen.", client.nickMaskString))
	}
	client.nickMaskCasefolded = nickMaskCasefolded
}

func (client *Client) SetNickname(nickname string) {
	if client.HasNick() {
		Log.error.Printf("%s nickname already set!", client.nickMaskString)
		return
	}
	client.nick = nickname
	client.updateNickMask()
	client.server.clients.Add(client)
}

func (client *Client) ChangeNickname(nickname string) {
	origNickMask := client.nickMaskString
	client.server.clients.Remove(client)
	client.server.whoWas.Append(client)
	client.nick = nickname
	client.updateNickMask()
	client.server.clients.Add(client)
	client.Send(nil, origNickMask, "NICK", nickname)
	for friend := range client.Friends() {
		friend.Send(nil, origNickMask, "NICK", nickname)
	}
}

func (client *Client) Reply(reply string) error {
	//TODO(dan): We'll be passing around real message objects instead of raw strings
	return client.socket.WriteLine(reply)
}

func (client *Client) Quit(message string) {
	client.Send(nil, client.nickMaskString, "QUIT", message)
	client.Send(nil, client.nickMaskString, "ERROR", message)
}

func (client *Client) destroy() {
	if client.isDestroyed {
		return
	}

	client.isDestroyed = true
	client.server.whoWas.Append(client)
	friends := client.Friends()
	friends.Remove(client)

	// clean up channels
	for channel := range client.channels {
		channel.Quit(client)
	}

	// clean up server
	client.server.clients.Remove(client)

	// clean up self
	if client.idleTimer != nil {
		client.idleTimer.Stop()
	}
	if client.quitTimer != nil {
		client.quitTimer.Stop()
	}

	client.socket.Close()
	for friend := range client.Friends() {
		//TODO(dan): store quit message in user, if exists use that instead here
		friend.Send(nil, client.nickMaskString, "QUIT", "Exited")
	}
}

// SendFromClient sends an IRC line coming from a specific client.
// Adds account-tag to the line as well.
func (client *Client) SendFromClient(from *Client, tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
	// attach account-tag
	if client.capabilities[AccountTag] && from.account != &NoAccount {
		if tags == nil {
			tags = ircmsg.MakeTags("account", from.account.Name)
		} else {
			(*tags)["account"] = ircmsg.MakeTagValue(from.account.Name)
		}
	}

	return client.Send(tags, prefix, command, params...)
}

// Send sends an IRC line to the client.
func (client *Client) Send(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
	// attach server-time
	if client.capabilities[ServerTime] {
		if tags == nil {
			tags = ircmsg.MakeTags("time", time.Now().Format("2006-01-02T15:04:05.999Z"))
		} else {
			(*tags)["time"] = ircmsg.MakeTagValue(time.Now().Format("2006-01-02T15:04:05.999Z"))
		}
	}

	// send out the message
	message := ircmsg.MakeMessage(tags, prefix, command, params...)
	line, err := message.Line()
	if err != nil {
		// try not to fail quietly - especially useful when running tests, as a note to dig deeper
		message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending")
		line, _ := message.Line()
		client.socket.Write(line)
		return err
	}
	client.socket.Write(line)
	return nil
}

// Notice sends the client a notice from the server.
func (client *Client) Notice(text string) {
	client.Send(nil, client.server.name, "NOTICE", client.nick, text)
}
<|endoftext|>


<commit_before>package irc

// IRC client implementation.

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

type Client struct {
	User       User
	Errorchan  chan error
	Registered bool

	// Hold the actual irc connection
	conn net.Conn

	// List of MessageHandler chain, keyed by Message's action
	msgHandlers MessageHandlers

	// Message gets transmitted through this channel
	messagechan chan *Message
	error       error
}

// Connect to irc server at `addr` as this `user`
// if success Connect returns `Client`.
func Connect(addr string, user User) (*Client, error) {
	client := &Client{
		User:        user,
		Errorchan:   make(chan error),
		Registered:  false,
		messagechan: make(chan *Message, 25),
	}
	client.setupMsgHandlers()
	cConn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, &Client{error: err}
	}
	client.conn = cConn
	go client.handleInput()
	go client.processMessage()
	client.register(user)
	return client, nil
}

// Implement Error interface
func (c *Client) Error() string {
	return "Error creating client: " + c.error.Error() + "\n"
}

func (c *Client) Send(cmd string, a ...interface{}) {
	str := fmt.Sprintf(cmd, a...)
	c.conn.Write([]byte(str + "\r\n"))
	log.Println("out>", str)
}

func (c *Client) Join(channel, password string) {
	c.Send("JOIN %s %s", channel, password)
}

func (c *Client) Nick(nick string) {
	c.Send("NICK " + nick)
}

func (c *Client) Notice(to, msg string) {
	c.Send("NOTICE %s :%s", to, msg)
}

func (c *Client) Part(channel string) {
	c.Send("PART " + channel)
}

func (c *Client) Ping(arg string) {
	c.Send("PING :" + arg)
}

func (c *Client) Pong(arg string) {
	c.Send("PONG :" + arg)
}

func (c *Client) PrivMsg(to, msg string) {
	c.Send("PRIVMSG %s :%s", to, msg)
}

// Register User to the server, and optionally identify with nickserv
// XXX: Need to wait nickserv identify until User actually connected.
//      - At the first CTCP VERSION request?
func (c *Client) register(user User) {
	if c.Registered {
		return
	}

	// Sleep until we sure it's connected
	time.Sleep(time.Duration(5000) * time.Millisecond)

	c.Nick(user.Nick)
	c.Send("USER %s %d * :%s", user.Nick, user.mode, user.Realname)
	if len(user.password) != 0 {
		c.PrivMsg("nickserv", "identify "+user.password)
	}
}

// Response CTCP message.
func (c *Client) responseCTCP(to, answer string) {
	c.Notice(to, ctcpQuote(answer))
}

// Sit still wait for input, then pass it to Client.messagechan
func (c *Client) handleInput() {
	defer c.conn.Close()
	scanner = bufio.NewScanner(c.conn)
	for {
		if scanner.Scan() {
			c.messagechan <- parseMessage(scanner.Text())
		} else {
			close(c.messagechan)
			c.Errorchan <- scanner.Err()
			break
		}
	}
}

// Execute MessageHandler chain once its arrived at Client.messagechan
func (c *Client) processMessage() {
	for {
		msg, ok := <-c.messagechan
		if !ok {
			return
		}
		for _, fn := range c.msgHandlers[msg.Action] {
			fn(msg)
		}
	}
}
<commit_msg>Refactor irc's client. Re-add input logging.<commit_after>package irc

// IRC client implementation.

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"time"
)

type Client struct {
	User       User
	Errorchan  chan error
	Registered bool

	// Hold the actual irc connection
	conn net.Conn

	// List of MessageHandler chain, keyed by Message's action
	msgHandlers MessageHandlers

	// Message gets transmitted through this channel
	messagechan chan *Message
	error       error
}

// Connect to irc server at `addr` as this `user`
// if success Connect returns `Client`.
func Connect(addr string, user User) (*Client, error) {
	client := &Client{
		User:        user,
		Errorchan:   make(chan error),
		Registered:  false,
		messagechan: make(chan *Message, 25),
	}
	client.setupMsgHandlers()
	cConn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, &Client{error: err}
	}
	client.conn = cConn
	go client.handleInput()
	go client.processMessage()
	client.register(user)
	return client, nil
}

// Implement Error interface
func (c *Client) Error() string {
	return "Error creating client: " + c.error.Error() + "\n"
}

func (c *Client) Send(cmd string, a ...interface{}) {
	str := fmt.Sprintf(cmd, a...)
	c.conn.Write([]byte(str + "\r\n"))
	log.Println("out>", str)
}

func (c *Client) Join(channel, password string) {
	c.Send("JOIN %s %s", channel, password)
}

func (c *Client) Nick(nick string) {
	c.Send("NICK " + nick)
}

func (c *Client) Notice(to, msg string) {
	c.Send("NOTICE %s :%s", to, msg)
}

func (c *Client) Part(channel string) {
	c.Send("PART " + channel)
}

func (c *Client) Ping(arg string) {
	c.Send("PING :" + arg)
}

func (c *Client) Pong(arg string) {
	c.Send("PONG :" + arg)
}

func (c *Client) PrivMsg(to, msg string) {
	c.Send("PRIVMSG %s :%s", to, msg)
}

// Register User to the server, and optionally identify with nickserv
// XXX: Need to wait nickserv identify until User actually connected.
//      - At the first CTCP VERSION request?
func (c *Client) register(user User) {
	if c.Registered {
		return
	}

	c.Nick(user.Nick)
	c.Send("USER %s %d * :%s", user.Nick, user.mode, user.Realname)

	// Sleep until we sure it's connected
	time.Sleep(time.Duration(5000) * time.Millisecond)

	if len(user.password) != 0 {
		c.PrivMsg("nickserv", "identify "+user.password)
	}
}

// Response CTCP message.
func (c *Client) responseCTCP(to, answer string) {
	c.Notice(to, ctcpQuote(answer))
}

// Sit still wait for input, then pass it to Client.messagechan
func (c *Client) handleInput() {
	defer c.conn.Close()
	scanner := bufio.NewScanner(c.conn)
	for {
		if scanner.Scan() {
			msg := scanner.Text()
			log.Println("in>", msg)
			c.messagechan <- parseMessage(msg)
		} else {
			close(c.messagechan)
			c.Errorchan <- scanner.Err()
			break
		}
	}
}

// Execute MessageHandler chain once its arrived at Client.messagechan
func (c *Client) processMessage() {
	for {
		msg, ok := <-c.messagechan
		if !ok {
			return
		}
		for _, fn := range c.msgHandlers[msg.Action] {
			fn(msg)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strconv"

	"github.com/tidwall/buntdb"

	"github.com/oragono/oragono/irc/utils"
)

const (
	// produce a hardcoded version of the database schema
	// XXX instead of referencing, e.g., keyAccountExists, we should write in the string literal
	// (to ensure that no matter what code changes happen elsewhere, we're still producing a
	// db of the hardcoded version)
	importDBSchemaVersion = 18
)

type userImport struct {
	Name            string
	Hash            string
	Email           string
	RegisteredAt    int64 `json:"registeredAt"`
	Vhost           string
	AdditionalNicks []string `json:"additionalNicks"`
}

type channelImport struct {
	Name         string
	Founder      string
	RegisteredAt int64 `json:"registeredAt"`
	Topic        string
	TopicSetBy   string `json:"topicSetBy"`
	TopicSetAt   int64  `json:"topicSetAt"`
	Amode        map[string]string
	Modes        string
	Key          string
	Limit        int
}

type databaseImport struct {
	Version  int
	Source   string
	Users    map[string]userImport
	Channels map[string]channelImport
}

func serializeAmodes(raw map[string]string) (result []byte, err error) {
	processed := make(map[string]int, len(raw))
	for accountName, mode := range raw {
		if len(mode) != 1 {
			return nil, fmt.Errorf("invalid mode %s for account %s", mode, accountName)
		}
		cfname, err := CasefoldName(accountName)
		if err != nil {
			return nil, fmt.Errorf("invalid amode recipient %s: %w", accountName, err)
		}
		processed[cfname] = int(mode[0])
	}
	result, err = json.Marshal(processed)
	return
}

func doImportDBGeneric(config *Config, dbImport databaseImport, credsType CredentialsVersion, tx *buntdb.Tx) (err error) {
	requiredVersion := 1
	if dbImport.Version != requiredVersion {
		return fmt.Errorf("unsupported version of the db for import: version %d is required", requiredVersion)
	}

	tx.Set(keySchemaVersion, strconv.Itoa(importDBSchemaVersion), nil)
	tx.Set(keyCloakSecret, utils.GenerateSecretKey(), nil)

	for username, userInfo := range dbImport.Users {
		cfUsername, err := CasefoldName(username)
		if err != nil {
			log.Printf("invalid username %s: %v", username, err)
			continue
		}
		credentials := AccountCredentials{
			Version:        credsType,
			PassphraseHash: []byte(userInfo.Hash),
		}
		marshaledCredentials, err := json.Marshal(&credentials)
		if err != nil {
			log.Printf("invalid credentials for %s: %v", username, err)
			continue
		}
		tx.Set(fmt.Sprintf(keyAccountExists, cfUsername), "1", nil)
		tx.Set(fmt.Sprintf(keyAccountVerified, cfUsername), "1", nil)
		tx.Set(fmt.Sprintf(keyAccountName, cfUsername), userInfo.Name, nil)
		tx.Set(fmt.Sprintf(keyAccountCallback, cfUsername), "mailto:"+userInfo.Email, nil)
		tx.Set(fmt.Sprintf(keyAccountCredentials, cfUsername), string(marshaledCredentials), nil)
		tx.Set(fmt.Sprintf(keyAccountRegTime, cfUsername), strconv.FormatInt(userInfo.RegisteredAt, 10), nil)
		if userInfo.Vhost != "" {
			tx.Set(fmt.Sprintf(keyAccountVHost, cfUsername), userInfo.Vhost, nil)
		}
		if len(userInfo.AdditionalNicks) != 0 {
			tx.Set(fmt.Sprintf(keyAccountAdditionalNicks, cfUsername), marshalReservedNicks(userInfo.AdditionalNicks), nil)
		}
	}

	for chname, chInfo := range dbImport.Channels {
		cfchname, err := CasefoldChannel(chname)
		if err != nil {
			log.Printf("invalid channel name %s: %v", chname, err)
			continue
		}
		cffounder, err := CasefoldName(chInfo.Founder)
		if err != nil {
			log.Printf("invalid founder %s for channel %s: %v", chInfo.Founder, chname, err)
			continue
		}
		tx.Set(fmt.Sprintf(keyChannelExists, cfchname), "1", nil)
		tx.Set(fmt.Sprintf(keyChannelName, cfchname), chname, nil)
		tx.Set(fmt.Sprintf(keyChannelRegTime, cfchname), strconv.FormatInt(chInfo.RegisteredAt, 10), nil)
		tx.Set(fmt.Sprintf(keyChannelFounder, cfchname), cffounder, nil)
		accountChannelsKey := fmt.Sprintf(keyAccountChannels, cffounder)
		founderChannels, fcErr := tx.Get(accountChannelsKey)
		if fcErr != nil || founderChannels == "" {
			founderChannels = cfchname
		} else {
			founderChannels = fmt.Sprintf("%s,%s", founderChannels, cfchname)
		}
		tx.Set(accountChannelsKey, founderChannels, nil)
		if chInfo.Topic != "" {
			tx.Set(fmt.Sprintf(keyChannelTopic, cfchname), chInfo.Topic, nil)
			tx.Set(fmt.Sprintf(keyChannelTopicSetTime, cfchname), strconv.FormatInt(chInfo.TopicSetAt, 10), nil)
			tx.Set(fmt.Sprintf(keyChannelTopicSetBy, cfchname), chInfo.TopicSetBy, nil)
		}
		if len(chInfo.Amode) != 0 {
			m, err := serializeAmodes(chInfo.Amode)
			if err == nil {
				tx.Set(fmt.Sprintf(keyChannelAccountToUMode, cfchname), string(m), nil)
			} else {
				log.Printf("couldn't serialize amodes for %s: %v", chname, err)
			}
		}
		tx.Set(fmt.Sprintf(keyChannelModes, cfchname), chInfo.Modes, nil)
		if chInfo.Key != "" {
			tx.Set(fmt.Sprintf(keyChannelPassword, cfchname), chInfo.Key, nil)
		}
		if chInfo.Limit > 0 {
			tx.Set(fmt.Sprintf(keyChannelUserLimit, cfchname), strconv.Itoa(chInfo.Limit), nil)
		}
	}

	return nil
}

func doImportDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (err error) {
	switch dbImport.Source {
	case "atheme":
		return doImportDBGeneric(config, dbImport, CredentialsAtheme, tx)
	case "anope":
		return doImportDBGeneric(config, dbImport, CredentialsAnope, tx)
	default:
		return fmt.Errorf("unsupported import source: %s", dbImport.Source)
	}
}

func ImportDB(config *Config, infile string) (err error) {
	data, err := ioutil.ReadFile(infile)
	if err != nil {
		return
	}

	var dbImport databaseImport
	err = json.Unmarshal(data, &dbImport)
	if err != nil {
		return err
	}

	err = checkDBReadyForInit(config.Datastore.Path)
	if err != nil {
		return err
	}

	db, err := buntdb.Open(config.Datastore.Path)
	if err != nil {
		return err
	}

	performImport := func(tx *buntdb.Tx) (err error) {
		return doImportDB(config, dbImport, tx)
	}

	return db.Update(performImport)
}
<commit_msg>support certfp import<commit_after>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"strconv"

	"github.com/tidwall/buntdb"

	"github.com/oragono/oragono/irc/utils"
)

const (
	// produce a hardcoded version of the database schema
	// XXX instead of referencing, e.g., keyAccountExists, we should write in the string literal
	// (to ensure that no matter what code changes happen elsewhere, we're still producing a
	// db of the hardcoded version)
	importDBSchemaVersion = 18
)

type userImport struct {
	Name            string
	Hash            string
	Email           string
	RegisteredAt    int64 `json:"registeredAt"`
	Vhost           string
	AdditionalNicks []string `json:"additionalNicks"`
	Certfps         []string
}

type channelImport struct {
	Name         string
	Founder      string
	RegisteredAt int64 `json:"registeredAt"`
	Topic        string
	TopicSetBy   string `json:"topicSetBy"`
	TopicSetAt   int64  `json:"topicSetAt"`
	Amode        map[string]string
	Modes        string
	Key          string
	Limit        int
}

type databaseImport struct {
	Version  int
	Source   string
	Users    map[string]userImport
	Channels map[string]channelImport
}

func serializeAmodes(raw map[string]string) (result []byte, err error) {
	processed := make(map[string]int, len(raw))
	for accountName, mode := range raw {
		if len(mode) != 1 {
			return nil, fmt.Errorf("invalid mode %s for account %s", mode, accountName)
		}
		cfname, err := CasefoldName(accountName)
		if err != nil {
			return nil, fmt.Errorf("invalid amode recipient %s: %w", accountName, err)
		}
		processed[cfname] = int(mode[0])
	}
	result, err = json.Marshal(processed)
	return
}

func doImportDBGeneric(config *Config, dbImport databaseImport, credsType CredentialsVersion, tx *buntdb.Tx) (err error) {
	requiredVersion := 1
	if dbImport.Version != requiredVersion {
		return fmt.Errorf("unsupported version of the db for import: version %d is required", requiredVersion)
	}

	tx.Set(keySchemaVersion, strconv.Itoa(importDBSchemaVersion), nil)
	tx.Set(keyCloakSecret, utils.GenerateSecretKey(), nil)

	for username, userInfo := range dbImport.Users {
		cfUsername, err := CasefoldName(username)
		if err != nil {
			log.Printf("invalid username %s: %v", username, err)
			continue
		}
		var certfps []string
		for _, certfp := range userInfo.Certfps {
			normalizedCertfp, err := utils.NormalizeCertfp(certfp)
			if err == nil {
				certfps = append(certfps, normalizedCertfp)
			} else {
				log.Printf("invalid certfp %s for %s\n", username, certfp)
			}
		}
		credentials := AccountCredentials{
			Version:        credsType,
			PassphraseHash: []byte(userInfo.Hash),
			Certfps:        certfps,
		}
		marshaledCredentials, err := json.Marshal(&credentials)
		if err != nil {
			log.Printf("invalid credentials for %s: %v", username, err)
			continue
		}
		tx.Set(fmt.Sprintf(keyAccountExists, cfUsername), "1", nil)
		tx.Set(fmt.Sprintf(keyAccountVerified, cfUsername), "1", nil)
		tx.Set(fmt.Sprintf(keyAccountName, cfUsername), userInfo.Name, nil)
		tx.Set(fmt.Sprintf(keyAccountCallback, cfUsername), "mailto:"+userInfo.Email, nil)
		tx.Set(fmt.Sprintf(keyAccountCredentials, cfUsername), string(marshaledCredentials), nil)
		tx.Set(fmt.Sprintf(keyAccountRegTime, cfUsername), strconv.FormatInt(userInfo.RegisteredAt, 10), nil)
		if userInfo.Vhost != "" {
			tx.Set(fmt.Sprintf(keyAccountVHost, cfUsername), userInfo.Vhost, nil)
		}
		if len(userInfo.AdditionalNicks) != 0 {
			tx.Set(fmt.Sprintf(keyAccountAdditionalNicks, cfUsername), marshalReservedNicks(userInfo.AdditionalNicks), nil)
		}
		for _, certfp := range certfps {
			tx.Set(fmt.Sprintf(keyCertToAccount, certfp), cfUsername, nil)
		}
	}

	for chname, chInfo := range dbImport.Channels {
		cfchname, err := CasefoldChannel(chname)
		if err != nil {
			log.Printf("invalid channel name %s: %v", chname, err)
			continue
		}
		cffounder, err := CasefoldName(chInfo.Founder)
		if err != nil {
			log.Printf("invalid founder %s for channel %s: %v", chInfo.Founder, chname, err)
			continue
		}
		tx.Set(fmt.Sprintf(keyChannelExists, cfchname), "1", nil)
		tx.Set(fmt.Sprintf(keyChannelName, cfchname), chname, nil)
		tx.Set(fmt.Sprintf(keyChannelRegTime, cfchname), strconv.FormatInt(chInfo.RegisteredAt, 10), nil)
		tx.Set(fmt.Sprintf(keyChannelFounder, cfchname), cffounder, nil)
		accountChannelsKey := fmt.Sprintf(keyAccountChannels, cffounder)
		founderChannels, fcErr := tx.Get(accountChannelsKey)
		if fcErr != nil || founderChannels == "" {
			founderChannels = cfchname
		} else {
			founderChannels = fmt.Sprintf("%s,%s", founderChannels, cfchname)
		}
		tx.Set(accountChannelsKey, founderChannels, nil)
		if chInfo.Topic != "" {
			tx.Set(fmt.Sprintf(keyChannelTopic, cfchname), chInfo.Topic, nil)
			tx.Set(fmt.Sprintf(keyChannelTopicSetTime, cfchname), strconv.FormatInt(chInfo.TopicSetAt, 10), nil)
			tx.Set(fmt.Sprintf(keyChannelTopicSetBy, cfchname), chInfo.TopicSetBy, nil)
		}
		if len(chInfo.Amode) != 0 {
			m, err := serializeAmodes(chInfo.Amode)
			if err == nil {
				tx.Set(fmt.Sprintf(keyChannelAccountToUMode, cfchname), string(m), nil)
			} else {
				log.Printf("couldn't serialize amodes for %s: %v", chname, err)
			}
		}
		tx.Set(fmt.Sprintf(keyChannelModes, cfchname), chInfo.Modes, nil)
		if chInfo.Key != "" {
			tx.Set(fmt.Sprintf(keyChannelPassword, cfchname), chInfo.Key, nil)
		}
		if chInfo.Limit > 0 {
			tx.Set(fmt.Sprintf(keyChannelUserLimit, cfchname), strconv.Itoa(chInfo.Limit), nil)
		}
	}

	return nil
}

func doImportDB(config *Config, dbImport databaseImport, tx *buntdb.Tx) (err error) {
	switch dbImport.Source {
	case "atheme":
		return doImportDBGeneric(config, dbImport, CredentialsAtheme, tx)
	case "anope":
		return doImportDBGeneric(config, dbImport, CredentialsAnope, tx)
	default:
		return fmt.Errorf("unsupported import source: %s", dbImport.Source)
	}
}

func ImportDB(config *Config, infile string) (err error) {
	data, err := ioutil.ReadFile(infile)
	if err != nil {
		return
	}

	var dbImport databaseImport
	err = json.Unmarshal(data, &dbImport)
	if err != nil {
		return err
	}

	err = checkDBReadyForInit(config.Datastore.Path)
	if err != nil {
		return err
	}

	db, err := buntdb.Open(config.Datastore.Path)
	if err != nil {
		return err
	}

	performImport := func(tx *buntdb.Tx) (err error) {
		return doImportDB(config, dbImport, tx)
	}

	return db.Update(performImport)
}
<|endoftext|>


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

package isvcs

import (
	"github.com/control-center/serviced/dfs/docker"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"

	"time"
)

var Mgr *Manager

const (
	IMAGE_REPO    = "zenoss/serviced-isvcs"
	IMAGE_TAG     = "v43"
	ZK_IMAGE_REPO = "zenoss/isvcs-zookeeper"
	ZK_IMAGE_TAG  = "v4"
)

func Init(esStartupTimeoutInSeconds int, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	elasticsearch_serviced.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second
	elasticsearch_logstash.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)

	elasticsearch_serviced.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_serviced); err != nil {
		glog.Fatalf("%s", err)
	}
	elasticsearch_logstash.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_logstash); err != nil {
		glog.Fatalf("%s", err)
	}
	zookeeper.docker = dockerAPI
	if err := Mgr.Register(zookeeper); err != nil {
		glog.Fatalf("%s", err)
	}
	logstash.docker = dockerAPI
	if err := Mgr.Register(logstash); err != nil {
		glog.Fatalf("%s", err)
	}
	opentsdb.docker = dockerAPI
	if err := Mgr.Register(opentsdb); err != nil {
		glog.Fatalf("%s", err)
	}
	celery.docker = dockerAPI
	if err := Mgr.Register(celery); err != nil {
		glog.Fatalf("%s", err)
	}
	dockerRegistry.docker = dockerAPI
	if err := Mgr.Register(dockerRegistry); err != nil {
		glog.Fatalf("%s", err)
	}
}

func InitServices(isvcNames []string, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)
	for _, isvcName := range isvcNames {
		switch isvcName {
		case "zookeeper":
			zookeeper.docker = dockerAPI
			if err := Mgr.Register(zookeeper); err != nil {
				glog.Fatalf("%s", err)
			}
		}
	}
}
<commit_msg>use new isvcs image with java 8 support<commit_after>// Copyright 2014 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package isvcs

import (
	"github.com/control-center/serviced/dfs/docker"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"

	"time"
)

var Mgr *Manager

const (
	IMAGE_REPO    = "zenoss/serviced-isvcs"
	IMAGE_TAG     = "v44"
	ZK_IMAGE_REPO = "zenoss/isvcs-zookeeper"
	ZK_IMAGE_TAG  = "v4"
)

func Init(esStartupTimeoutInSeconds int, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	elasticsearch_serviced.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second
	elasticsearch_logstash.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)

	elasticsearch_serviced.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_serviced); err != nil {
		glog.Fatalf("%s", err)
	}
	elasticsearch_logstash.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_logstash); err != nil {
		glog.Fatalf("%s", err)
	}
	zookeeper.docker = dockerAPI
	if err := Mgr.Register(zookeeper); err != nil {
		glog.Fatalf("%s", err)
	}
	logstash.docker = dockerAPI
	if err := Mgr.Register(logstash); err != nil {
		glog.Fatalf("%s", err)
	}
	opentsdb.docker = dockerAPI
	if err := Mgr.Register(opentsdb); err != nil {
		glog.Fatalf("%s", err)
	}
	celery.docker = dockerAPI
	if err := Mgr.Register(celery); err != nil {
		glog.Fatalf("%s", err)
	}
	dockerRegistry.docker = dockerAPI
	if err := Mgr.Register(dockerRegistry); err != nil {
		glog.Fatalf("%s", err)
	}
}

func InitServices(isvcNames []string, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)
	for _, isvcName := range isvcNames {
		switch isvcName {
		case "zookeeper":
			zookeeper.docker = dockerAPI
			if err := Mgr.Register(zookeeper); err != nil {
				glog.Fatalf("%s", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package graph

import (
	"errors"
	"fmt"
	"github.com/jkomoros/boardgame/enum"
	"strconv"
)

//EdgeFilter is a type of function that can be passed to filter in edges. Only
//edges that return true will be kept.
type EdgeFilter func(enum enum.Enum, from, to int) bool

//DirectionUp will return true if to is in a strictly lower-indexed row then
//from.
func DirectionUp(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[0] > toIndexes[0]
}

//DirectionDown will return true if to is in a strictly higher-indexed row
//then from.
func DirectionDown(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[0] > toIndexes[0]
}

//DirectionLeft will return true if to is in a strictly lower-indexed col then
//from.
func DirectionLeft(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[1] > toIndexes[1]
}

//DirectionRight will return true if to is in a strictly higher-indexed col
//then from.
func DirectionRight(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[1] > toIndexes[1]
}

//DirectionPerpendicular will return true if to is perpendicular to from (in the
//same row or col).
func DirectionPerpendicular(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	if fromIndexes[0] == toIndexes[0] {
		return true
	}
	return fromIndexes[1] == toIndexes[1]
}

//DirectionDiagonal will return true if to is non-perpendicular to from.
func DirectionDiagonal(enum enum.Enum, from, to int) bool {
	return !DirectionPerpendicular(enum, from, to)
}

//NewGridConnectedness is a helper function to create a finished graph
//representing the connections between a grid. By default it adds edges
//between each of the 8 adjacent cells. However, all neighbors must pass the
//provided filters to be added. This package also defines a number of
//Direction* EdgeFilters. The enum passed must be a ranged, 2 dimensional enum.
//	//Returns a graph that has all cells connected to each of their neighbors.
//	NewGridConnectedness(e)
//
//  //Returns a graph that creates connections upward and diagonally from each
//  //cell.
//	NewGridConnectedness(e, DirectionUp, DirectionDiagonal)
//
func NewGridConnectedness(ranged2DEnum enum.Enum, filter ...EdgeFilter) (Graph, error) {
	if !ranged2DEnum.IsRange() {
		return nil, errors.New("The enum was not created with AddRange")
	}
	if len(ranged2DEnum.RangeDimensions()) != 2 {
		return nil, errors.New("The enum did not have two dimensions")
	}

	graph := New(false, ranged2DEnum)

	for _, val := range ranged2DEnum.Values() {

		theNeighbors := neighbors(ranged2DEnum, val)

		for _, theFilter := range filter {
			var tempNeighbors []int
			for _, n := range theNeighbors {
				if theFilter(ranged2DEnum, val, n) {
					tempNeighbors = append(tempNeighbors, n)
				}
			}
			theNeighbors = tempNeighbors
		}

		if err := graph.AddEdges(val, theNeighbors...); err != nil {
			return nil, errors.New("Couldn't add " + strconv.Itoa(val) + ": " + fmt.Sprintf("%v", theNeighbors) + ": " + err.Error())
		}

	}

	graph.Finish()

	return graph, nil

}

//assumes that theEnum is a 2d ranged enum, and that start is a valid value in
//it.
func neighbors(theEnum enum.Enum, start int) []int {
	var result []int
	indexes := theEnum.ValueToRange(start)
	for rOffset := -1; rOffset < 2; rOffset++ {
		for cOffset := -1; cOffset < 2; cOffset++ {

			if rOffset == 0 && cOffset == 0 {
				//This is the start cell
				continue
			}

			r := indexes[0] + rOffset
			c := indexes[1] + cOffset

			val := theEnum.RangeToValue(r, c)

			if val != enum.IllegalValue {
				result = append(result, val)
			}

		}
	}
	return result
}
<commit_msg>Note that the graph package includes lots of Direction* EdgeFilters. Part of #493.<commit_after>package graph

import (
	"errors"
	"fmt"
	"github.com/jkomoros/boardgame/enum"
	"strconv"
)

//EdgeFilter is a type of function that can be passed to filter in edges. Only
//edges that return true will be kept. This package defines a large number of
//them, all of which start with "Direction".
type EdgeFilter func(enum enum.Enum, from, to int) bool

//DirectionUp will return true if to is in a strictly lower-indexed row then
//from.
func DirectionUp(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[0] > toIndexes[0]
}

//DirectionDown will return true if to is in a strictly higher-indexed row
//then from.
func DirectionDown(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[0] > toIndexes[0]
}

//DirectionLeft will return true if to is in a strictly lower-indexed col then
//from.
func DirectionLeft(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[1] > toIndexes[1]
}

//DirectionRight will return true if to is in a strictly higher-indexed col
//then from.
func DirectionRight(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	return fromIndexes[1] > toIndexes[1]
}

//DirectionPerpendicular will return true if to is perpendicular to from (in the
//same row or col).
func DirectionPerpendicular(enum enum.Enum, from, to int) bool {
	fromIndexes := enum.ValueToRange(from)
	toIndexes := enum.ValueToRange(to)
	if fromIndexes[0] == toIndexes[0] {
		return true
	}
	return fromIndexes[1] == toIndexes[1]
}

//DirectionDiagonal will return true if to is non-perpendicular to from.
func DirectionDiagonal(enum enum.Enum, from, to int) bool {
	return !DirectionPerpendicular(enum, from, to)
}

//NewGridConnectedness is a helper function to create a finished graph
//representing the connections between a grid. By default it adds edges
//between each of the 8 adjacent cells. However, all neighbors must pass the
//provided filters to be added. This package also defines a number of
//Direction* EdgeFilters. The enum passed must be a ranged, 2 dimensional enum.
//	//Returns a graph that has all cells connected to each of their neighbors.
//	NewGridConnectedness(e)
//
//  //Returns a graph that creates connections upward and diagonally from each
//  //cell.
//	NewGridConnectedness(e, DirectionUp, DirectionDiagonal)
//
func NewGridConnectedness(ranged2DEnum enum.Enum, filter ...EdgeFilter) (Graph, error) {
	if !ranged2DEnum.IsRange() {
		return nil, errors.New("The enum was not created with AddRange")
	}
	if len(ranged2DEnum.RangeDimensions()) != 2 {
		return nil, errors.New("The enum did not have two dimensions")
	}

	graph := New(false, ranged2DEnum)

	for _, val := range ranged2DEnum.Values() {

		theNeighbors := neighbors(ranged2DEnum, val)

		for _, theFilter := range filter {
			var tempNeighbors []int
			for _, n := range theNeighbors {
				if theFilter(ranged2DEnum, val, n) {
					tempNeighbors = append(tempNeighbors, n)
				}
			}
			theNeighbors = tempNeighbors
		}

		if err := graph.AddEdges(val, theNeighbors...); err != nil {
			return nil, errors.New("Couldn't add " + strconv.Itoa(val) + ": " + fmt.Sprintf("%v", theNeighbors) + ": " + err.Error())
		}

	}

	graph.Finish()

	return graph, nil

}

//assumes that theEnum is a 2d ranged enum, and that start is a valid value in
//it.
func neighbors(theEnum enum.Enum, start int) []int {
	var result []int
	indexes := theEnum.ValueToRange(start)
	for rOffset := -1; rOffset < 2; rOffset++ {
		for cOffset := -1; cOffset < 2; cOffset++ {

			if rOffset == 0 && cOffset == 0 {
				//This is the start cell
				continue
			}

			r := indexes[0] + rOffset
			c := indexes[1] + cOffset

			val := theEnum.RangeToValue(r, c)

			if val != enum.IllegalValue {
				result = append(result, val)
			}

		}
	}
	return result
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/influxdata/flux"
	"github.com/influxdata/flux/csv"
	"github.com/influxdata/flux/lang"
	iclient "github.com/influxdata/influxdb/client"
	"github.com/pkg/errors"
)

const (
	fluxPath = "/api/v2/query"
)

// Shared transports for all clients to prevent leaking connections
var (
	skipVerifyTransport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	defaultTransport = &http.Transport{}
)

// HTTP implements a Flux query client that makes requests to the /api/v2/query
// API endpoint.
type HTTP struct {
	Addr               string
	InsecureSkipVerify bool
	url                *url.URL
}

// NewHTTP creates a HTTP client
func NewHTTP(host string, port int, ssl bool) (*HTTP, error) {
	addr := net.JoinHostPort(host, strconv.Itoa(port))
	u, e := iclient.ParseConnectionString(addr, ssl)
	if e != nil {
		return nil, e
	}
	u.Path = fluxPath
	return &HTTP{url: &u}, nil
}

// Query runs a flux query against a influx server and decodes the result
func (s *HTTP) Query(ctx context.Context, r *ProxyRequest) (flux.ResultIterator, error) {
	qreq, err := QueryRequestFromProxyRequest(r)
	if err != nil {
		return nil, err
	}
	var body bytes.Buffer
	if err := json.NewEncoder(&body).Encode(qreq); err != nil {
		return nil, err
	}

	hreq, err := http.NewRequest("POST", s.url.String(), &body)
	if err != nil {
		return nil, err
	}

	hreq.Header.Set("Content-Type", "application/json")
	hreq.Header.Set("Accept", "text/csv")
	hreq = hreq.WithContext(ctx)

	hc := newClient(s.url.Scheme, s.InsecureSkipVerify)
	resp, err := hc.Do(hreq)
	if err != nil {
		return nil, err
	}

	if err := checkError(resp); err != nil {
		return nil, err
	}

	decoder := csv.NewMultiResultDecoder(csv.ResultDecoderConfig{})
	return decoder.Decode(resp.Body)
}

func newClient(scheme string, insecure bool) *http.Client {
	hc := &http.Client{
		Transport: defaultTransport,
	}
	if scheme == "https" && insecure {
		hc.Transport = skipVerifyTransport
	}
	return hc
}

// CheckError reads the http.Response and returns an error if one exists.
// It will automatically recognize the errors returned by Influx services
// and decode the error into an internal error type. If the error cannot
// be determined in that way, it will create a generic error message.
//
// If there is no error, then this returns nil.
func checkError(resp *http.Response) error {
	switch resp.StatusCode / 100 {
	case 4, 5:
		// We will attempt to parse this error outside of this block.
	case 2:
		return nil
	default:
		// TODO(jsternberg): Figure out what to do here?
		//return kerrors.InternalErrorf("unexpected status code: %d %s", resp.StatusCode, resp.Status)
	}

	// There is no influx error so we need to report that we have some kind
	// of error from somewhere.
	// TODO(jsternberg): Try to make this more advance by reading the response
	// and either decoding a possible json message or just reading the text itself.
	// This might be good enough though.
	msg := "unknown server error"
	if resp.StatusCode/100 == 4 {
		msg = "client error"
	}
	return errors.Wrap(errors.New(resp.Status), msg)
}

func QueryRequestFromProxyRequest(req *ProxyRequest) (*QueryRequest, error) {
	qr := new(QueryRequest)
	switch c := req.Compiler.(type) {
	case lang.FluxCompiler:
		qr.Type = "flux"
		qr.Query = c.Query
	case lang.SpecCompiler:
		qr.Type = "flux"
		qr.Spec = c.Spec
	default:
		return nil, fmt.Errorf("unsupported compiler %T", c)
	}
	switch d := req.Dialect.(type) {
	case *csv.Dialect:
		var header = !d.ResultEncoderConfig.NoHeader
		qr.Dialect.Header = &header
		qr.Dialect.Delimiter = string(d.ResultEncoderConfig.Delimiter)
		qr.Dialect.CommentPrefix = "#"
		qr.Dialect.DateTimeFormat = "RFC3339"
		qr.Dialect.Annotations = d.ResultEncoderConfig.Annotations
	default:
		return nil, fmt.Errorf("unsupported dialect %T", d)
	}

	return qr, nil
}
<commit_msg>feat(cli/influx): Display detailed error messages when available<commit_after>package client

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"mime"
	"net"
	"net/http"
	"net/url"
	"strconv"

	"github.com/influxdata/flux"
	"github.com/influxdata/flux/csv"
	"github.com/influxdata/flux/lang"
	iclient "github.com/influxdata/influxdb/client"
	"github.com/pkg/errors"
)

const (
	fluxPath = "/api/v2/query"
)

// Shared transports for all clients to prevent leaking connections
var (
	skipVerifyTransport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	defaultTransport = &http.Transport{}
)

// HTTP implements a Flux query client that makes requests to the /api/v2/query
// API endpoint.
type HTTP struct {
	Addr               string
	InsecureSkipVerify bool
	url                *url.URL
}

// NewHTTP creates a HTTP client
func NewHTTP(host string, port int, ssl bool) (*HTTP, error) {
	addr := net.JoinHostPort(host, strconv.Itoa(port))
	u, e := iclient.ParseConnectionString(addr, ssl)
	if e != nil {
		return nil, e
	}
	u.Path = fluxPath
	return &HTTP{url: &u}, nil
}

// Query runs a flux query against a influx server and decodes the result
func (s *HTTP) Query(ctx context.Context, r *ProxyRequest) (flux.ResultIterator, error) {
	qreq, err := QueryRequestFromProxyRequest(r)
	if err != nil {
		return nil, err
	}
	var body bytes.Buffer
	if err := json.NewEncoder(&body).Encode(qreq); err != nil {
		return nil, err
	}

	hreq, err := http.NewRequest("POST", s.url.String(), &body)
	if err != nil {
		return nil, err
	}

	hreq.Header.Set("Content-Type", "application/json")
	hreq.Header.Set("Accept", "text/csv")
	hreq = hreq.WithContext(ctx)

	hc := newClient(s.url.Scheme, s.InsecureSkipVerify)
	resp, err := hc.Do(hreq)
	if err != nil {
		return nil, err
	}

	if err := checkError(resp); err != nil {
		return nil, err
	}

	decoder := csv.NewMultiResultDecoder(csv.ResultDecoderConfig{})
	return decoder.Decode(resp.Body)
}

func newClient(scheme string, insecure bool) *http.Client {
	hc := &http.Client{
		Transport: defaultTransport,
	}
	if scheme == "https" && insecure {
		hc.Transport = skipVerifyTransport
	}
	return hc
}

// CheckError reads the http.Response and returns an error if one exists.
// It will automatically recognize the errors returned by Influx services
// and decode the error into an internal error type. If the error cannot
// be determined in that way, it will create a generic error message.
//
// If there is no error, then this returns nil.
func checkError(resp *http.Response) error {
	switch resp.StatusCode / 100 {
	case 4:
		// We will attempt to parse this error outside of this block.
		msg := "client error"
		data, _ := ioutil.ReadAll(resp.Body)
		mt, _, err := mime.ParseMediaType(resp.Header.Get("content-type"))
		if err == nil && mt == "text/plain" && len(msg) > 0 {
			msg = string(data)
		}
		return errors.Wrap(errors.New(resp.Status), msg)
	case 1, 2:
		return nil

	default:
		msg := "unknown server error"
		return errors.Wrap(errors.New(resp.Status), msg)
	}
}

func QueryRequestFromProxyRequest(req *ProxyRequest) (*QueryRequest, error) {
	qr := new(QueryRequest)
	switch c := req.Compiler.(type) {
	case lang.FluxCompiler:
		qr.Type = "flux"
		qr.Query = c.Query
	case lang.SpecCompiler:
		qr.Type = "flux"
		qr.Spec = c.Spec
	default:
		return nil, fmt.Errorf("unsupported compiler %T", c)
	}
	switch d := req.Dialect.(type) {
	case *csv.Dialect:
		var header = !d.ResultEncoderConfig.NoHeader
		qr.Dialect.Header = &header
		qr.Dialect.Delimiter = string(d.ResultEncoderConfig.Delimiter)
		qr.Dialect.CommentPrefix = "#"
		qr.Dialect.DateTimeFormat = "RFC3339"
		qr.Dialect.Annotations = d.ResultEncoderConfig.Annotations
	default:
		return nil, fmt.Errorf("unsupported dialect %T", d)
	}

	return qr, nil
}
<|endoftext|>


<commit_before>package jsonrpc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

type Client struct {
	Url string
	id int
}

type Response struct {
	Id int `json:"id"`
	Result interface{} `json:"result"`
	Error *ResponseError `json:"error"`
}

type ResponseError struct {
	Code int `json:"code"`
	Message string `json:"message"`
	Data interface{} `json:"data"`
}

func NewClient(url string) *Client {
	client := new(Client)
	client.Url = url
	return client
}

func (c *Client) Call(method string, params interface{}) (*Response, error) {
	var payload = map[string]interface{}{
		"jsonrpc": "2.0",
		"method":  method,
		"params":  params,
		"id":      c.id,
	}

	c.id += 1
	data, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}
	buf := bytes.NewBuffer(data)
	resp, err := http.Post(c.Url, "application/json", buf)

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

	decoder := json.NewDecoder(resp.Body)
	var respPayload *Response
	err = decoder.Decode(&respPayload)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("Invalid response from server. Status: %s. %s", resp.Status, err.Error()))
	}

	return respPayload, nil
}
<commit_msg>update<commit_after>package jsonrpc

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"time"
)

type Client struct {
	Url string
	id  int
	c   *http.Client
}

type Response struct {
	Id     int            `json:"id"`
	Result interface{}    `json:"result"`
	Error  *ResponseError `json:"error"`
}

type ResponseError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

func NewClient(url string) *Client {
	client := new(Client)
	client.Url = url
	client.c = &http.Client{}
	return client
}

func (c *Client) Call(method string, params interface{}) (*Response, error) {
	var payload = map[string]interface{}{
		"jsonrpc": "2.0",
		"method":  method,
		"params":  params,
		"id":      c.id,
	}

	c.id += 1
	data, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}
	buf := bytes.NewBuffer(data)
	c.c.Timeout = timeout
	resp, err := c.c.Post(c.Url, "application/json", buf)

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

	decoder := json.NewDecoder(resp.Body)
	var respPayload *Response
	err = decoder.Decode(&respPayload)

	if err != nil {
		return nil, errors.New(fmt.Sprintf("Invalid response from server. Status: %s. %s", resp.Status, err.Error()))
	}

	return respPayload, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package jsre

import (
	"io/ioutil"
	"os"
	"path"
	"testing"
	"time"

	"github.com/robertkrimen/otto"
)

type testNativeObjectBinding struct{}

type msg struct {
	Msg string
}

func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value {
	m, err := call.Argument(0).ToString()
	if err != nil {
		return otto.UndefinedValue()
	}
	v, _ := call.Otto.ToValue(&msg{m})
	return v
}

func newWithTestJS(t *testing.T, testjs string) (*JSRE, string) {
	dir, err := ioutil.TempDir("", "jsre-test")
	if err != nil {
		t.Fatal("cannot create temporary directory:", err)
	}
	if testjs != "" {
		if err := ioutil.WriteFile(path.Join(dir, "test.js"), []byte(testjs), os.ModePerm); err != nil {
			t.Fatal("cannot create test.js:", err)
		}
	}
	return New(dir), dir
}

func TestExec(t *testing.T) {
	jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
	defer os.RemoveAll(dir)

	err := jsre.Exec("test.js")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}

func TestNatto(t *testing.T) {
	jsre, dir := newWithTestJS(t, `setTimeout(function(){msg = "testMsg"}, 1);`)
	defer os.RemoveAll(dir)

	err := jsre.Exec("test.js")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	time.Sleep(time.Millisecond * 10)
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}

func TestBind(t *testing.T) {
	jsre := New("")
	defer jsre.Stop(false)

	jsre.Bind("no", &testNativeObjectBinding{})

	_, err := jsre.Run(`no.TestMethod("testMsg")`)
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestLoadScript(t *testing.T) {
	jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
	defer os.RemoveAll(dir)

	_, err := jsre.Run(`loadScript("test.js")`)
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}
<commit_msg>jsre: fix #1876, sleep too short on a slow test server<commit_after>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package jsre

import (
	"io/ioutil"
	"os"
	"path"
	"testing"
	"time"

	"github.com/robertkrimen/otto"
)

type testNativeObjectBinding struct{}

type msg struct {
	Msg string
}

func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value {
	m, err := call.Argument(0).ToString()
	if err != nil {
		return otto.UndefinedValue()
	}
	v, _ := call.Otto.ToValue(&msg{m})
	return v
}

func newWithTestJS(t *testing.T, testjs string) (*JSRE, string) {
	dir, err := ioutil.TempDir("", "jsre-test")
	if err != nil {
		t.Fatal("cannot create temporary directory:", err)
	}
	if testjs != "" {
		if err := ioutil.WriteFile(path.Join(dir, "test.js"), []byte(testjs), os.ModePerm); err != nil {
			t.Fatal("cannot create test.js:", err)
		}
	}
	return New(dir), dir
}

func TestExec(t *testing.T) {
	jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
	defer os.RemoveAll(dir)

	err := jsre.Exec("test.js")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}

func TestNatto(t *testing.T) {
	jsre, dir := newWithTestJS(t, `setTimeout(function(){msg = "testMsg"}, 1);`)
	defer os.RemoveAll(dir)

	err := jsre.Exec("test.js")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	time.Sleep(100 * time.Millisecond)
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}

func TestBind(t *testing.T) {
	jsre := New("")
	defer jsre.Stop(false)

	jsre.Bind("no", &testNativeObjectBinding{})

	_, err := jsre.Run(`no.TestMethod("testMsg")`)
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestLoadScript(t *testing.T) {
	jsre, dir := newWithTestJS(t, `msg = "testMsg"`)
	defer os.RemoveAll(dir)

	_, err := jsre.Run(`loadScript("test.js")`)
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	val, err := jsre.Run("msg")
	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}
	if !val.IsString() {
		t.Errorf("expected string value, got %v", val)
	}
	exp := "testMsg"
	got, _ := val.ToString()
	if exp != got {
		t.Errorf("expected '%v', got '%v'", exp, got)
	}
	jsre.Stop(false)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

type dirAliases struct {
	m                 map[string]FileServer
	mu                sync.RWMutex
	FileServerFactory fileServerFactory
}

func (da *dirAliases) List() []string {
	da.mu.RLock()
	defer da.mu.RUnlock()
	aliases := make([]string, 0, len(da.m))
	for alias := range da.m {
		aliases = append(aliases, alias)
	}
	return aliases
}

// Get retrieves the path for the given alias.
// It returns "" if the alias doesn't exist.
func (da *dirAliases) Get(alias string) string {
	da.mu.RLock()
	defer da.mu.RUnlock()
	return da.m[alias].Root()
}

// Put registers an alias for the given path.
// It returns true if the alias already exists.
func (da *dirAliases) Put(alias string, path string) bool {
	da.mu.Lock()
	defer da.mu.Unlock()
	_, ok := da.m[alias]

	fs := da.FileServerFactory(path)
	da.m[alias] = fs
	return ok
}

// Delete removes an existing alias.
// It returns true if the alias existed.
func (da *dirAliases) Delete(alias string) bool {
	da.mu.RLock()
	defer da.mu.RUnlock()
	_, ok := da.m[alias]
	delete(da.m, alias)
	return ok
}

func (da *dirAliases) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !(strings.Count(r.URL.Path, "/") >= 2 && len(r.URL.Path) > 2) {
		http.NotFound(w, r)
		return
	}
	slashIndex := strings.Index(r.URL.Path[1:], "/")
	if slashIndex == -1 {
		http.NotFound(w, r)
		return
	}
	alias := r.URL.Path[1 : slashIndex+1]
	r.URL.Path = r.URL.Path[1+slashIndex:]

	da.mu.RLock()
	defer da.mu.RUnlock()
	fs, ok := da.m[alias]
	if !ok {
		http.Error(w, fmt.Sprintf("alias %q not found", alias), http.StatusNotFound)
		return
	}
	fs.ServeHTTP(w, r)
}

func newDirAliases() *dirAliases {
	return &dirAliases{
		m:                 make(map[string]FileServer),
		FileServerFactory: stdFileServerFactory,
	}
}

type dirServer struct {
	DirAliases *dirAliases
	Addr       string
	Port       uint16
	srv        *http.Server
	ln         net.Listener
	started    chan struct{}
}

func newDirServer(addr string) *dirServer {
	return &dirServer{
		DirAliases: newDirAliases(),
		Addr:       addr,
		started:    make(chan struct{}),
	}
}

func (ds *dirServer) ListenAndServe() error {
	ln, err := net.Listen("tcp", ds.Addr)
	if err != nil {
		return err
	}
	ds.Addr = ln.Addr().String()
	_, sport, err := net.SplitHostPort(ds.Addr)
	if err != nil {
		return err
	}
	port, err := strconv.Atoi(sport)
	if err != nil {
		return err
	}
	ds.Port = uint16(port)
	ds.srv = &http.Server{
		Handler: ds.DirAliases,
	}
	ds.ln = tcpKeepAliveListener{ln.(*net.TCPListener)}

	close(ds.started)
	if err := ds.srv.Serve(ds.ln); err != nil {
		return err
	}
	return nil
}

func (ds *dirServer) Close() error {
	return ds.ln.Close()
}

// borrowed from net/http
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// borrowed from net/http
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}

type serverPool struct {
	Srvs  []*dirServer
	SrvCh chan *dirServer
}

func (sp *serverPool) Add(addr string) (*dirServer, error) {
	if err := CheckAddr(addr); err != nil {
		return nil, err
	}
	ds := newDirServer(addr)
	sp.SrvCh <- ds
	<-ds.started
	sp.Srvs = append(sp.Srvs, ds)
	return ds, nil
}

func (sp *serverPool) Get(port uint16) *dirServer {
	for _, srv := range sp.Srvs {
		if srv.Port == port {
			return srv
		}
	}
	return nil
}

func (sp *serverPool) Remove(port uint16) (bool, error) {
	for i, srv := range sp.Srvs {
		if srv.Port != port {
			continue
		}
		if err := srv.Close(); err != nil {
			return false, err
		}
		copy(sp.Srvs[i:], sp.Srvs[i+1:])
		sp.Srvs[len(sp.Srvs)-1] = nil
		sp.Srvs = sp.Srvs[:len(sp.Srvs)-1]
		return true, nil
	}
	return false, nil
}

func (sp *serverPool) ListenAndRun() {
	for _, srv := range sp.Srvs {
		go func(ds *dirServer) {
			// TODO remove server from list?
			log.Print(ds.ListenAndServe())
		}(srv)
	}
	for srv := range sp.SrvCh {
		go func(ds *dirServer) {
			// TODO remove server from list?
			log.Print(ds.ListenAndServe())
		}(srv)
	}
}

func CheckAddr(addr string) error {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return ln.Close()
}
<commit_msg>Handle case where an alias doesn't exist<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

type dirAliases struct {
	m                 map[string]FileServer
	mu                sync.RWMutex
	FileServerFactory fileServerFactory
}

func (da *dirAliases) List() []string {
	da.mu.RLock()
	defer da.mu.RUnlock()
	aliases := make([]string, 0, len(da.m))
	for alias := range da.m {
		aliases = append(aliases, alias)
	}
	return aliases
}

// Get retrieves the path for the given alias.
// It returns "" if the alias doesn't exist.
func (da *dirAliases) Get(alias string) string {
	da.mu.RLock()
	defer da.mu.RUnlock()
	fs, ok := da.m[alias]
	if !ok {
		return ""
	}
	return fs.Root()
}

// Put registers an alias for the given path.
// It returns true if the alias already exists.
func (da *dirAliases) Put(alias string, path string) bool {
	da.mu.Lock()
	defer da.mu.Unlock()
	_, ok := da.m[alias]

	fs := da.FileServerFactory(path)
	da.m[alias] = fs
	return ok
}

// Delete removes an existing alias.
// It returns true if the alias existed.
func (da *dirAliases) Delete(alias string) bool {
	da.mu.RLock()
	defer da.mu.RUnlock()
	_, ok := da.m[alias]
	delete(da.m, alias)
	return ok
}

func (da *dirAliases) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !(strings.Count(r.URL.Path, "/") >= 2 && len(r.URL.Path) > 2) {
		http.NotFound(w, r)
		return
	}
	slashIndex := strings.Index(r.URL.Path[1:], "/")
	if slashIndex == -1 {
		http.NotFound(w, r)
		return
	}
	alias := r.URL.Path[1 : slashIndex+1]
	r.URL.Path = r.URL.Path[1+slashIndex:]

	da.mu.RLock()
	defer da.mu.RUnlock()
	fs, ok := da.m[alias]
	if !ok {
		http.Error(w, fmt.Sprintf("alias %q not found", alias), http.StatusNotFound)
		return
	}
	fs.ServeHTTP(w, r)
}

func newDirAliases() *dirAliases {
	return &dirAliases{
		m:                 make(map[string]FileServer),
		FileServerFactory: stdFileServerFactory,
	}
}

type dirServer struct {
	DirAliases *dirAliases
	Addr       string
	Port       uint16
	srv        *http.Server
	ln         net.Listener
	started    chan struct{}
}

func newDirServer(addr string) *dirServer {
	return &dirServer{
		DirAliases: newDirAliases(),
		Addr:       addr,
		started:    make(chan struct{}),
	}
}

func (ds *dirServer) ListenAndServe() error {
	ln, err := net.Listen("tcp", ds.Addr)
	if err != nil {
		return err
	}
	ds.Addr = ln.Addr().String()
	_, sport, err := net.SplitHostPort(ds.Addr)
	if err != nil {
		return err
	}
	port, err := strconv.Atoi(sport)
	if err != nil {
		return err
	}
	ds.Port = uint16(port)
	ds.srv = &http.Server{
		Handler: ds.DirAliases,
	}
	ds.ln = tcpKeepAliveListener{ln.(*net.TCPListener)}

	close(ds.started)
	if err := ds.srv.Serve(ds.ln); err != nil {
		return err
	}
	return nil
}

func (ds *dirServer) Close() error {
	return ds.ln.Close()
}

// borrowed from net/http
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// borrowed from net/http
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}

type serverPool struct {
	Srvs  []*dirServer
	SrvCh chan *dirServer
}

func (sp *serverPool) Add(addr string) (*dirServer, error) {
	if err := CheckAddr(addr); err != nil {
		return nil, err
	}
	ds := newDirServer(addr)
	sp.SrvCh <- ds
	<-ds.started
	sp.Srvs = append(sp.Srvs, ds)
	return ds, nil
}

func (sp *serverPool) Get(port uint16) *dirServer {
	for _, srv := range sp.Srvs {
		if srv.Port == port {
			return srv
		}
	}
	return nil
}

func (sp *serverPool) Remove(port uint16) (bool, error) {
	for i, srv := range sp.Srvs {
		if srv.Port != port {
			continue
		}
		if err := srv.Close(); err != nil {
			return false, err
		}
		copy(sp.Srvs[i:], sp.Srvs[i+1:])
		sp.Srvs[len(sp.Srvs)-1] = nil
		sp.Srvs = sp.Srvs[:len(sp.Srvs)-1]
		return true, nil
	}
	return false, nil
}

func (sp *serverPool) ListenAndRun() {
	for _, srv := range sp.Srvs {
		go func(ds *dirServer) {
			// TODO remove server from list?
			log.Print(ds.ListenAndServe())
		}(srv)
	}
	for srv := range sp.SrvCh {
		go func(ds *dirServer) {
			// TODO remove server from list?
			log.Print(ds.ListenAndServe())
		}(srv)
	}
}

func CheckAddr(addr string) error {
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return ln.Close()
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Jorge Acereda Maciá. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

// Package ffvorbis provides a wrapper around the vorbis codec in ffmpeg.
package ffvorbis

// #cgo LDFLAGS: -lavcodec
/*
#include "libavcodec/avcodec.h"
#if LIBAVCODEC_VERSION_MAJOR == 53
#define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS
#endif
#include <string.h>
extern AVCodec ff_vorbis_decoder;

static void convertS16(void * vd, const void * vs, int n) {
 const int16_t * s = (const int16_t*)vs;
 float * d = (float*)vd;
 float scale = 1 / 65536.0; // 32768.0f;
 int i;
 for (i = 0; i < n; i++) d[i] = scale * s[i];
}
*/
import "C"

import (
	"log"
	"unsafe"
)

func init() {
	C.avcodec_register(&C.ff_vorbis_decoder)
}

type Decoder struct {
	c  *C.AVCodec
	cc *C.AVCodecContext
}

func NewDecoder(data []byte, channels, rate int) *Decoder {
	var d Decoder
	d.c = C.avcodec_find_decoder(C.AV_CODEC_ID_VORBIS)
	d.cc = C.avcodec_alloc_context3(d.c)
	d.cc.codec_type = C.AVMEDIA_TYPE_AUDIO
	d.cc.sample_rate = C.int(rate)
	d.cc.channels = C.int(channels)
	d.cc.extradata = (*C.uint8_t)(&data[0])
	d.cc.extradata_size = C.int(len(data))
	d.cc.channels = 2
	C.avcodec_open2(d.cc, d.c, nil)
	return &d
}

func (d *Decoder) Decode(data []byte) []float32 {
	var pkt C.AVPacket
	var fr C.AVFrame
	var got C.int
	C.avcodec_get_frame_defaults(&fr)
	C.av_init_packet(&pkt)
	pkt.data = (*C.uint8_t)(&data[0])
	pkt.size = C.int(len(data))
	dec := C.avcodec_decode_audio4(d.cc, &fr, &got, &pkt)
	if dec < 0 {
		log.Println("Unable to decode")
		return nil
	}
	if dec != pkt.size {
		log.Println("Partial decode")
	}
	if got == 0 {
		return nil
	}
	nvals := d.cc.channels * fr.nb_samples
	buf := make([]float32, nvals)
	dst := unsafe.Pointer(&buf[0])
	src := unsafe.Pointer(fr.data[0])
	switch d.cc.sample_fmt {
	case C.AV_SAMPLE_FMT_FLT:
		C.memcpy(dst, src, C.size_t(nvals*4))
	case C.AV_SAMPLE_FMT_S16:
		C.convertS16(dst, src, nvals)
	default:
		log.Panic("Unsupported format")
	}
	if pkt.data != nil {
		C.av_free_packet(&pkt)
	}
	return buf
}
<commit_msg>Register all codecs, ff_vorbis_decoder isn't exported on Linux<commit_after>// Copyright (c) 2012, Jorge Acereda Maciá. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

// Package ffvorbis provides a wrapper around the vorbis codec in ffmpeg.
package ffvorbis

// #cgo LDFLAGS: -lavcodec
/*
#include "libavcodec/avcodec.h"
#if LIBAVCODEC_VERSION_MAJOR == 53
#define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS
#endif
#include <string.h>
extern AVCodec ff_vorbis_decoder;

static void convertS16(void * vd, const void * vs, int n) {
 const int16_t * s = (const int16_t*)vs;
 float * d = (float*)vd;
 float scale = 1 / 65536.0; // 32768.0f;
 int i;
 for (i = 0; i < n; i++) d[i] = scale * s[i];
}
*/
import "C"

import (
	"log"
	"unsafe"
)

func init() {
	C.avcodec_register_all()
}

type Decoder struct {
	c  *C.AVCodec
	cc *C.AVCodecContext
}

func NewDecoder(data []byte, channels, rate int) *Decoder {
	var d Decoder
	d.c = C.avcodec_find_decoder(C.AV_CODEC_ID_VORBIS)
	d.cc = C.avcodec_alloc_context3(d.c)
	d.cc.codec_type = C.AVMEDIA_TYPE_AUDIO
	d.cc.sample_rate = C.int(rate)
	d.cc.channels = C.int(channels)
	d.cc.extradata = (*C.uint8_t)(&data[0])
	d.cc.extradata_size = C.int(len(data))
	d.cc.channels = 2
	C.avcodec_open2(d.cc, d.c, nil)
	return &d
}

func (d *Decoder) Decode(data []byte) []float32 {
	var pkt C.AVPacket
	var fr C.AVFrame
	var got C.int
	C.avcodec_get_frame_defaults(&fr)
	C.av_init_packet(&pkt)
	pkt.data = (*C.uint8_t)(&data[0])
	pkt.size = C.int(len(data))
	dec := C.avcodec_decode_audio4(d.cc, &fr, &got, &pkt)
	if dec < 0 {
		log.Println("Unable to decode")
		return nil
	}
	if dec != pkt.size {
		log.Println("Partial decode")
	}
	if got == 0 {
		return nil
	}
	nvals := d.cc.channels * fr.nb_samples
	buf := make([]float32, nvals)
	dst := unsafe.Pointer(&buf[0])
	src := unsafe.Pointer(fr.data[0])
	switch d.cc.sample_fmt {
	case C.AV_SAMPLE_FMT_FLT:
		C.memcpy(dst, src, C.size_t(nvals*4))
	case C.AV_SAMPLE_FMT_S16:
		C.convertS16(dst, src, nvals)
	default:
		log.Panic("Unsupported format")
	}
	if pkt.data != nil {
		C.av_free_packet(&pkt)
	}
	return buf
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"fmt"
	"testing"
)

func ExampleLanguage() {
	Seed(11)
	fmt.Println(Language())
	// Output: Kazakh
}

func BenchmarkLanguage(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Language()
	}
}

func ExampleLanguageAbbreviation() {
	Seed(11)
	fmt.Println(LanguageAbbreviation())
	// Output: kk
}

func BenchmarkLanguageAbbreviation(b *testing.B) {
	for i := 0; i < b.N; i++ {
		LanguageAbbreviation()
	}
}

func ExampleProgrammingLanguage() {
	Seed(464)
	fmt.Println(ProgrammingLanguage())
	// Output: Go
}

func BenchmarkProgrammingLanguage(b *testing.B) {
	for i := 0; i < b.N; i++ {
		ProgrammingLanguage()
	}
}

func ExampleProgrammingLanguageBest() {
	Seed(11)
	fmt.Println(ProgrammingLanguageBest())
	// Output: Go
}

func BenchmarkProgrammingLanguageBest(b *testing.B) {
	for i := 0; i < b.N; i++ {
		ProgrammingLanguageBest()
	}
}
<commit_msg>language test<commit_after>package gofakeit

import (
	"fmt"
	"testing"
)

func ExampleLanguage() {
	Seed(11)
	fmt.Println(Language())
	// Output: Kazakh
}

func ExampleFaker_Language() {
	f := New(11)
	fmt.Println(f.Language())
	// Output: Kazakh
}

func BenchmarkLanguage(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Language()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Language()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Language()
		}
	})
}

func ExampleLanguageAbbreviation() {
	Seed(11)
	fmt.Println(LanguageAbbreviation())
	// Output: kk
}

func ExampleFaker_LanguageAbbreviation() {
	f := New(11)
	fmt.Println(f.LanguageAbbreviation())
	// Output: kk
}

func BenchmarkLanguageAbbreviation(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			LanguageAbbreviation()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.LanguageAbbreviation()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.LanguageAbbreviation()
		}
	})
}

func ExampleProgrammingLanguage() {
	Seed(464)
	fmt.Println(ProgrammingLanguage())
	// Output: Go
}

func ExampleFaker_ProgrammingLanguage() {
	f := New(464)
	fmt.Println(f.ProgrammingLanguage())
	// Output: Go
}

func BenchmarkProgrammingLanguage(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			ProgrammingLanguage()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.ProgrammingLanguage()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.ProgrammingLanguage()
		}
	})
}

func ExampleProgrammingLanguageBest() {
	Seed(11)
	fmt.Println(ProgrammingLanguageBest())
	// Output: Go
}

func ExampleFaker_ProgrammingLanguageBest() {
	f := New(11)
	fmt.Println(f.ProgrammingLanguageBest())
	// Output: Go
}

func BenchmarkProgrammingLanguageBest(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			ProgrammingLanguageBest()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.ProgrammingLanguageBest()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.ProgrammingLanguageBest()
		}
	})
}
<|endoftext|>


<commit_before>package gaerecords

import (
	"os"
	"appengine/datastore"
)

// Represents a single model. A model is a class of data.
//  // create a new model for 'people'
//  people := NewModel("people")
type Model struct {
	recordType string
}

// Creates a new model for data classified by the specified recordType.
//
// For example, the following code creates a new Model called 'people':
//
//   people := NewModel("people")
func NewModel(recordType string) *Model {

	model := new(Model)

	model.recordType = recordType

	return model

}

// Creates a new record of this type.
//   people := NewModel("people")
//   person1 := people.New()
//   person2 := people.New()
func (m *Model) New() *Record {
	return NewRecord(m)
}

// Gets the record type of the model as a string.  This is the string you specify
// when calling NewModel(string) and is used as the Kind in the datasource keys.
func (m *Model) RecordType() string {
	return m.recordType
}

/*
	Persistence
	----------------------------------------------------------------------
*/

// Finds the record of this type with the specified id.
//  people := NewModel("people")
//  firstPerson := people.Find(1)
func (m *Model) Find(id int64) (*Record, os.Error) {
	return findOneByID(m, id)
}

// Finds all records of this type.
//   people := NewModel("people")
//   everyone := people.All()
func (m *Model) All() ([]*Record, os.Error) {
	return findAll(m)
}

// Deletes a single record of this type.  Returns nil if successful, otherwise
// the datastore error that was returned.
//   people := NewModel("people")
//   people.Delete(1)
func (m *Model) Delete(id int64) os.Error {
	return deleteOneByID(m, id)
}

/*
	datastore.Keys
	----------------------------------------------------------------------
*/

// Creates a new datastore Key for this kind of record.
func (m *Model) NewKey() *datastore.Key {
	return datastore.NewIncompleteKey(GetAppEngineContext(), m.recordType, nil)
}

// Creates a new datastore Key for this kind of record with the specified ID.
func (m *Model) NewKeyWithID(id int64) *datastore.Key {
	return datastore.NewKey(GetAppEngineContext(), m.recordType, "", int64(id), nil)
}
<commit_msg>added comments to model fields<commit_after>package gaerecords

import (
	"os"
	"appengine/datastore"
)

// Represents a single model. A model is a class of data.
//  // create a new model for 'people'
//  people := NewModel("people")
type Model struct {

	// internal string holding the 'type' of this model,
	// or the kind of data this model works with
	recordType string
}

// Creates a new model for data classified by the specified recordType.
//
// For example, the following code creates a new Model called 'people':
//
//   people := NewModel("people")
func NewModel(recordType string) *Model {

	model := new(Model)

	model.recordType = recordType

	return model

}

// Creates a new record of this type.
//   people := NewModel("people")
//   person1 := people.New()
//   person2 := people.New()
func (m *Model) New() *Record {
	return NewRecord(m)
}

// Gets the record type of the model as a string.  This is the string you specify
// when calling NewModel(string) and is used as the Kind in the datasource keys.
func (m *Model) RecordType() string {
	return m.recordType
}

/*
	Persistence
	----------------------------------------------------------------------
*/

// Finds the record of this type with the specified id.
//  people := NewModel("people")
//  firstPerson := people.Find(1)
func (m *Model) Find(id int64) (*Record, os.Error) {
	return findOneByID(m, id)
}

// Finds all records of this type.
//   people := NewModel("people")
//   everyone := people.All()
func (m *Model) All() ([]*Record, os.Error) {
	return findAll(m)
}

// Deletes a single record of this type.  Returns nil if successful, otherwise
// the datastore error that was returned.
//   people := NewModel("people")
//   people.Delete(1)
func (m *Model) Delete(id int64) os.Error {
	return deleteOneByID(m, id)
}

/*
	datastore.Keys
	----------------------------------------------------------------------
*/

// Creates a new datastore Key for this kind of record.
func (m *Model) NewKey() *datastore.Key {
	return datastore.NewIncompleteKey(GetAppEngineContext(), m.recordType, nil)
}

// Creates a new datastore Key for this kind of record with the specified ID.
func (m *Model) NewKeyWithID(id int64) *datastore.Key {
	return datastore.NewKey(GetAppEngineContext(), m.recordType, "", int64(id), nil)
}
<|endoftext|>


<commit_before>package lib

import (
	"fmt"
	. "github.com/ahmetalpbalkan/go-linq"
)

type T interface{}

func getCollection(allPosts []*LongPost) map[string][]string {
	res, err := From(allPosts).GroupBy(func(post T) T { return post.(*LongPost).Category }, func(post T) T { return post.(*LongPost).Slug })
	if err != nil {
		fmt.Errorf("Error", err)
	} else {
		fmt.Println(res)
		for key, value := range res {
			fmt.Println(key, value)
		}
	}
}
<commit_msg>add return value<commit_after>package lib

import (
	"fmt"
	. "github.com/ahmetalpbalkan/go-linq"
)

type T interface{}

func getCollection(allPosts []*LongPost) map[string][]string {
	res, err := From(allPosts).GroupBy(func(post T) T { return post.(*LongPost).Category }, func(post T) T { return post.(*LongPost).Slug })
	if err != nil {
		fmt.Errorf("Error", err)
	} else {
		fmt.Println(res)
		for key, value := range res {
			fmt.Println(key, value)
		}
		return res
	}
}
<|endoftext|>