<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package present implements parsing and rendering of present files,
which can be slide presentations as in golang.org/x/tools/cmd/present
or articles as in golang.org/x/blog (the Go blog).

File Format

Present files begin with a header giving the title of the document
and other metadata, which looks like:

	# Title of document
	Subtitle of document
	15:04 2 Jan 2006
	Tags: foo, bar, baz
	Summary: This is a great document you want to read.
	OldURL: former-path-for-this-doc

The "# " prefix before the title indicates that this is
a Markdown-enabled present file: it uses
Markdown for text markup in the body of the file.
If the "# " prefix is missing, the file uses
legacy present markup, described below.

The date line may be written without a time:
	2 Jan 2006
In this case, the time will be interpreted as 10am UTC on that date.

The tags line is a comma-separated list of tags that may be used to categorize
the document.

The summary line gives a short summary used in blog feeds.

The old URL line, which may be repeated, gives an older (perhaps relative) URL
for this document.
A server might use these to generate appropriate redirects.

Only the title is required;
the subtitle, date, tags, summary, and old URL lines are optional.
In Markdown-enabled present, the summary defaults to being empty.
In legacy present, the summary defaults to the first paragraph of text.

After the header come zero or more author blocks, like this:

	Author Name
	Job title, Company
	joe@example.com
	https://url/
	@twitter_name

The first line of the author block is conventionally the author name.
Otherwise, the author section may contain a mixture of text, twitter names, and links.
For slide presentations, only the plain text lines will be displayed on the
first slide.

If multiple author blocks are listed, each new block must be preceded
by its own blank line.

After the author blocks come the presentation slides or article sections,
which can in turn have subsections.
In Markdown-enabled present files, each slide or section begins with a "##" header line,
subsections begin with a "###" header line, and so on.
In legacy present files, each slide or section begins with a "*" header line,
subsections begin with a "**" header line, and so on.

In addition to the marked-up text in a section (or subsection),
a present file can contain present command invocations, each of which begins
with a dot, as in:

	.code x.go /^func main/,/^}/
	.play y.go
	.image image.jpg
	.background image.jpg
	.iframe https://foo
	.link https://foo label
	.html file.html
	.caption _Gopher_ by [[https://twitter.com/reneefrench][Renée French]]

Other than the commands, the text in a section is interpreted
either as Markdown or as legacy present markup.

Markdown Syntax

Markdown typically means the generic name for a family of similar markup languages.
The specific variant used in present is CommonMark.
See https://commonmark.org/help/tutorial/ for a quick tutorial.

In Markdown-enabled present,
section headings can end in {#name} to set the HTML anchor ID for the heading to "name".

Lines beginning with "//" (outside of code blocks, of course)
are treated as present comments and have no effect.

Lines beginning with ": " are treated as speaker notes, described below.

Example:

	# Title of Talk

	My Name
	9 Mar 2020
	me@example.com

	## Title of Slide or Section (must begin with ##)

	Some Text

	### Subsection {#anchor}

	- bullets
	- more bullets
	- a bullet continued
	  on the next line

	#### Sub-subsection

	Some More text

		Preformatted text (code block)
		is indented (by one tab, or four spaces)

	Further Text, including command invocations.

	## Section 2: Example formatting {#fmt}

	Formatting:

	_italic_
	// A comment that is completely ignored.
	: Speaker notes.
	**bold**
	`program`
	Markup—_especially italic text_—can easily be overused.
	_Why use scoped\_ptr_? Use plain **\*ptr** instead.

	Visit [the Go home page](https://golang.org/).

Legacy Present Syntax

Compared to Markdown,
in legacy present
slides/sections use "*" instead of "##",
whole-line comments begin with "#" instead of "//",
bullet lists can only contain single (possibly wrapped) text lines,
and the font styling and link syntaxes are subtly different.

Example:

	Title of Talk

	My Name
	1 Jan 2013
	me@example.com

	* Title of Slide or Section (must begin with *)

	Some Text

	** Subsection

	- bullets
	- more bullets
	- a bullet continued
	  on the next line (indented at least one space)

	*** Sub-subsection

	Some More text

	  Preformatted text (code block)
	  is indented (however you like)

	Further Text, including command invocations.

	* Section 2: Example formatting

	Formatting:

	_italic_
	*bold*
	`program`
	Markup—_especially_italic_text_—can easily be overused.
	_Why_use_scoped__ptr_? Use plain ***ptr* instead.

	Visit [[https://golang.org][the Go home page]].

Within the input for plain text or lists, text bracketed by font
markers will be presented in italic, bold, or program font.
Marker characters are _ (italic), * (bold) and ` (program font).
An opening marker must be preceded by a space or punctuation
character or else be at start of a line; similarly, a closing
marker must be followed by a space or punctuation character or
else be at the end of a line. Unmatched markers appear as plain text.
There must be no spaces between markers. Within marked text,
a single marker character becomes a space and a doubled single
marker quotes the marker character.

Links can be included in any text with the form [[url][label]], or
[[url]] to use the URL itself as the label.

Command Invocations

A number of special commands are available through invocations
in the input text. Each such invocation contains a period as the
first character on the line, followed immediately by the name of
the function, followed by any arguments. A typical invocation might
be

	.play demo.go /^func show/,/^}/

(except that the ".play" must be at the beginning of the line and
not be indented as in this comment.)

Here follows a description of the functions:

code:

Injects program source into the output by extracting code from files
and injecting them as HTML-escaped <pre> blocks.  The argument is
a file name followed by an optional address that specifies what
section of the file to display. The address syntax is similar in
its simplest form to that of ed, but comes from sam and is more
general. See
	https://plan9.io/sys/doc/sam/sam.html Table II
for full details. The displayed block is always rounded out to a
full line at both ends.

If no pattern is present, the entire file is displayed.

Any line in the program that ends with the four characters
	OMIT
is deleted from the source before inclusion, making it easy
to write things like
	.code test.go /START OMIT/,/END OMIT/
to find snippets like this
	tedious_code = boring_function()
	// START OMIT
	interesting_code = fascinating_function()
	// END OMIT
and see only this:
	interesting_code = fascinating_function()

Also, inside the displayed text a line that ends
	// HL
will be highlighted in the display. A highlighting mark may have a
suffix word, such as
	// HLxxx
Such highlights are enabled only if the code invocation ends with
"HL" followed by the word:
	.code test.go /^type Foo/,/^}/ HLxxx

The .code function may take one or more flags immediately preceding
the filename. This command shows test.go in an editable text area:
	.code -edit test.go
This command shows test.go with line numbers:
	.code -numbers test.go

play:

The function "play" is the same as "code" but puts a button
on the displayed source so the program can be run from the browser.
Although only the selected text is shown, all the source is included
in the HTML output so it can be presented to the compiler.

link:

Create a hyperlink. The syntax is 1 or 2 space-separated arguments.
The first argument is always the HTTP URL.  If there is a second
argument, it is the text label to display for this link.

	.link https://golang.org golang.org

image:

The template uses the function "image" to inject picture files.

The syntax is simple: 1 or 3 space-separated arguments.
The first argument is always the file name.
If there are more arguments, they are the height and width;
both must be present, or substituted with an underscore.
Replacing a dimension argument with the underscore parameter
preserves the aspect ratio of the image when scaling.

	.image images/betsy.jpg 100 200
	.image images/janet.jpg _ 300

video:

The template uses the function "video" to inject video files.

The syntax is simple: 2 or 4 space-separated arguments.
The first argument is always the file name.
The second argument is always the file content-type.
If there are more arguments, they are the height and width;
both must be present, or substituted with an underscore.
Replacing a dimension argument with the underscore parameter
preserves the aspect ratio of the video when scaling.

	.video videos/evangeline.mp4 video/mp4 400 600

	.video videos/mabel.ogg video/ogg 500 _

background:

The template uses the function "background" to set the background image for
a slide.  The only argument is the file name of the image.

	.background images/susan.jpg

caption:

The template uses the function "caption" to inject figure captions.

The text after ".caption" is embedded in a figcaption element after
processing styling and links as in standard text lines.

	.caption _Gopher_ by [[https://twitter.com/reneefrench][Renée French]]

iframe:

The function "iframe" injects iframes (pages inside pages).
Its syntax is the same as that of image.

html:

The function html includes the contents of the specified file as
unescaped HTML. This is useful for including custom HTML elements
that cannot be created using only the slide format.
It is your responsibility to make sure the included HTML is valid and safe.

	.html file.html

Presenter Notes

Lines that begin with ": " are treated as presenter notes,
in both Markdown and legacy present syntax.
By default, presenter notes are collected but ignored.

When running the present command with -notes,
typing 'N' in your browser displaying your slides
will create a second window displaying the notes.
The second window is completely synced with the main
window, except that presenter notes are only visible in the second window.

Notes may appear anywhere within the slide text. For example:

	* Title of slide

	Some text.

	: Presenter notes (first paragraph)

	Some more text.

	: Presenter notes (subsequent paragraph(s))

*/
package present // import "golang.org/x/tools/present"
<commit_msg>x/tools/present: point to instagram sted twitter for Renee French<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package present implements parsing and rendering of present files,
which can be slide presentations as in golang.org/x/tools/cmd/present
or articles as in golang.org/x/blog (the Go blog).

File Format

Present files begin with a header giving the title of the document
and other metadata, which looks like:

	# Title of document
	Subtitle of document
	15:04 2 Jan 2006
	Tags: foo, bar, baz
	Summary: This is a great document you want to read.
	OldURL: former-path-for-this-doc

The "# " prefix before the title indicates that this is
a Markdown-enabled present file: it uses
Markdown for text markup in the body of the file.
If the "# " prefix is missing, the file uses
legacy present markup, described below.

The date line may be written without a time:
	2 Jan 2006
In this case, the time will be interpreted as 10am UTC on that date.

The tags line is a comma-separated list of tags that may be used to categorize
the document.

The summary line gives a short summary used in blog feeds.

The old URL line, which may be repeated, gives an older (perhaps relative) URL
for this document.
A server might use these to generate appropriate redirects.

Only the title is required;
the subtitle, date, tags, summary, and old URL lines are optional.
In Markdown-enabled present, the summary defaults to being empty.
In legacy present, the summary defaults to the first paragraph of text.

After the header come zero or more author blocks, like this:

	Author Name
	Job title, Company
	joe@example.com
	https://url/
	@twitter_name

The first line of the author block is conventionally the author name.
Otherwise, the author section may contain a mixture of text, twitter names, and links.
For slide presentations, only the plain text lines will be displayed on the
first slide.

If multiple author blocks are listed, each new block must be preceded
by its own blank line.

After the author blocks come the presentation slides or article sections,
which can in turn have subsections.
In Markdown-enabled present files, each slide or section begins with a "##" header line,
subsections begin with a "###" header line, and so on.
In legacy present files, each slide or section begins with a "*" header line,
subsections begin with a "**" header line, and so on.

In addition to the marked-up text in a section (or subsection),
a present file can contain present command invocations, each of which begins
with a dot, as in:

	.code x.go /^func main/,/^}/
	.play y.go
	.image image.jpg
	.background image.jpg
	.iframe https://foo
	.link https://foo label
	.html file.html
	.caption _Gopher_ by [[https://instagram.com/reneefrench][Renee French]]

Other than the commands, the text in a section is interpreted
either as Markdown or as legacy present markup.

Markdown Syntax

Markdown typically means the generic name for a family of similar markup languages.
The specific variant used in present is CommonMark.
See https://commonmark.org/help/tutorial/ for a quick tutorial.

In Markdown-enabled present,
section headings can end in {#name} to set the HTML anchor ID for the heading to "name".

Lines beginning with "//" (outside of code blocks, of course)
are treated as present comments and have no effect.

Lines beginning with ": " are treated as speaker notes, described below.

Example:

	# Title of Talk

	My Name
	9 Mar 2020
	me@example.com

	## Title of Slide or Section (must begin with ##)

	Some Text

	### Subsection {#anchor}

	- bullets
	- more bullets
	- a bullet continued
	  on the next line

	#### Sub-subsection

	Some More text

		Preformatted text (code block)
		is indented (by one tab, or four spaces)

	Further Text, including command invocations.

	## Section 2: Example formatting {#fmt}

	Formatting:

	_italic_
	// A comment that is completely ignored.
	: Speaker notes.
	**bold**
	`program`
	Markup—_especially italic text_—can easily be overused.
	_Why use scoped\_ptr_? Use plain **\*ptr** instead.

	Visit [the Go home page](https://golang.org/).

Legacy Present Syntax

Compared to Markdown,
in legacy present
slides/sections use "*" instead of "##",
whole-line comments begin with "#" instead of "//",
bullet lists can only contain single (possibly wrapped) text lines,
and the font styling and link syntaxes are subtly different.

Example:

	Title of Talk

	My Name
	1 Jan 2013
	me@example.com

	* Title of Slide or Section (must begin with *)

	Some Text

	** Subsection

	- bullets
	- more bullets
	- a bullet continued
	  on the next line (indented at least one space)

	*** Sub-subsection

	Some More text

	  Preformatted text (code block)
	  is indented (however you like)

	Further Text, including command invocations.

	* Section 2: Example formatting

	Formatting:

	_italic_
	*bold*
	`program`
	Markup—_especially_italic_text_—can easily be overused.
	_Why_use_scoped__ptr_? Use plain ***ptr* instead.

	Visit [[https://golang.org][the Go home page]].

Within the input for plain text or lists, text bracketed by font
markers will be presented in italic, bold, or program font.
Marker characters are _ (italic), * (bold) and ` (program font).
An opening marker must be preceded by a space or punctuation
character or else be at start of a line; similarly, a closing
marker must be followed by a space or punctuation character or
else be at the end of a line. Unmatched markers appear as plain text.
There must be no spaces between markers. Within marked text,
a single marker character becomes a space and a doubled single
marker quotes the marker character.

Links can be included in any text with the form [[url][label]], or
[[url]] to use the URL itself as the label.

Command Invocations

A number of special commands are available through invocations
in the input text. Each such invocation contains a period as the
first character on the line, followed immediately by the name of
the function, followed by any arguments. A typical invocation might
be

	.play demo.go /^func show/,/^}/

(except that the ".play" must be at the beginning of the line and
not be indented as in this comment.)

Here follows a description of the functions:

code:

Injects program source into the output by extracting code from files
and injecting them as HTML-escaped <pre> blocks.  The argument is
a file name followed by an optional address that specifies what
section of the file to display. The address syntax is similar in
its simplest form to that of ed, but comes from sam and is more
general. See
	https://plan9.io/sys/doc/sam/sam.html Table II
for full details. The displayed block is always rounded out to a
full line at both ends.

If no pattern is present, the entire file is displayed.

Any line in the program that ends with the four characters
	OMIT
is deleted from the source before inclusion, making it easy
to write things like
	.code test.go /START OMIT/,/END OMIT/
to find snippets like this
	tedious_code = boring_function()
	// START OMIT
	interesting_code = fascinating_function()
	// END OMIT
and see only this:
	interesting_code = fascinating_function()

Also, inside the displayed text a line that ends
	// HL
will be highlighted in the display. A highlighting mark may have a
suffix word, such as
	// HLxxx
Such highlights are enabled only if the code invocation ends with
"HL" followed by the word:
	.code test.go /^type Foo/,/^}/ HLxxx

The .code function may take one or more flags immediately preceding
the filename. This command shows test.go in an editable text area:
	.code -edit test.go
This command shows test.go with line numbers:
	.code -numbers test.go

play:

The function "play" is the same as "code" but puts a button
on the displayed source so the program can be run from the browser.
Although only the selected text is shown, all the source is included
in the HTML output so it can be presented to the compiler.

link:

Create a hyperlink. The syntax is 1 or 2 space-separated arguments.
The first argument is always the HTTP URL.  If there is a second
argument, it is the text label to display for this link.

	.link https://golang.org golang.org

image:

The template uses the function "image" to inject picture files.

The syntax is simple: 1 or 3 space-separated arguments.
The first argument is always the file name.
If there are more arguments, they are the height and width;
both must be present, or substituted with an underscore.
Replacing a dimension argument with the underscore parameter
preserves the aspect ratio of the image when scaling.

	.image images/betsy.jpg 100 200
	.image images/janet.jpg _ 300

video:

The template uses the function "video" to inject video files.

The syntax is simple: 2 or 4 space-separated arguments.
The first argument is always the file name.
The second argument is always the file content-type.
If there are more arguments, they are the height and width;
both must be present, or substituted with an underscore.
Replacing a dimension argument with the underscore parameter
preserves the aspect ratio of the video when scaling.

	.video videos/evangeline.mp4 video/mp4 400 600

	.video videos/mabel.ogg video/ogg 500 _

background:

The template uses the function "background" to set the background image for
a slide.  The only argument is the file name of the image.

	.background images/susan.jpg

caption:

The template uses the function "caption" to inject figure captions.

The text after ".caption" is embedded in a figcaption element after
processing styling and links as in standard text lines.

	.caption _Gopher_ by [[https://instagram.com/reneefrench][Renee French]]

iframe:

The function "iframe" injects iframes (pages inside pages).
Its syntax is the same as that of image.

html:

The function html includes the contents of the specified file as
unescaped HTML. This is useful for including custom HTML elements
that cannot be created using only the slide format.
It is your responsibility to make sure the included HTML is valid and safe.

	.html file.html

Presenter Notes

Lines that begin with ": " are treated as presenter notes,
in both Markdown and legacy present syntax.
By default, presenter notes are collected but ignored.

When running the present command with -notes,
typing 'N' in your browser displaying your slides
will create a second window displaying the notes.
The second window is completely synced with the main
window, except that presenter notes are only visible in the second window.

Notes may appear anywhere within the slide text. For example:

	* Title of slide

	Some text.

	: Presenter notes (first paragraph)

	Some more text.

	: Presenter notes (subsequent paragraph(s))

*/
package present // import "golang.org/x/tools/present"
<|endoftext|>


<commit_before>// This file contains the models that are passed between different
// servers running within the bot.

package model

type Config struct {
	Verbose bool

	// Base URL for Jira
	JiraUrl     string `required:"true"`
	JiraKey     string `required:"true"`
	JiraAppName string `default:"JiraSlack"`

	// Jira OAuth access data
	JiraAccessToken  string `required:"true"`
	JiraAccessSecret string `required:"true"`

	SlackKey string `required:"true"`
	SlackUrl string `default:""`

	WebHookBind string `default:":80"`
	WebHookKey  string `required:"true"`

	TemplateDir string `default:"./templates"`
}

type AttachmentField struct {
	Title string `json:"title"`
	Value string `json:"value"`
	Short bool   `json:"short,omitempty"`
}

type ChatAttachment struct {
	Fallback   string            `json:"fallback,omitempty"`
	Color      string            `json:"color,omitempty"`
	Pretext    string            `json:"pretext,omitempty"`
	AuthorName string            `json:"author_name,omitempty"`
	AuthorLink string            `json:"author_link,omitempty"`
	AuthorIcon string            `json:"author_icon,omitempty"`
	Title      string            `json:"title,omitempty"`
	TitleLink  string            `json:"title_link,omitempty"`
	Text       string            `json:"text,omitempty"`
	Fields     []AttachmentField `json:"fields,omitempty"`
	ImageUrl   string            `json:"image_url,omitempty"`
	ThumbUrl   string            `json:"thumb_url,omitempty"`
}

// ChatMessage contains information about an incoming or outgoing message.
type ChatMessage struct {
	// For incoming chat messages, the user who typed the message. This is
	// ignored for outging messages since we can't pretend to be another user.
	FromUser string
	// The user to whom the message is addresesed, if any. For Slack, this is
	// the @user at the beginning of the message.
	ToUser string
	// The name of a channel to send to.
	Channel string
	Text    string
	// For incoming messages, true if the message is addressed to the bot.
	// This can either be through a DM channel or by starting with @botuser.
	ToBot bool
	// Attachment, if any
	Attachment *ChatAttachment
}
<commit_msg>Use attachment model from slack package instead<commit_after>// This file contains the models that are passed between different
// servers running within the bot.

package model

import (
	"github.com/nlopes/slack"
)

type Config struct {
	Verbose bool

	// Base URL for Jira
	JiraUrl     string `required:"true"`
	JiraKey     string `required:"true"`
	JiraAppName string `default:"JiraSlack"`

	// Jira OAuth access data
	JiraAccessToken  string `required:"true"`
	JiraAccessSecret string `required:"true"`

	SlackKey            string `required:"true"`
	SlackUrl            string `default:"https://slack.com/api/"`
	SlackDefaultChannel string `required:"true"`

	WebHookBind string `default:":80"`
	WebHookKey  string `required:"true"`

	TemplateDir string `default:"./templates"`
}

// ChatMessage contains information about an incoming or outgoing message.
type ChatMessage struct {
	// For incoming chat messages, the user who typed the message. This is
	// ignored for outging messages since we can't pretend to be another user.
	FromUser string
	// The user to whom the message is addresesed, if any. For Slack, this is
	// the @user at the beginning of the message.
	ToUser string
	// The name of a channel to send to.
	Channel string
	Text    string
	// For incoming messages, true if the message is addressed to the bot.
	// This can either be through a DM channel or by starting with @botuser.
	ToBot bool
	// Attachment, if any
	Attachment *slack.Attachment
}
<|endoftext|>


<commit_before>package mouse

import (
	"crypto/tls"
	"fmt"
	"gopkg.in/sorcix/irc.v1"
	"net"
	"storage"
	"sync"
	"time"
)

type Mouse struct {
	Config  *Config
	Storage *storage.Store

	conn   net.Conn
	reader *irc.Decoder
	writer *irc.Encoder
	mutex  *sync.Mutex

	data     chan *irc.Message
	handlers []func(*Event)
}

func New(config Config) (*Mouse, error) {
	mouse := Mouse{
		Config: &config,
		data:   make(chan *irc.Message, 10),
		mutex:  &sync.Mutex{},
	}

	var err error
	mouse.Storage, err = storage.New(config.StorageDriver, config.Storage.DSN)

	return &mouse, err
}

func (mouse *Mouse) Connect() error {
	var err error
	server := fmt.Sprintf("%s:%d", mouse.Config.Host, mouse.Config.Port)

	if mouse.Config.TLS {
		mouse.conn, err = tls.Dial("tcp", server, mouse.Config.TLSConfig)
	} else {
		mouse.conn, err = net.Dial("tcp", server)
	}

	if err != nil {
		return err
	}

	// Create readers and writers from the connection
	mouse.reader = irc.NewDecoder(mouse.conn)
	mouse.writer = irc.NewEncoder(mouse.conn)

	// Write initial connect messages
	if mouse.Config.Pass != "" {
		if err = mouse.writer.Encode(&irc.Message{
			Command: irc.PASS,
			Params:  []string{mouse.Config.Pass},
		}); err != nil {
			return err
		}
	}

	if err = mouse.writer.Encode(&irc.Message{
		Command: irc.NICK,
		Params:  []string{mouse.Config.Nick},
	}); err != nil {
		return err
	}

	if err = mouse.writer.Encode(&irc.Message{
		Command: irc.USER,
		Params:  []string{mouse.Config.User, "0", "*", mouse.Config.Name},
	}); err != nil {
		return err
	}

	go mouse.loop()

	return err
}

func (mouse *Mouse) loop() {
	go mouse.handle()

	for {
		mouse.conn.SetDeadline(time.Now().Add(300 * time.Second))
		message, err := mouse.reader.Decode()
		if err != nil {
			break
		}

		mouse.data <- message
	}

	if mouse.Config.Reconnect {
		mouse.Connect()
	}
}

func (mouse *Mouse) handle() {
	for {
		// Receive the data
		message := <-mouse.data

		// If the command is a PING from the server, we need to respond ASAP.
		// We're responding in a goroutine so we can also pass the event on to
		// all of the event handlers that might rely on a PING event.
		if message.Command == irc.PING {
			go mouse.pong(message)
		}

		// Sometimes there is no channel, and when that happens it means it's a
		// message from the server. We set it to our current nick so we know.
		channel := mouse.Config.Nick
		if len(message.Params) > 0 {
			channel = message.Params[0]
		}

		// During some events (like "PING") Prefix is not set, which causes a
		// problem when we try to access it. We set it here so we don't panic.
		if message.Prefix == nil {
			message.Prefix = &irc.Prefix{}
		}

		event := &Event{
			Channel: channel,
			Command: message.Command,
			Host:    message.Prefix.Host,
			Message: message.Trailing,
			Nick:    message.Prefix.Name,
			User:    message.Prefix.User,
		}

		go func(event *Event) {
			mouse.mutex.Lock()
			defer mouse.mutex.Unlock()

			for _, handler := range mouse.handlers {
				handler(event)
			}

		}(event)
	}
}

func (mouse *Mouse) pong(message *irc.Message) {
	mouse.writer.Encode(&irc.Message{
		Command: irc.PONG,
		Params:  []string{message.Trailing},
	})
}

func (mouse *Mouse) Use(handler func(*Event)) {
	mouse.handlers = append(mouse.handlers, handler)
}

func (mouse *Mouse) Join(channel string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.JOIN,
		Params:  []string{channel},
	})
}

func (mouse *Mouse) Part(channel string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.PART,
		Params:  []string{channel},
	})
}

func (mouse *Mouse) Say(channel, message string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.PRIVMSG,
		Params:   []string{channel},
		Trailing: message,
	})
}

func (mouse *Mouse) Op(channel, nick string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "+o"},
		Trailing: nick,
	})
}

func (mouse *Mouse) Deop(channel, nick string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "-o"},
		Trailing: nick,
	})
}

func (mouse *Mouse) Kick(channel, user, reason string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.KICK,
		Params:   []string{user},
		Trailing: reason,
	})
}

func (mouse *Mouse) Ban(channel, user, reason string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "+b", user},
		Trailing: reason,
	})
}

func (mouse *Mouse) Unban(channel, user string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.MODE,
		Params:  []string{channel, "-b", user},
	})
}
<commit_msg>Fix problem with kick<commit_after>package mouse

import (
	"crypto/tls"
	"fmt"
	"gopkg.in/sorcix/irc.v1"
	"net"
	"storage"
	"sync"
	"time"
)

type Mouse struct {
	Config  *Config
	Storage *storage.Store

	conn   net.Conn
	reader *irc.Decoder
	writer *irc.Encoder
	mutex  *sync.Mutex

	data     chan *irc.Message
	handlers []func(*Event)
}

func New(config Config) (*Mouse, error) {
	mouse := Mouse{
		Config: &config,
		data:   make(chan *irc.Message, 10),
		mutex:  &sync.Mutex{},
	}

	var err error
	mouse.Storage, err = storage.New(config.StorageDriver, config.Storage.DSN)

	return &mouse, err
}

func (mouse *Mouse) Connect() error {
	var err error
	server := fmt.Sprintf("%s:%d", mouse.Config.Host, mouse.Config.Port)

	if mouse.Config.TLS {
		mouse.conn, err = tls.Dial("tcp", server, mouse.Config.TLSConfig)
	} else {
		mouse.conn, err = net.Dial("tcp", server)
	}

	if err != nil {
		return err
	}

	// Create readers and writers from the connection
	mouse.reader = irc.NewDecoder(mouse.conn)
	mouse.writer = irc.NewEncoder(mouse.conn)

	// Write initial connect messages
	if mouse.Config.Pass != "" {
		if err = mouse.writer.Encode(&irc.Message{
			Command: irc.PASS,
			Params:  []string{mouse.Config.Pass},
		}); err != nil {
			return err
		}
	}

	if err = mouse.writer.Encode(&irc.Message{
		Command: irc.NICK,
		Params:  []string{mouse.Config.Nick},
	}); err != nil {
		return err
	}

	if err = mouse.writer.Encode(&irc.Message{
		Command: irc.USER,
		Params:  []string{mouse.Config.User, "0", "*", mouse.Config.Name},
	}); err != nil {
		return err
	}

	go mouse.loop()

	return err
}

func (mouse *Mouse) loop() {
	go mouse.handle()

	for {
		mouse.conn.SetDeadline(time.Now().Add(300 * time.Second))
		message, err := mouse.reader.Decode()
		if err != nil {
			break
		}

		mouse.data <- message
	}

	if mouse.Config.Reconnect {
		mouse.Connect()
	}
}

func (mouse *Mouse) handle() {
	for {
		// Receive the data
		message := <-mouse.data

		// If the command is a PING from the server, we need to respond ASAP.
		// We're responding in a goroutine so we can also pass the event on to
		// all of the event handlers that might rely on a PING event.
		if message.Command == irc.PING {
			go mouse.pong(message)
		}

		// Sometimes there is no channel, and when that happens it means it's a
		// message from the server. We set it to our current nick so we know.
		channel := mouse.Config.Nick
		if len(message.Params) > 0 {
			channel = message.Params[0]
		}

		// During some events (like "PING") Prefix is not set, which causes a
		// problem when we try to access it. We set it here so we don't panic.
		if message.Prefix == nil {
			message.Prefix = &irc.Prefix{}
		}

		event := &Event{
			Channel: channel,
			Command: message.Command,
			Host:    message.Prefix.Host,
			Message: message.Trailing,
			Nick:    message.Prefix.Name,
			User:    message.Prefix.User,
		}

		go func(event *Event) {
			mouse.mutex.Lock()
			defer mouse.mutex.Unlock()

			for _, handler := range mouse.handlers {
				handler(event)
			}

		}(event)
	}
}

func (mouse *Mouse) pong(message *irc.Message) {
	mouse.writer.Encode(&irc.Message{
		Command: irc.PONG,
		Params:  []string{message.Trailing},
	})
}

func (mouse *Mouse) Use(handler func(*Event)) {
	mouse.handlers = append(mouse.handlers, handler)
}

func (mouse *Mouse) Join(channel string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.JOIN,
		Params:  []string{channel},
	})
}

func (mouse *Mouse) Part(channel string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.PART,
		Params:  []string{channel},
	})
}

func (mouse *Mouse) Say(channel, message string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.PRIVMSG,
		Params:   []string{channel},
		Trailing: message,
	})
}

func (mouse *Mouse) Op(channel, nick string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "+o"},
		Trailing: nick,
	})
}

func (mouse *Mouse) Deop(channel, nick string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "-o"},
		Trailing: nick,
	})
}

func (mouse *Mouse) Kick(channel, user, reason string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.KICK,
		Params:   []string{channel, user},
		Trailing: reason,
	})
}

func (mouse *Mouse) Ban(channel, user, reason string) error {
	return mouse.writer.Encode(&irc.Message{
		Command:  irc.MODE,
		Params:   []string{channel, "+b", user},
		Trailing: reason,
	})
}

func (mouse *Mouse) Unban(channel, user string) error {
	return mouse.writer.Encode(&irc.Message{
		Command: irc.MODE,
		Params:  []string{channel, "-b", user},
	})
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package net

import (
	"context"
	"internal/poll"
	"os"
	"runtime"
	"sync/atomic"
	"syscall"
)

// Network file descriptor.
type netFD struct {
	pfd poll.FD

	// immutable until Close
	family      int
	sotype      int
	isConnected bool
	net         string
	laddr       Addr
	raddr       Addr
}

func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
	ret := &netFD{
		pfd: poll.FD{
			Sysfd:         sysfd,
			IsStream:      sotype == syscall.SOCK_STREAM,
			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
		},
		family: family,
		sotype: sotype,
		net:    net,
	}
	return ret, nil
}

func (fd *netFD) init() error {
	return fd.pfd.Init(fd.net, true)
}

func (fd *netFD) setAddr(laddr, raddr Addr) {
	fd.laddr = laddr
	fd.raddr = raddr
	runtime.SetFinalizer(fd, (*netFD).Close)
}

func (fd *netFD) name() string {
	var ls, rs string
	if fd.laddr != nil {
		ls = fd.laddr.String()
	}
	if fd.raddr != nil {
		rs = fd.raddr.String()
	}
	return fd.net + ":" + ls + "->" + rs
}

func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
	// Do not need to call fd.writeLock here,
	// because fd is not yet accessible to user,
	// so no concurrent operations are possible.
	switch err := connectFunc(fd.pfd.Sysfd, ra); err {
	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
	case nil, syscall.EISCONN:
		select {
		case <-ctx.Done():
			return nil, mapErr(ctx.Err())
		default:
		}
		if err := fd.pfd.Init(fd.net, true); err != nil {
			return nil, err
		}
		runtime.KeepAlive(fd)
		return nil, nil
	case syscall.EINVAL:
		// On Solaris we can see EINVAL if the socket has
		// already been accepted and closed by the server.
		// Treat this as a successful connection--writes to
		// the socket will see EOF.  For details and a test
		// case in C see https://golang.org/issue/6828.
		if runtime.GOOS == "solaris" {
			return nil, nil
		}
		fallthrough
	default:
		return nil, os.NewSyscallError("connect", err)
	}
	if err := fd.pfd.Init(fd.net, true); err != nil {
		return nil, err
	}
	if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
		fd.pfd.SetWriteDeadline(deadline)
		defer fd.pfd.SetWriteDeadline(noDeadline)
	}

	// Start the "interrupter" goroutine, if this context might be canceled.
	// (The background context cannot)
	//
	// The interrupter goroutine waits for the context to be done and
	// interrupts the dial (by altering the fd's write deadline, which
	// wakes up waitWrite).
	if ctx != context.Background() {
		// Wait for the interrupter goroutine to exit before returning
		// from connect.
		done := make(chan struct{})
		interruptRes := make(chan error)
		defer func() {
			close(done)
			if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
				// The interrupter goroutine called SetWriteDeadline,
				// but the connect code below had returned from
				// waitWrite already and did a successful connect (ret
				// == nil). Because we've now poisoned the connection
				// by making it unwritable, don't return a successful
				// dial. This was issue 16523.
				ret = ctxErr
				fd.Close() // prevent a leak
			}
		}()
		go func() {
			select {
			case <-ctx.Done():
				// Force the runtime's poller to immediately give up
				// waiting for writability, unblocking waitWrite
				// below.
				fd.pfd.SetWriteDeadline(aLongTimeAgo)
				testHookCanceledDial()
				interruptRes <- ctx.Err()
			case <-done:
				interruptRes <- nil
			}
		}()
	}

	for {
		// Performing multiple connect system calls on a
		// non-blocking socket under Unix variants does not
		// necessarily result in earlier errors being
		// returned. Instead, once runtime-integrated network
		// poller tells us that the socket is ready, get the
		// SO_ERROR socket option to see if the connection
		// succeeded or failed. See issue 7474 for further
		// details.
		if err := fd.pfd.WaitWrite(); err != nil {
			select {
			case <-ctx.Done():
				return nil, mapErr(ctx.Err())
			default:
			}
			return nil, err
		}
		nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
		if err != nil {
			return nil, os.NewSyscallError("getsockopt", err)
		}
		switch err := syscall.Errno(nerr); err {
		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
		case syscall.EISCONN:
			return nil, nil
		case syscall.Errno(0):
			// The runtime poller can wake us up spuriously;
			// see issues 14548 and 19289. Check that we are
			// really connected; if not, wait again.
			if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
				return rsa, nil
			}
		default:
			return nil, os.NewSyscallError("getsockopt", err)
		}
		runtime.KeepAlive(fd)
	}
}

func (fd *netFD) Close() error {
	runtime.SetFinalizer(fd, nil)
	return fd.pfd.Close()
}

func (fd *netFD) shutdown(how int) error {
	err := fd.pfd.Shutdown(how)
	runtime.KeepAlive(fd)
	return wrapSyscallError("shutdown", err)
}

func (fd *netFD) closeRead() error {
	return fd.shutdown(syscall.SHUT_RD)
}

func (fd *netFD) closeWrite() error {
	return fd.shutdown(syscall.SHUT_WR)
}

func (fd *netFD) Read(p []byte) (n int, err error) {
	n, err = fd.pfd.Read(p)
	runtime.KeepAlive(fd)
	return n, wrapSyscallError("read", err)
}

func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
	n, sa, err = fd.pfd.ReadFrom(p)
	runtime.KeepAlive(fd)
	return n, sa, wrapSyscallError("recvfrom", err)
}

func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
	n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
	runtime.KeepAlive(fd)
	return n, oobn, flags, sa, wrapSyscallError("recvmsg", err)
}

func (fd *netFD) Write(p []byte) (nn int, err error) {
	nn, err = fd.pfd.Write(p)
	runtime.KeepAlive(fd)
	return nn, wrapSyscallError("write", err)
}

func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
	n, err = fd.pfd.WriteTo(p, sa)
	runtime.KeepAlive(fd)
	return n, wrapSyscallError("sendto", err)
}

func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
	n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
	runtime.KeepAlive(fd)
	return n, oobn, wrapSyscallError("sendmsg", err)
}

func (fd *netFD) accept() (netfd *netFD, err error) {
	d, rsa, errcall, err := fd.pfd.Accept()
	if err != nil {
		if errcall != "" {
			err = wrapSyscallError(errcall, err)
		}
		return nil, err
	}

	if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
		poll.CloseFunc(d)
		return nil, err
	}
	if err = netfd.init(); err != nil {
		fd.Close()
		return nil, err
	}
	lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
	netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
	return netfd, nil
}

// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
// If the kernel doesn't support it, this is set to 0.
var tryDupCloexec = int32(1)

func dupCloseOnExec(fd int) (newfd int, err error) {
	if atomic.LoadInt32(&tryDupCloexec) == 1 {
		r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
		if runtime.GOOS == "darwin" && e1 == syscall.EBADF {
			// On OS X 10.6 and below (but we only support
			// >= 10.6), F_DUPFD_CLOEXEC is unsupported
			// and fcntl there falls back (undocumented)
			// to doing an ioctl instead, returning EBADF
			// in this case because fd is not of the
			// expected device fd type. Treat it as
			// EINVAL instead, so we fall back to the
			// normal dup path.
			// TODO: only do this on 10.6 if we can detect 10.6
			// cheaply.
			e1 = syscall.EINVAL
		}
		switch e1 {
		case 0:
			return int(r0), nil
		case syscall.EINVAL:
			// Old kernel. Fall back to the portable way
			// from now on.
			atomic.StoreInt32(&tryDupCloexec, 0)
		default:
			return -1, os.NewSyscallError("fcntl", e1)
		}
	}
	return dupCloseOnExecOld(fd)
}

// dupCloseOnExecUnixOld is the traditional way to dup an fd and
// set its O_CLOEXEC bit, using two system calls.
func dupCloseOnExecOld(fd int) (newfd int, err error) {
	syscall.ForkLock.RLock()
	defer syscall.ForkLock.RUnlock()
	newfd, err = syscall.Dup(fd)
	if err != nil {
		return -1, os.NewSyscallError("dup", err)
	}
	syscall.CloseOnExec(newfd)
	return
}

func (fd *netFD) dup() (f *os.File, err error) {
	ns, err := dupCloseOnExec(fd.pfd.Sysfd)
	if err != nil {
		return nil, err
	}

	// We want blocking mode for the new fd, hence the double negative.
	// This also puts the old fd into blocking mode, meaning that
	// I/O will block the thread instead of letting us use the epoll server.
	// Everything will still work, just with more threads.
	if err = fd.pfd.SetBlocking(); err != nil {
		return nil, os.NewSyscallError("setnonblock", err)
	}

	return os.NewFile(uintptr(ns), fd.name()), nil
}
<commit_msg>net: report connect error as coming from "connect"<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package net

import (
	"context"
	"internal/poll"
	"os"
	"runtime"
	"sync/atomic"
	"syscall"
)

// Network file descriptor.
type netFD struct {
	pfd poll.FD

	// immutable until Close
	family      int
	sotype      int
	isConnected bool
	net         string
	laddr       Addr
	raddr       Addr
}

func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
	ret := &netFD{
		pfd: poll.FD{
			Sysfd:         sysfd,
			IsStream:      sotype == syscall.SOCK_STREAM,
			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
		},
		family: family,
		sotype: sotype,
		net:    net,
	}
	return ret, nil
}

func (fd *netFD) init() error {
	return fd.pfd.Init(fd.net, true)
}

func (fd *netFD) setAddr(laddr, raddr Addr) {
	fd.laddr = laddr
	fd.raddr = raddr
	runtime.SetFinalizer(fd, (*netFD).Close)
}

func (fd *netFD) name() string {
	var ls, rs string
	if fd.laddr != nil {
		ls = fd.laddr.String()
	}
	if fd.raddr != nil {
		rs = fd.raddr.String()
	}
	return fd.net + ":" + ls + "->" + rs
}

func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
	// Do not need to call fd.writeLock here,
	// because fd is not yet accessible to user,
	// so no concurrent operations are possible.
	switch err := connectFunc(fd.pfd.Sysfd, ra); err {
	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
	case nil, syscall.EISCONN:
		select {
		case <-ctx.Done():
			return nil, mapErr(ctx.Err())
		default:
		}
		if err := fd.pfd.Init(fd.net, true); err != nil {
			return nil, err
		}
		runtime.KeepAlive(fd)
		return nil, nil
	case syscall.EINVAL:
		// On Solaris we can see EINVAL if the socket has
		// already been accepted and closed by the server.
		// Treat this as a successful connection--writes to
		// the socket will see EOF.  For details and a test
		// case in C see https://golang.org/issue/6828.
		if runtime.GOOS == "solaris" {
			return nil, nil
		}
		fallthrough
	default:
		return nil, os.NewSyscallError("connect", err)
	}
	if err := fd.pfd.Init(fd.net, true); err != nil {
		return nil, err
	}
	if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
		fd.pfd.SetWriteDeadline(deadline)
		defer fd.pfd.SetWriteDeadline(noDeadline)
	}

	// Start the "interrupter" goroutine, if this context might be canceled.
	// (The background context cannot)
	//
	// The interrupter goroutine waits for the context to be done and
	// interrupts the dial (by altering the fd's write deadline, which
	// wakes up waitWrite).
	if ctx != context.Background() {
		// Wait for the interrupter goroutine to exit before returning
		// from connect.
		done := make(chan struct{})
		interruptRes := make(chan error)
		defer func() {
			close(done)
			if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
				// The interrupter goroutine called SetWriteDeadline,
				// but the connect code below had returned from
				// waitWrite already and did a successful connect (ret
				// == nil). Because we've now poisoned the connection
				// by making it unwritable, don't return a successful
				// dial. This was issue 16523.
				ret = ctxErr
				fd.Close() // prevent a leak
			}
		}()
		go func() {
			select {
			case <-ctx.Done():
				// Force the runtime's poller to immediately give up
				// waiting for writability, unblocking waitWrite
				// below.
				fd.pfd.SetWriteDeadline(aLongTimeAgo)
				testHookCanceledDial()
				interruptRes <- ctx.Err()
			case <-done:
				interruptRes <- nil
			}
		}()
	}

	for {
		// Performing multiple connect system calls on a
		// non-blocking socket under Unix variants does not
		// necessarily result in earlier errors being
		// returned. Instead, once runtime-integrated network
		// poller tells us that the socket is ready, get the
		// SO_ERROR socket option to see if the connection
		// succeeded or failed. See issue 7474 for further
		// details.
		if err := fd.pfd.WaitWrite(); err != nil {
			select {
			case <-ctx.Done():
				return nil, mapErr(ctx.Err())
			default:
			}
			return nil, err
		}
		nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
		if err != nil {
			return nil, os.NewSyscallError("getsockopt", err)
		}
		switch err := syscall.Errno(nerr); err {
		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
		case syscall.EISCONN:
			return nil, nil
		case syscall.Errno(0):
			// The runtime poller can wake us up spuriously;
			// see issues 14548 and 19289. Check that we are
			// really connected; if not, wait again.
			if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
				return rsa, nil
			}
		default:
			return nil, os.NewSyscallError("connect", err)
		}
		runtime.KeepAlive(fd)
	}
}

func (fd *netFD) Close() error {
	runtime.SetFinalizer(fd, nil)
	return fd.pfd.Close()
}

func (fd *netFD) shutdown(how int) error {
	err := fd.pfd.Shutdown(how)
	runtime.KeepAlive(fd)
	return wrapSyscallError("shutdown", err)
}

func (fd *netFD) closeRead() error {
	return fd.shutdown(syscall.SHUT_RD)
}

func (fd *netFD) closeWrite() error {
	return fd.shutdown(syscall.SHUT_WR)
}

func (fd *netFD) Read(p []byte) (n int, err error) {
	n, err = fd.pfd.Read(p)
	runtime.KeepAlive(fd)
	return n, wrapSyscallError("read", err)
}

func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
	n, sa, err = fd.pfd.ReadFrom(p)
	runtime.KeepAlive(fd)
	return n, sa, wrapSyscallError("recvfrom", err)
}

func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
	n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
	runtime.KeepAlive(fd)
	return n, oobn, flags, sa, wrapSyscallError("recvmsg", err)
}

func (fd *netFD) Write(p []byte) (nn int, err error) {
	nn, err = fd.pfd.Write(p)
	runtime.KeepAlive(fd)
	return nn, wrapSyscallError("write", err)
}

func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
	n, err = fd.pfd.WriteTo(p, sa)
	runtime.KeepAlive(fd)
	return n, wrapSyscallError("sendto", err)
}

func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
	n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
	runtime.KeepAlive(fd)
	return n, oobn, wrapSyscallError("sendmsg", err)
}

func (fd *netFD) accept() (netfd *netFD, err error) {
	d, rsa, errcall, err := fd.pfd.Accept()
	if err != nil {
		if errcall != "" {
			err = wrapSyscallError(errcall, err)
		}
		return nil, err
	}

	if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
		poll.CloseFunc(d)
		return nil, err
	}
	if err = netfd.init(); err != nil {
		fd.Close()
		return nil, err
	}
	lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
	netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
	return netfd, nil
}

// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
// If the kernel doesn't support it, this is set to 0.
var tryDupCloexec = int32(1)

func dupCloseOnExec(fd int) (newfd int, err error) {
	if atomic.LoadInt32(&tryDupCloexec) == 1 {
		r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
		if runtime.GOOS == "darwin" && e1 == syscall.EBADF {
			// On OS X 10.6 and below (but we only support
			// >= 10.6), F_DUPFD_CLOEXEC is unsupported
			// and fcntl there falls back (undocumented)
			// to doing an ioctl instead, returning EBADF
			// in this case because fd is not of the
			// expected device fd type. Treat it as
			// EINVAL instead, so we fall back to the
			// normal dup path.
			// TODO: only do this on 10.6 if we can detect 10.6
			// cheaply.
			e1 = syscall.EINVAL
		}
		switch e1 {
		case 0:
			return int(r0), nil
		case syscall.EINVAL:
			// Old kernel. Fall back to the portable way
			// from now on.
			atomic.StoreInt32(&tryDupCloexec, 0)
		default:
			return -1, os.NewSyscallError("fcntl", e1)
		}
	}
	return dupCloseOnExecOld(fd)
}

// dupCloseOnExecUnixOld is the traditional way to dup an fd and
// set its O_CLOEXEC bit, using two system calls.
func dupCloseOnExecOld(fd int) (newfd int, err error) {
	syscall.ForkLock.RLock()
	defer syscall.ForkLock.RUnlock()
	newfd, err = syscall.Dup(fd)
	if err != nil {
		return -1, os.NewSyscallError("dup", err)
	}
	syscall.CloseOnExec(newfd)
	return
}

func (fd *netFD) dup() (f *os.File, err error) {
	ns, err := dupCloseOnExec(fd.pfd.Sysfd)
	if err != nil {
		return nil, err
	}

	// We want blocking mode for the new fd, hence the double negative.
	// This also puts the old fd into blocking mode, meaning that
	// I/O will block the thread instead of letting us use the epoll server.
	// Everything will still work, just with more threads.
	if err = fd.pfd.SetBlocking(); err != nil {
		return nil, os.NewSyscallError("setnonblock", err)
	}

	return os.NewFile(uintptr(ns), fd.name()), nil
}
<|endoftext|>


<commit_before>// +build db

// Package postgres_test includes tests which only run when using the build tag
// db (go test -tags=db) which is a good way to do integration testing as
// proposed by Bourgon (2014):
// http://peter.bourgon.org/go-in-production/#testing-and-validation
package postgres_test

import (
	"flag"
	"fmt"
	"testing"

	"github.com/psimika/secure-web-app/petfind"
	"github.com/psimika/secure-web-app/petfind/postgres"
)

var (
	user   = flag.String("user", "psimika", "username to use to run tests on Postgres")
	pass   = flag.String("pass", "", "password to use to run tests on Postgres")
	host   = flag.String("host", "localhost", "host for connecting to Postgres and run the tests")
	port   = flag.String("port", "5432", "port for connecting to Postgres and run the tests")
	dbname = flag.String("dbname", "petfind_test", "test database, tables will be created and dropped on each test")
)

func init() {
	flag.Parse()
}

// To include the test coverage of the db tests:
//
// go test -tags=db -pass '' -coverprofile=cover.out -covermode=count
//
// go tool cover -html=cover.out
//
// (Pike 2013) https://blog.golang.org/cover

func setup(t *testing.T) petfind.Store {
	if *pass == "" {
		t.Errorf("No password provided for user %q to connect to Postgres and run the tests.", *user)
		t.Errorf("These tests need a Postgres account %q that has access to test database %q.", *user, *dbname)
		t.Fatal("Use: go test -tags=db -pass '<db password>'")
	}
	datasource := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s", *user, *pass, *host, *port, *dbname)
	s, err := postgres.NewStore(datasource)
	if err != nil {
		t.Fatalf("NewStore failed for datasource %q: %v", datasource, err)
	}
	return s
}

func teardown(t *testing.T, s petfind.Store) {
	if err := s.DropSchema(); err != nil {
		t.Error(err)
	}
}
<commit_msg>Import db driver in tests and change db username<commit_after>// +build db

// Package postgres_test includes tests which only run when using the build tag
// db (go test -tags=db) which is a good way to do integration testing as
// proposed by Bourgon (2014):
// http://peter.bourgon.org/go-in-production/#testing-and-validation
package postgres_test

import (
	"flag"
	"fmt"
	"testing"

	_ "github.com/lib/pq"

	"github.com/psimika/secure-web-app/petfind"
	"github.com/psimika/secure-web-app/petfind/postgres"
)

var (
	user   = flag.String("user", "petfind", "username to use to run tests on Postgres")
	pass   = flag.String("pass", "", "password to use to run tests on Postgres")
	host   = flag.String("host", "localhost", "host for connecting to Postgres and run the tests")
	port   = flag.String("port", "5432", "port for connecting to Postgres and run the tests")
	dbname = flag.String("dbname", "petfind_test", "test database, tables will be created and dropped on each test")
)

func init() {
	flag.Parse()
}

// To include the test coverage of the db tests:
//
// go test -tags=db -pass '' -coverprofile=cover.out -covermode=count
//
// go tool cover -html=cover.out
//
// (Pike 2013) https://blog.golang.org/cover

func setup(t *testing.T) petfind.Store {
	if *pass == "" {
		t.Errorf("No password provided for user %q to connect to Postgres and run the tests.", *user)
		t.Errorf("These tests need a Postgres account %q that has access to test database %q.", *user, *dbname)
		t.Fatal("Use: go test -tags=db -pass '<db password>'")
	}
	datasource := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s", *user, *pass, *host, *port, *dbname)
	s, err := postgres.NewStore(datasource)
	if err != nil {
		t.Fatalf("NewStore failed for datasource %q: %v", datasource, err)
	}
	return s
}

func teardown(t *testing.T, s petfind.Store) {
	if err := s.DropSchema(); err != nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	def "definitions"
	hw "hardware"
)

func EventHandler(){
	//Check for all events in loop
	//Make convinient variables
	//Fix lights

	var BtnChan = make(chan def.BtnPress, 10)

	for{
	}
}

func eventBtnPressed(){
	//Check for a button beeing pressed
	lastBtnPresse := def.BtnPress{
				Button: btn,
				Floor: floor,
	}
	var BtnPressed:=-2

	for floor := 0; floor < def.NumFloors; floor++ {
		for btn := 0; btn < def.NumButtons; btn++ {
			if hw.ReadBtn(floor, btn){

			}
		}
	}
}<commit_msg>eventBtnPressed done<commit_after>package main

import (
	def "definitions"
	hw "hardware"
)

func EventHandler(){
	//Check for all events in loop
	//Make convinient variables
	//Fix lights

	//Convenient channels
	var BtnChan = make(chan def.BtnPress, 10)

	//Convenient variables/structs

	//Threads
	go eventBtnPressed(BtnChan)

	for{
		select{
			case
		}
	}
}

func eventBtnPressed(ch chan){
	//Check for a button beeing pressed
	lastBtnPressed := def.BtnPress{
		Button: -1,
		Floor: -1,
	}
	btnPressed := def.BtnPress{
		Button: -2,
		Floor: -2,
	}
	for{
		for floor := 0; floor < def.NumFloors; floor++ {
			for btn := 0; btn < def.NumButtons; btn++ {
				if hw.ReadBtn(floor, btn){
					btnPressed.Button = btn
					btnPressed.Floor = floor
					//Check if there is an order assigned to button
					if lastBtnPressed != btnPressed && !qMatrix.Active{
						ch <- btnPressed
					}
				}
			}
		}
		lastBtnPressed = btnPressed
	}
}<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 main

import (
	"fmt"
	"io/ioutil"
	"strings"

	"istio.io/pilot/model"

	"github.com/golang/glog"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ingress struct {
	*infra
	logs *accessLogs
}

const (
	ingressServiceName = "istio-ingress"
)

func (t *ingress) String() string {
	return "ingress"
}

func (t *ingress) setup() error {
	if !t.Ingress {
		return nil
	}
	t.logs = makeAccessLogs()

	// send secrets
	key, err := ioutil.ReadFile("test/integration/testdata/cert.key")
	if err != nil {
		return err
	}
	crt, err := ioutil.ReadFile("test/integration/testdata/cert.crt")
	if err != nil {
		return err
	}
	_, err = client.CoreV1().Secrets(t.Namespace).Create(&v1.Secret{
		ObjectMeta: metav1.ObjectMeta{Name: "ingress"},
		Data: map[string][]byte{
			"tls.key": key,
			"tls.crt": crt,
		},
	})
	if err != nil {
		return err
	}

	// parse and send yamls
	yamlFile, err := ioutil.ReadFile("test/integration/testdata/ingress.yaml")
	if err != nil {
		return err
	}
	if err = t.kubeApply(string(yamlFile)); err != nil {
		return err
	}

	// send route rules for "c" only
	if err = t.applyConfig("rule-default-route.yaml.tmpl", map[string]string{
		"Destination": "c",
		"Namespace":   t.Namespace,
	}, model.RouteRule); err != nil {
		return err
	}

	return nil
}

func (t *ingress) run() error {
	if !t.Ingress {
		glog.Info("skipping test since ingress is missing")
		return nil
	}

	funcs := make(map[string]func() status)
	funcs["Ingress status IP"] = t.checkIngressStatus
	funcs["Route rule for /c"] = t.checkRouteRule

	cases := []struct {
		// empty destination to expect 404
		dst  string
		url  string
		host string
	}{
		{"a", fmt.Sprintf("https://%s:443", ingressServiceName), ""},
		{"b", fmt.Sprintf("https://%s:443/pasta", ingressServiceName), ""},
		{"a", fmt.Sprintf("http://%s/lucky", ingressServiceName), ""},
		{"b", fmt.Sprintf("http://%s/lol", ingressServiceName), ""},
		{"a", fmt.Sprintf("http://%s/foo", ingressServiceName), "foo.bar.com"},
		{"a", fmt.Sprintf("http://%s/bar", ingressServiceName), "foo.baz.com"},
		{"a", fmt.Sprintf("grpc://%s:80", ingressServiceName), "api.company.com"},
		{"", fmt.Sprintf("https://%s:443/notfound", ingressServiceName), ""},
		{"", fmt.Sprintf("http://%s/notfound", ingressServiceName), ""},
		{"", fmt.Sprintf("http://%s/foo", ingressServiceName), ""},
	}
	for _, req := range cases {
		name := fmt.Sprintf("Ingress request to %+v", req)
		funcs[name] = (func(dst, url, host string) func() status {
			extra := ""
			if host != "" {
				extra = "-key Host -val " + host
			}
			return func() status {
				resp := t.clientRequest("t", url, 1, extra)
				if dst == "" {
					if len(resp.code) > 0 && resp.code[0] == "404" {
						return nil
					}
				} else if len(resp.id) > 0 {
					if !strings.Contains(resp.body, "X-Forwarded-For") &&
						!strings.Contains(resp.body, "x-forwarded-for") {
						glog.Warningf("Missing X-Forwarded-For in the body: %s", resp.body)
						return errAgain
					}

					id := resp.id[0]
					t.logs.add(dst, id, name)
					t.logs.add("ingress", id, name)
					return nil
				}
				return errAgain
			}
		})(req.dst, req.url, req.host)
	}

	if err := parallel(funcs); err != nil {
		return err
	}
	if err := t.logs.check(t.infra); err != nil {
		return err
	}
	return nil
}

// checkRouteRule verifies that version splitting is applied to ingress paths
func (t *ingress) checkRouteRule() status {
	url := fmt.Sprintf("http://%s/c", ingressServiceName)
	resp := t.clientRequest("t", url, 100, "")
	count := counts(resp.version)
	glog.V(2).Infof("counts: %v", count)
	if count["v1"] >= 95 {
		return nil
	}
	return errAgain
}

// ensure that IPs/hostnames are in the ingress statuses
func (t *ingress) checkIngressStatus() status {
	ings, err := client.Extensions().Ingresses(t.Namespace).List(metav1.ListOptions{})
	if err != nil {
		return err
	}
	if len(ings.Items) == 0 {
		return fmt.Errorf("ingress status failure: no ingress")
	}
	for _, ing := range ings.Items {
		if len(ing.Status.LoadBalancer.Ingress) == 0 {
			return errAgain
		}

		for _, status := range ing.Status.LoadBalancer.Ingress {
			if status.IP == "" && status.Hostname == "" {
				return errAgain
			}
			glog.Infof("Ingress Status IP: %s", status.IP)
		}
	}
	return nil
}

func (t *ingress) teardown() {
	if !t.Ingress {
		return
	}
	if err := client.Extensions().Ingresses(t.Namespace).
		DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}); err != nil {
		glog.Warning(err)
	}
	if err := t.deleteAllConfigs(); err != nil {
		glog.Warning(err)
	}
}
<commit_msg>fix postsubmit (#995)<commit_after>// Copyright 2017 Istio 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 main

import (
	"fmt"
	"io/ioutil"
	"strings"

	"istio.io/pilot/model"

	"github.com/golang/glog"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ingress struct {
	*infra
	logs *accessLogs
}

const (
	ingressServiceName = "istio-ingress"
	ingressSecretName  = "ingress"
)

func (t *ingress) String() string {
	return "ingress"
}

func (t *ingress) setup() error {
	if !t.Ingress {
		return nil
	}
	t.logs = makeAccessLogs()

	// send secrets
	key, err := ioutil.ReadFile("test/integration/testdata/cert.key")
	if err != nil {
		return err
	}
	crt, err := ioutil.ReadFile("test/integration/testdata/cert.crt")
	if err != nil {
		return err
	}
	_, err = client.CoreV1().Secrets(t.Namespace).Create(&v1.Secret{
		ObjectMeta: metav1.ObjectMeta{Name: ingressSecretName},
		Data: map[string][]byte{
			"tls.key": key,
			"tls.crt": crt,
		},
	})
	if err != nil {
		return err
	}

	// parse and send yamls
	yamlFile, err := ioutil.ReadFile("test/integration/testdata/ingress.yaml")
	if err != nil {
		return err
	}
	if err = t.kubeApply(string(yamlFile)); err != nil {
		return err
	}

	// send route rules for "c" only
	if err = t.applyConfig("rule-default-route.yaml.tmpl", map[string]string{
		"Destination": "c",
		"Namespace":   t.Namespace,
	}, model.RouteRule); err != nil {
		return err
	}

	return nil
}

func (t *ingress) run() error {
	if !t.Ingress {
		glog.Info("skipping test since ingress is missing")
		return nil
	}

	funcs := make(map[string]func() status)
	funcs["Ingress status IP"] = t.checkIngressStatus
	funcs["Route rule for /c"] = t.checkRouteRule

	cases := []struct {
		// empty destination to expect 404
		dst  string
		url  string
		host string
	}{
		{"a", fmt.Sprintf("https://%s:443", ingressServiceName), ""},
		{"b", fmt.Sprintf("https://%s:443/pasta", ingressServiceName), ""},
		{"a", fmt.Sprintf("http://%s/lucky", ingressServiceName), ""},
		{"b", fmt.Sprintf("http://%s/lol", ingressServiceName), ""},
		{"a", fmt.Sprintf("http://%s/foo", ingressServiceName), "foo.bar.com"},
		{"a", fmt.Sprintf("http://%s/bar", ingressServiceName), "foo.baz.com"},
		{"a", fmt.Sprintf("grpc://%s:80", ingressServiceName), "api.company.com"},
		{"", fmt.Sprintf("https://%s:443/notfound", ingressServiceName), ""},
		{"", fmt.Sprintf("http://%s/notfound", ingressServiceName), ""},
		{"", fmt.Sprintf("http://%s/foo", ingressServiceName), ""},
	}
	for _, req := range cases {
		name := fmt.Sprintf("Ingress request to %+v", req)
		funcs[name] = (func(dst, url, host string) func() status {
			extra := ""
			if host != "" {
				extra = "-key Host -val " + host
			}
			return func() status {
				resp := t.clientRequest("t", url, 1, extra)
				if dst == "" {
					if len(resp.code) > 0 && resp.code[0] == "404" {
						return nil
					}
				} else if len(resp.id) > 0 {
					if !strings.Contains(resp.body, "X-Forwarded-For") &&
						!strings.Contains(resp.body, "x-forwarded-for") {
						glog.Warningf("Missing X-Forwarded-For in the body: %s", resp.body)
						return errAgain
					}

					id := resp.id[0]
					t.logs.add(dst, id, name)
					t.logs.add("ingress", id, name)
					return nil
				}
				return errAgain
			}
		})(req.dst, req.url, req.host)
	}

	if err := parallel(funcs); err != nil {
		return err
	}
	if err := t.logs.check(t.infra); err != nil {
		return err
	}
	return nil
}

// checkRouteRule verifies that version splitting is applied to ingress paths
func (t *ingress) checkRouteRule() status {
	url := fmt.Sprintf("http://%s/c", ingressServiceName)
	resp := t.clientRequest("t", url, 100, "")
	count := counts(resp.version)
	glog.V(2).Infof("counts: %v", count)
	if count["v1"] >= 95 {
		return nil
	}
	return errAgain
}

// ensure that IPs/hostnames are in the ingress statuses
func (t *ingress) checkIngressStatus() status {
	ings, err := client.Extensions().Ingresses(t.Namespace).List(metav1.ListOptions{})
	if err != nil {
		return err
	}
	if len(ings.Items) == 0 {
		return fmt.Errorf("ingress status failure: no ingress")
	}
	for _, ing := range ings.Items {
		if len(ing.Status.LoadBalancer.Ingress) == 0 {
			return errAgain
		}

		for _, status := range ing.Status.LoadBalancer.Ingress {
			if status.IP == "" && status.Hostname == "" {
				return errAgain
			}
			glog.Infof("Ingress Status IP: %s", status.IP)
		}
	}
	return nil
}

func (t *ingress) teardown() {
	if !t.Ingress {
		return
	}
	if err := client.Extensions().Ingresses(t.Namespace).
		DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}); err != nil {
		glog.Warning(err)
	}
	if err := client.CoreV1().Secrets(t.Namespace).
		Delete(ingressSecretName, &metav1.DeleteOptions{}); err != nil {
		glog.Warning(err)
	}
	if err := t.deleteAllConfigs(); err != nil {
		glog.Warning(err)
	}
}
<|endoftext|>


<commit_before>package protoadaptor

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/ethereum/go-ethereum/log"
	router "github.com/fractalplatform/fractal/event"
	"github.com/fractalplatform/fractal/p2p"
	"github.com/fractalplatform/fractal/utils/rlp"
)

type pack struct {
	From     string
	To       string
	Typecode uint32
	Payload  []byte
}

type remotePeer struct {
	peer *p2p.Peer
	ws   p2p.MsgReadWriter
}

// ProtoAdaptor is subprotocol on p2p
type ProtoAdaptor struct {
	p2p.Server
	peerMangaer
	event   chan *router.Event
	station router.Station
}

// NewProtoAdaptor return new ProtoAdaptor
func NewProtoAdaptor(config *p2p.Config) *ProtoAdaptor {
	adaptor := &ProtoAdaptor{
		Server: p2p.Server{
			Config: config,
		},
		peerMangaer: peerMangaer{
			activePeers: make(map[[8]byte]*remotePeer),
			station:     nil,
		},
		event:   make(chan *router.Event),
		station: router.NewLocalStation("p2p", nil),
	}
	adaptor.peerMangaer.station = router.NewBroadcastStation("broadcast", &adaptor.peerMangaer)
	adaptor.Server.Config.Protocols = adaptor.Protocols()
	return adaptor
}

// Start start p2p protocol adaptor
func (adaptor *ProtoAdaptor) Start() error {
	router.StationRegister(adaptor.peerMangaer.station)
	router.AdaptorRegister(adaptor)
	router.Subscribe(nil, adaptor.event, router.DisconectCtrl, nil)
	go adaptor.adaptorEvent()
	return adaptor.Server.Start()
}

func (adaptor *ProtoAdaptor) adaptorEvent() {
	for {
		e := <-adaptor.event
		switch e.Typecode {
		case router.DisconectCtrl:
			peer := e.Data.(router.Station).Data().(*remotePeer)
			peer.peer.Disconnect(p2p.DiscSubprotocolError)
			//peer.Disconnect(DiscSubprotocolError)
		}
	}
}

func (adaptor *ProtoAdaptor) adaptorLoop(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
	remote := remotePeer{ws: ws, peer: peer}
	station := router.NewRemoteStation(string(remote.peer.ID().Bytes()[:8]), &remote)
	adaptor.peerMangaer.addActivePeer(&remote)
	router.StationRegister(station)
	url := remote.peer.Node().String()
	router.SendTo(station, nil, router.NewPeerNotify, &url)
	defer func() {
		adaptor.peerMangaer.delActivePeer(&remote)
		router.StationUnregister(station)
		url := remote.peer.Node().String()
		router.SendTo(station, nil, router.DelPeerNotify, &url)
	}()

	for {
		msg, err := ws.ReadMsg()
		if err != nil {
			return err
		}
		pack := pack{}
		if err := msg.Decode(&pack); err != nil {
			return err
		}
		e, err := pack2event(&pack, station)
		if err != nil {
			return err
		}
		go router.SendEvent(e)
	}
}

// Protocols .
func (adaptor *ProtoAdaptor) Protocols() []p2p.Protocol {
	return []p2p.Protocol{
		p2p.Protocol{
			Name:    "FractalTest",
			Version: 1,
			Length:  1,
			Run:     adaptor.adaptorLoop,
		},
	}
}

// Stop .
func (adaptor *ProtoAdaptor) Stop() {
	adaptor.Server.Stop()
	log.Info("P2P networking stopped")
}

// SendOut .
func (adaptor *ProtoAdaptor) SendOut(e *router.Event) error {
	if e.To.IsBroadcast() {
		adaptor.msgBroadcast(e)
		return nil
	}
	return adaptor.msgSend(e)
}

func (adaptor *ProtoAdaptor) msgSend(e *router.Event) error {
	pack, err := event2pack(e)
	if err != nil {
		return err
	}
	return p2p.Send(e.To.Data().(*remotePeer).ws, 0, pack)
}

func (adaptor *ProtoAdaptor) msgBroadcast(e *router.Event) {
	te := *e
	te.To = nil
	pack, err := event2pack(&te)
	if err != nil {
		return
	}

	send := func(peer *remotePeer) {
		p2p.Send(peer.ws, 0, pack)
	}
	if e.To.Data() != nil {
		pack.To = "" // if sendto 'broadcast' station, remote will broadcast again, and dead loop (-_-)
		e.To.Data().(*peerMangaer).mapActivePeer(send)
		return
	}
	adaptor.peerMangaer.mapActivePeer(send)
}

func event2pack(e *router.Event) (*pack, error) {
	buf, err := rlp.EncodeToBytes(e.Data)
	if err != nil {
		return nil, err
	}
	from := ""
	if e.From != nil {
		from = e.From.Name()
	}
	to := ""
	if e.To != nil {
		to = e.To.Name()[8:]
	}
	return &pack{
		From:     from,
		To:       to,
		Typecode: uint32(e.Typecode),
		Payload:  buf,
	}, nil
}

func pack2event(pack *pack, station router.Station) (*router.Event, error) {
	var elem interface{}

	isPtr := false
	typ := router.GetTypeByCode(int(pack.Typecode))
	if typ == nil {
		return nil, errors.New(fmt.Sprint("unknow typecode:", pack.Typecode))
	} else {
		//for typ.Kind() == reflect.Ptr {
		if typ.Kind() == reflect.Ptr {
			isPtr = true
			typ = typ.Elem()
		}
		obj := reflect.New(typ)
		if err := rlp.DecodeBytes(pack.Payload, obj.Interface()); err != nil {
			return nil, err
		}
		if isPtr {
			elem = obj.Interface()
		} else {
			elem = obj.Elem().Interface()
		}
	}
	if pack.From != "" {
		station = router.NewRemoteStation(station.Name()+pack.From, station.Data())
	}
	return &router.Event{
		From:     station,
		To:       router.GetStationByName(pack.To),
		Typecode: int(pack.Typecode),
		Data:     elem,
	}, nil
}
<commit_msg>p2p: each peer uses only one Coroutine to handle message<commit_after>package protoadaptor

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/ethereum/go-ethereum/log"
	router "github.com/fractalplatform/fractal/event"
	"github.com/fractalplatform/fractal/p2p"
	"github.com/fractalplatform/fractal/utils/rlp"
)

type pack struct {
	From     string
	To       string
	Typecode uint32
	Payload  []byte
}

type remotePeer struct {
	peer *p2p.Peer
	ws   p2p.MsgReadWriter
}

// ProtoAdaptor is subprotocol on p2p
type ProtoAdaptor struct {
	p2p.Server
	peerMangaer
	event   chan *router.Event
	station router.Station
}

// NewProtoAdaptor return new ProtoAdaptor
func NewProtoAdaptor(config *p2p.Config) *ProtoAdaptor {
	adaptor := &ProtoAdaptor{
		Server: p2p.Server{
			Config: config,
		},
		peerMangaer: peerMangaer{
			activePeers: make(map[[8]byte]*remotePeer),
			station:     nil,
		},
		event:   make(chan *router.Event),
		station: router.NewLocalStation("p2p", nil),
	}
	adaptor.peerMangaer.station = router.NewBroadcastStation("broadcast", &adaptor.peerMangaer)
	adaptor.Server.Config.Protocols = adaptor.Protocols()
	return adaptor
}

// Start start p2p protocol adaptor
func (adaptor *ProtoAdaptor) Start() error {
	router.StationRegister(adaptor.peerMangaer.station)
	router.AdaptorRegister(adaptor)
	router.Subscribe(nil, adaptor.event, router.DisconectCtrl, nil)
	go adaptor.adaptorEvent()
	return adaptor.Server.Start()
}

func (adaptor *ProtoAdaptor) adaptorEvent() {
	for {
		e := <-adaptor.event
		switch e.Typecode {
		case router.DisconectCtrl:
			peer := e.Data.(router.Station).Data().(*remotePeer)
			peer.peer.Disconnect(p2p.DiscSubprotocolError)
			//peer.Disconnect(DiscSubprotocolError)
		}
	}
}

func (adaptor *ProtoAdaptor) adaptorLoop(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
	remote := remotePeer{ws: ws, peer: peer}
	station := router.NewRemoteStation(string(remote.peer.ID().Bytes()[:8]), &remote)
	adaptor.peerMangaer.addActivePeer(&remote)
	router.StationRegister(station)
	url := remote.peer.Node().String()
	router.SendTo(station, nil, router.NewPeerNotify, &url)
	defer func() {
		adaptor.peerMangaer.delActivePeer(&remote)
		router.StationUnregister(station)
		url := remote.peer.Node().String()
		router.SendTo(station, nil, router.DelPeerNotify, &url)
	}()

	for {
		msg, err := ws.ReadMsg()
		if err != nil {
			return err
		}
		pack := pack{}
		if err := msg.Decode(&pack); err != nil {
			return err
		}
		e, err := pack2event(&pack, station)
		if err != nil {
			return err
		}
		router.SendEvent(e)
	}
}

// Protocols .
func (adaptor *ProtoAdaptor) Protocols() []p2p.Protocol {
	return []p2p.Protocol{
		p2p.Protocol{
			Name:    "FractalTest",
			Version: 1,
			Length:  1,
			Run:     adaptor.adaptorLoop,
		},
	}
}

// Stop .
func (adaptor *ProtoAdaptor) Stop() {
	adaptor.Server.Stop()
	log.Info("P2P networking stopped")
}

// SendOut .
func (adaptor *ProtoAdaptor) SendOut(e *router.Event) error {
	if e.To.IsBroadcast() {
		adaptor.msgBroadcast(e)
		return nil
	}
	return adaptor.msgSend(e)
}

func (adaptor *ProtoAdaptor) msgSend(e *router.Event) error {
	pack, err := event2pack(e)
	if err != nil {
		return err
	}
	return p2p.Send(e.To.Data().(*remotePeer).ws, 0, pack)
}

func (adaptor *ProtoAdaptor) msgBroadcast(e *router.Event) {
	te := *e
	te.To = nil
	pack, err := event2pack(&te)
	if err != nil {
		return
	}

	send := func(peer *remotePeer) {
		p2p.Send(peer.ws, 0, pack)
	}
	if e.To.Data() != nil {
		pack.To = "" // if sendto 'broadcast' station, remote will broadcast again, and dead loop (-_-)
		e.To.Data().(*peerMangaer).mapActivePeer(send)
		return
	}
	adaptor.peerMangaer.mapActivePeer(send)
}

func event2pack(e *router.Event) (*pack, error) {
	buf, err := rlp.EncodeToBytes(e.Data)
	if err != nil {
		return nil, err
	}
	from := ""
	if e.From != nil {
		from = e.From.Name()
	}
	to := ""
	if e.To != nil {
		to = e.To.Name()[8:]
	}
	return &pack{
		From:     from,
		To:       to,
		Typecode: uint32(e.Typecode),
		Payload:  buf,
	}, nil
}

func pack2event(pack *pack, station router.Station) (*router.Event, error) {
	var elem interface{}

	isPtr := false
	typ := router.GetTypeByCode(int(pack.Typecode))
	if typ == nil {
		return nil, errors.New(fmt.Sprint("unknow typecode:", pack.Typecode))
	} else {
		//for typ.Kind() == reflect.Ptr {
		if typ.Kind() == reflect.Ptr {
			isPtr = true
			typ = typ.Elem()
		}
		obj := reflect.New(typ)
		if err := rlp.DecodeBytes(pack.Payload, obj.Interface()); err != nil {
			return nil, err
		}
		if isPtr {
			elem = obj.Interface()
		} else {
			elem = obj.Elem().Interface()
		}
	}
	if pack.From != "" {
		station = router.NewRemoteStation(station.Name()+pack.From, station.Data())
	}
	return &router.Event{
		From:     station,
		To:       router.GetStationByName(pack.To),
		Typecode: int(pack.Typecode),
		Data:     elem,
	}, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"fmt"
	"testing"
	"time"

	"github.com/pkg/errors"
	"github.com/shirou/gopsutil/process"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/minikube/pkg/kapi"
)

// WaitForBusyboxRunning waits until busybox pod to be running
func WaitForBusyboxRunning(t *testing.T, namespace string, miniProfile string) error {
	client, err := kapi.Client(miniProfile)
	if err != nil {
		return errors.Wrap(err, "getting kubernetes client")
	}
	selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"}))
	return kapi.WaitForPodsWithLabelRunning(client, namespace, selector)
}

// Logf writes logs to stdout if -v is set.
func Logf(str string, args ...interface{}) {
	if !testing.Verbose() {
		return
	}
	fmt.Printf(" %s | ", time.Now().Format("15:04:05"))
	fmt.Println(fmt.Sprintf(str, args...))
}

// KillProcess kills the process associated with the given pid and all its children
func KillProcess(pid int, t *testing.T) error {
	p, err := process.NewProcess(int32(pid))
	if err != nil {
		// Process doesn't exist
		return err
	}
	children, err := p.Children()
	if err != nil {
		// No children, log the error, don't exit
		t.Log(err)
	}
	for _, c := range children {
		err = c.Kill()
		if err != nil {
			// Log the error, but don't exit
			t.Log(err)
		}
	}
	err = p.Kill()
	if err != nil {
		return err
	}

	return nil

}
<commit_msg>remove extra line<commit_after>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package util

import (
	"fmt"
	"testing"
	"time"

	"github.com/pkg/errors"
	"github.com/shirou/gopsutil/process"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/minikube/pkg/kapi"
)

// WaitForBusyboxRunning waits until busybox pod to be running
func WaitForBusyboxRunning(t *testing.T, namespace string, miniProfile string) error {
	client, err := kapi.Client(miniProfile)
	if err != nil {
		return errors.Wrap(err, "getting kubernetes client")
	}
	selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox"}))
	return kapi.WaitForPodsWithLabelRunning(client, namespace, selector)
}

// Logf writes logs to stdout if -v is set.
func Logf(str string, args ...interface{}) {
	if !testing.Verbose() {
		return
	}
	fmt.Printf(" %s | ", time.Now().Format("15:04:05"))
	fmt.Println(fmt.Sprintf(str, args...))
}

// KillProcess kills the process associated with the given pid and all its children
func KillProcess(pid int, t *testing.T) error {
	p, err := process.NewProcess(int32(pid))
	if err != nil {
		// Process doesn't exist
		return err
	}
	children, err := p.Children()
	if err != nil {
		// No children, log the error, don't exit
		t.Log(err)
	}
	for _, c := range children {
		err = c.Kill()
		if err != nil {
			// Log the error, but don't exit
			t.Log(err)
		}
	}
	err = p.Kill()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package utils

import "testing"

func TestNewConfig(t *testing.T) {
	config, err := NewConfig("../run.conf")
	if err != nil {
		t.Error(err)
	}
	if config.Sources["http"] != "http:%s" {
		t.Errorf("Parse result is not correct")
	}
}
<commit_msg>add test for NewConfigFromString<commit_after>package utils

import "testing"

func TestNewConfig(t *testing.T) {
	config, err := NewConfig("../run.conf")
	if err != nil {
		t.Error(err)
	}
	if config.Sources["http"] != "http:%s" {
		t.Errorf("Parse result is not correct")
	}
}

func TestNewConfigFromString(t *testing.T) {
	str := `
[sources]
# ignore
default: default_url
  space: space_url  `
	config, err := NewConfigFromString(str)
	if err != nil {
		t.Error(err)
	}
	if config.Sources["default"] != "default_url" {
		t.Errorf("'default' source is not parsed correctly")
	} else if config.Sources["space"] != "space_url" {
		t.Errorf("'space' source is not parsed correctly")
	} else if _, ok := config.Sources["ignore"]; ok {
		t.Errorf("'ignore' source should be ignored")
	}
}
<|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 utils

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/zenoss/glog"
)

// ExecDockerExec execs the command using docker exec
func ExecDockerExec(containerID string, bashcmd []string) error {
	command, err := generateDockerExecCommand(containerID, bashcmd, false)
	if err != nil {
		return err
	}
	glog.V(1).Infof("exec command for container:%v command: %v\n", containerID, command)
	return syscall.Exec(command[0], command[0:], os.Environ())
}

// RunDockerExec runs the command using docker exec
func RunDockerExec(containerID string, bashcmd []string) ([]byte, error) {
	command, err := generateDockerExecCommand(containerID, bashcmd, true)
	if err != nil {
		return nil, err
	}
	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		glog.Errorf("Error running command:'%s' output: %s  error: %s\n", command, output, err)
		return output, err
	}
	glog.V(1).Infof("Successfully ran command:'%s' output: %s\n", command, output)
	return output, nil
}

// generateDockerExecCommand returns a slice containing docker exec command to exec
func generateDockerExecCommand(containerID string, bashcmd []string, prependBash bool) ([]string, error) {
	if containerID == "" {
		return []string{}, fmt.Errorf("will not attach to container with empty containerID")
	}

	exeMap, err := exePaths([]string{"docker"})
	if err != nil {
		return []string{}, err
	}

	// TODO: add '-h' hostname to specify the container hostname when that
	// feature becomes available
	attachCmd := []string{exeMap["docker"], "exec", "-i", "-t", containerID, "--"}
	if prependBash {
		attachCmd = append(attachCmd, "/bin/bash", "-c", fmt.Sprintf("%s", strings.Join(bashcmd, " ")))
	} else {
		attachCmd = append(attachCmd, bashcmd...)
	}
	glog.V(1).Infof("attach command for container:%v command: %v\n", containerID, attachCmd)
	return attachCmd, nil
}

// hasFeatureDockerExec returns true if docker exec is supported
func hasFeatureDockerExec() bool {
	command := []string{"docker", "exec"}

	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	// when docker exec is supported, we expect above 'docker exec' to fail,
	// but provide usage
	glog.V(1).Infof("Successfully ran command:'%s'  err: %s  output: %s\n", command, err, output)

	return strings.Contains(string(output), "Usage: docker exec")
}

// AttachAndRun attaches to a container and runs the command
func AttachAndRun(containerID string, bashcmd []string) ([]byte, error) {
	result, err := AttachAndRunMaybeSudo(containerID, bashcmd, true)
	return result, err
}

// Like AttachAndRun, but specify whether or not to use sudo
func AttachAndRunMaybeSudo(containerID string, bashcmd []string, useSudo bool) ([]byte, error) {
	if hasFeatureDockerExec() {
		return RunDockerExec(containerID, bashcmd)
	}

	_, err := exec.LookPath("nsenter")
	if err == nil {
		return RunNSEnter(containerID, bashcmd, useSudo)
	}

	return nil, fmt.Errorf("unable to find attach utility to run: %s", bashcmd)
}

// AttachAndExec attaches to a container and execs the command
func AttachAndExec(containerID string, bashcmd []string) error {
	if hasFeatureDockerExec() {
		return ExecDockerExec(containerID, bashcmd)
	}

	_, err := exec.LookPath("nsenter")
	if err == nil {
		return ExecNSEnter(containerID, bashcmd)
	}

	return fmt.Errorf("unable to find attach utility to exec: %s", bashcmd)
}

// exePaths returns the full path to the given executables in a map
func exePaths(exes []string) (map[string]string, error) {
	exeMap := map[string]string{}

	for _, exe := range exes {
		path, err := exec.LookPath(exe)
		if err != nil {
			glog.Errorf("exe:'%v' not found error:%v\n", exe, err)
			return nil, err
		}

		exeMap[exe] = path
	}

	return exeMap, nil
}
<commit_msg>remove extraneous -- from docker exec command<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 utils

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/zenoss/glog"
)

// ExecDockerExec execs the command using docker exec
func ExecDockerExec(containerID string, bashcmd []string) error {
	command, err := generateDockerExecCommand(containerID, bashcmd, false)
	if err != nil {
		return err
	}
	glog.V(1).Infof("exec command for container:%v command: %v\n", containerID, command)
	return syscall.Exec(command[0], command[0:], os.Environ())
}

// RunDockerExec runs the command using docker exec
func RunDockerExec(containerID string, bashcmd []string) ([]byte, error) {
	command, err := generateDockerExecCommand(containerID, bashcmd, true)
	if err != nil {
		return nil, err
	}
	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		glog.Errorf("Error running command:'%s' output: %s  error: %s\n", command, output, err)
		return output, err
	}
	glog.V(1).Infof("Successfully ran command:'%s' output: %s\n", command, output)
	return output, nil
}

// generateDockerExecCommand returns a slice containing docker exec command to exec
func generateDockerExecCommand(containerID string, bashcmd []string, prependBash bool) ([]string, error) {
	if containerID == "" {
		return []string{}, fmt.Errorf("will not attach to container with empty containerID")
	}

	exeMap, err := exePaths([]string{"docker"})
	if err != nil {
		return []string{}, err
	}

	// TODO: add '-h' hostname to specify the container hostname when that
	// feature becomes available
	attachCmd := []string{exeMap["docker"], "exec", "-i", "-t", containerID}
	if prependBash {
		attachCmd = append(attachCmd, "/bin/bash", "-c", fmt.Sprintf("%s", strings.Join(bashcmd, " ")))
	} else {
		attachCmd = append(attachCmd, bashcmd...)
	}
	glog.V(1).Infof("attach command for container:%v command: %v\n", containerID, attachCmd)
	return attachCmd, nil
}

// hasFeatureDockerExec returns true if docker exec is supported
func hasFeatureDockerExec() bool {
	command := []string{"docker", "exec"}

	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	// when docker exec is supported, we expect above 'docker exec' to fail,
	// but provide usage
	glog.V(1).Infof("Successfully ran command:'%s'  err: %s  output: %s\n", command, err, output)

	return strings.Contains(string(output), "Usage: docker exec")
}

// AttachAndRun attaches to a container and runs the command
func AttachAndRun(containerID string, bashcmd []string) ([]byte, error) {
	result, err := AttachAndRunMaybeSudo(containerID, bashcmd, true)
	return result, err
}

// Like AttachAndRun, but specify whether or not to use sudo
func AttachAndRunMaybeSudo(containerID string, bashcmd []string, useSudo bool) ([]byte, error) {
	if hasFeatureDockerExec() {
		return RunDockerExec(containerID, bashcmd)
	}

	_, err := exec.LookPath("nsenter")
	if err == nil {
		return RunNSEnter(containerID, bashcmd, useSudo)
	}

	return nil, fmt.Errorf("unable to find attach utility to run: %s", bashcmd)
}

// AttachAndExec attaches to a container and execs the command
func AttachAndExec(containerID string, bashcmd []string) error {
	if hasFeatureDockerExec() {
		return ExecDockerExec(containerID, bashcmd)
	}

	_, err := exec.LookPath("nsenter")
	if err == nil {
		return ExecNSEnter(containerID, bashcmd)
	}

	return fmt.Errorf("unable to find attach utility to exec: %s", bashcmd)
}

// exePaths returns the full path to the given executables in a map
func exePaths(exes []string) (map[string]string, error) {
	exeMap := map[string]string{}

	for _, exe := range exes {
		path, err := exec.LookPath(exe)
		if err != nil {
			glog.Errorf("exe:'%v' not found error:%v\n", exe, err)
			return nil, err
		}

		exeMap[exe] = path
	}

	return exeMap, nil
}
<|endoftext|>


<commit_before>package models_test

import (
	"github.com/alex1sz/shotcharter-go/db"
	"github.com/alex1sz/shotcharter-go/models"
	"github.com/alex1sz/shotcharter-go/test/helpers/test_helper"
	"log"
	"testing"
)

func TestSetupBeforeAndAfterCountsHelper(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("games")

	if after_create_count != 0 {
		t.Error("setupCountVariables failed, after_create_count expected to be 0")
	}

	if pre_create_count < 1 {
		t.Error("No games created!")
	}

	if sql != "SELECT COUNT(*) from games" {
		t.Error("setupCountVariables failed wrong sql query")
	}
}

func TestTeamCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("teams")

	test_helper.CreateTestTeam()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Team create failed!")
	}
}

func TestPlayerCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("players")

	team := test_helper.CreateTestTeam()

	player := models.Player{Name: "Alejandro Alejandro", Active: true, JerseyNumber: 24, Team: &team}
	player.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Player create failed!")
	}
}

func TestGameCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("games")

	home_team := test_helper.CreateTestTeam()
	away_team := test_helper.CreateTestTeam()

	game := models.Game{HomeTeam: &home_team, AwayTeam: &away_team}
	game.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Game create failed!")
	}
}

func TestShotCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("shots")

	player := test_helper.CreateTestPlayer()
	game := test_helper.CreateTestGameForHomeTeam(player.Team)

	shot := models.Shot{Player: &player, Game: &game, PtValue: 3, Made: true, XAxis: 312, YAxis: 250}
	shot.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Shot not created!")
	}
}

func TestFindTeamByID(t *testing.T) {
	team := test_helper.CreateTestTeam()

	returnedTeam, err := models.FindTeamByID(team.ID)

	log.Print(returnedTeam)

	if err != nil {
		log.Println(err)
		t.Error("FindTeamByID fails to return team!")
	}
}
<commit_msg>Adds test for GameFindByID<commit_after>package models_test

import (
	"github.com/alex1sz/shotcharter-go/db"
	"github.com/alex1sz/shotcharter-go/models"
	"github.com/alex1sz/shotcharter-go/test/helpers/test_helper"
	"log"
	"testing"
)

func TestSetupBeforeAndAfterCountsHelper(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("games")

	if after_create_count != 0 {
		t.Error("setupCountVariables failed, after_create_count expected to be 0")
	}

	if pre_create_count < 1 {
		t.Error("No games created!")
	}

	if sql != "SELECT COUNT(*) from games" {
		t.Error("setupCountVariables failed wrong sql query")
	}
}

func TestTeamCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("teams")

	test_helper.CreateTestTeam()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Team create failed!")
	}
}

func TestPlayerCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("players")

	team := test_helper.CreateTestTeam()

	player := models.Player{Name: "Alejandro Alejandro", Active: true, JerseyNumber: 24, Team: &team}
	player.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Player create failed!")
	}
}

func TestGameCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("games")

	home_team := test_helper.CreateTestTeam()
	away_team := test_helper.CreateTestTeam()

	game := models.Game{HomeTeam: &home_team, AwayTeam: &away_team}
	game.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Game create failed!")
	}
}

func TestShotCreate(t *testing.T) {
	var pre_create_count, after_create_count, sql = test_helper.SetupBeforeAndAfterCounts("shots")

	player := test_helper.CreateTestPlayer()
	game := test_helper.CreateTestGameForHomeTeam(player.Team)

	shot := models.Shot{Player: &player, Game: &game, PtValue: 3, Made: true, XAxis: 312, YAxis: 250}
	shot.Create()

	db.Db.Get(after_create_count, sql)

	if after_create_count > pre_create_count {
		t.Error("Shot not created!")
	}
}

func TestFindTeamByID(t *testing.T) {
	team := test_helper.CreateTestTeam()

	returnedTeam, err := models.FindTeamByID(team.ID)

	log.Print(returnedTeam)

	if err != nil {
		log.Println(err)
		t.Error("FindTeamByID failed to return team!")
	}
}

func TestGameFindByID(t *testing.T) {
	game := test_helper.CreateTestGame()

	var returnedGame, err = models.FindGameByID(game.ID)

	if len(returnedGame.ID) < 1 {
		log.Println("FindGameByID returns game but also returns err")
		log.Println(err)
		t.Error("FindGameByID failed to return valid game")
	}
}
<|endoftext|>