forked from lug/matterbridge
		
	Compare commits
	
		
			53 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0f2976c5ce | ||
| 
						 | 
					78b17977c5 | ||
| 
						 | 
					6ec77e06ea | ||
| 
						 | 
					e48db67649 | ||
| 
						 | 
					e03f331f55 | ||
| 
						 | 
					ff5aeeb1e1 | ||
| 
						 | 
					33844fa60c | ||
| 
						 | 
					85faa43145 | ||
| 
						 | 
					59e6abcc11 | ||
| 
						 | 
					38e3bbe5c9 | ||
| 
						 | 
					51265d5464 | ||
| 
						 | 
					de4c780410 | ||
| 
						 | 
					6b18257185 | ||
| 
						 | 
					4b1ebaf7d5 | ||
| 
						 | 
					93db74e7e1 | ||
| 
						 | 
					0e6fe4070a | ||
| 
						 | 
					69b534ee99 | ||
| 
						 | 
					71a504945b | ||
| 
						 | 
					99ac7dc114 | ||
| 
						 | 
					4984473c1b | ||
| 
						 | 
					3fcce2d8a0 | ||
| 
						 | 
					a53e699112 | ||
| 
						 | 
					f29822db02 | ||
| 
						 | 
					a63433e41b | ||
| 
						 | 
					e0379ca5af | ||
| 
						 | 
					4759ee6132 | ||
| 
						 | 
					5ec94fdb43 | ||
| 
						 | 
					a64deb1238 | ||
| 
						 | 
					f914695801 | ||
| 
						 | 
					304dc2e25f | ||
| 
						 | 
					fd74dca175 | ||
| 
						 | 
					c7ace91bf6 | ||
| 
						 | 
					9f07a2cfd5 | ||
| 
						 | 
					0dc5e042d2 | ||
| 
						 | 
					f0a5d2396f | ||
| 
						 | 
					bdac03f725 | ||
| 
						 | 
					c1f80383f7 | ||
| 
						 | 
					bd7c1e3e3c | ||
| 
						 | 
					5c1b02c7a3 | ||
| 
						 | 
					38fce68609 | ||
| 
						 | 
					90f276863b | ||
| 
						 | 
					5282cdaccd | ||
| 
						 | 
					008ea94b53 | ||
| 
						 | 
					693f1946b7 | ||
| 
						 | 
					8b6a00d1c5 | ||
| 
						 | 
					43738dbc89 | ||
| 
						 | 
					6feccd4c6c | ||
| 
						 | 
					25d72a7e31 | ||
| 
						 | 
					523f6ffb80 | ||
| 
						 | 
					b346ac868b | ||
| 
						 | 
					d0cda03478 | ||
| 
						 | 
					19b3145bd1 | ||
| 
						 | 
					a0d1fc0d6a | 
							
								
								
									
										11
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
FROM alpine:edge
 | 
			
		||||
ENTRYPOINT ["/bin/matterbridge"]
 | 
			
		||||
 | 
			
		||||
COPY . /go/src/github.com/42wim/matterbridge
 | 
			
		||||
RUN apk update && apk add go git \
 | 
			
		||||
        && cd /go/src/github.com/42wim/matterbridge \
 | 
			
		||||
        && export GOPATH=/go \
 | 
			
		||||
        && go get \
 | 
			
		||||
        && go build -o /bin/matterbridge \
 | 
			
		||||
        && rm -rf /go \
 | 
			
		||||
        && apk del --purge git go
 | 
			
		||||
							
								
								
									
										57
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								README.md
									
									
									
									
									
								
							@@ -3,14 +3,19 @@
 | 
			
		||||
Simple bridge between mattermost and IRC. Uses the in/outgoing webhooks.  
 | 
			
		||||
Relays public channel messages between mattermost and IRC.  
 | 
			
		||||
 | 
			
		||||
Work in progress. 
 | 
			
		||||
Requires mattermost 1.2.0+
 | 
			
		||||
 | 
			
		||||
There is also [matterbridge-plus] (https://github.com/42wim/matterbridge-plus) which uses the mattermost API and needs a dedicated user (bot). But requires no incoming/outgoing webhook setup. 
 | 
			
		||||
 | 
			
		||||
## binaries
 | 
			
		||||
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/tag/v0.4.2)
 | 
			
		||||
 | 
			
		||||
## building
 | 
			
		||||
Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
 | 
			
		||||
Go 1.6+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cd $GOPATH
 | 
			
		||||
go get https://github.com/42wim/matterbridge
 | 
			
		||||
go get github.com/42wim/matterbridge
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You should now have matterbridge binary in the bin directory:
 | 
			
		||||
@@ -23,7 +28,12 @@ matterbridge
 | 
			
		||||
## running
 | 
			
		||||
1) Copy the matterbridge.conf.sample to matterbridge.conf in the same directory as the matterbridge binary.  
 | 
			
		||||
2) Edit matterbridge.conf with the settings for your environment. See below for more config information.  
 | 
			
		||||
3) Now you can run matterbridge.  
 | 
			
		||||
3) Now you can run matterbridge. 
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Usage of matterbridge:
 | 
			
		||||
  -conf="matterbridge.conf": config file
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Matterbridge will:
 | 
			
		||||
* start a webserver listening on the port specified in the configuration.
 | 
			
		||||
@@ -32,7 +42,7 @@ Matterbridge will:
 | 
			
		||||
 | 
			
		||||
## config
 | 
			
		||||
### matterbridge
 | 
			
		||||
matterbridge looks for matterbridge.conf in current directory.
 | 
			
		||||
matterbridge looks for matterbridge.conf in current directory. (use -conf to specify another file)
 | 
			
		||||
 | 
			
		||||
Look at matterbridge.conf.sample for an example
 | 
			
		||||
 | 
			
		||||
@@ -45,12 +55,49 @@ UseTLS=false
 | 
			
		||||
SkipTLSVerify=true
 | 
			
		||||
nick="matterbot"
 | 
			
		||||
channel="#matterbridge"
 | 
			
		||||
UseSlackCircumfix=false
 | 
			
		||||
#Freenode nickserv
 | 
			
		||||
NickServNick="nickserv"
 | 
			
		||||
#Password for nickserv
 | 
			
		||||
NickServPassword="secret"
 | 
			
		||||
#Ignore the messages from these nicks. They will not be sent to mattermost
 | 
			
		||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
			
		||||
 | 
			
		||||
[mattermost]
 | 
			
		||||
#url is your incoming webhook url (account settings - integrations - incoming webhooks)
 | 
			
		||||
url="http://mattermost.yourdomain.com/hooks/incomingwebhookkey"  
 | 
			
		||||
#port the bridge webserver will listen on
 | 
			
		||||
port=9999
 | 
			
		||||
#address the webserver will bind to
 | 
			
		||||
BindAddress="0.0.0.0"
 | 
			
		||||
showjoinpart=true #show irc users joining and parting
 | 
			
		||||
#the token you get from the outgoing webhook in mattermost. If empty no token check will be done.
 | 
			
		||||
#if you use multiple IRC channel (see below, this must be empty!)
 | 
			
		||||
token=yourtokenfrommattermost
 | 
			
		||||
#disable certificate checking (selfsigned certificates)
 | 
			
		||||
#SkipTLSVerify=true
 | 
			
		||||
#whether to prefix messages from IRC to mattermost with the sender's nick. Useful if username overrides for incoming webhooks isn't enabled on the mattermost server
 | 
			
		||||
PrefixMessagesWithNick=false
 | 
			
		||||
#how to format the list of IRC nicks when displayed in mattermost. Possible options are "table" and "plain"
 | 
			
		||||
NickFormatter=plain
 | 
			
		||||
#how many nicks to list per row for formatters that support this
 | 
			
		||||
NicksPerRow=4
 | 
			
		||||
#Ignore the messages from these nicks. They will not be sent to irc
 | 
			
		||||
IgnoreNicks="mmbot spammer2"
 | 
			
		||||
 | 
			
		||||
#multiple channel config
 | 
			
		||||
#token you can find in your outgoing webhook
 | 
			
		||||
[Token "outgoingwebhooktoken1"] 
 | 
			
		||||
IRCChannel="#off-topic"
 | 
			
		||||
MMChannel="off-topic"
 | 
			
		||||
 | 
			
		||||
[Token "outgoingwebhooktoken2"]
 | 
			
		||||
IRCChannel="#testing"
 | 
			
		||||
MMChannel="testing"
 | 
			
		||||
 | 
			
		||||
[general]
 | 
			
		||||
#request your API key on https://github.com/giphy/GiphyAPI. This is a public beta key
 | 
			
		||||
GiphyApiKey="dc6zaTOxFJmzC"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### mattermost
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								config.go
									
									
									
									
									
								
							@@ -1,35 +0,0 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"gopkg.in/gcfg.v1"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	IRC struct {
 | 
			
		||||
		UseTLS        bool
 | 
			
		||||
		SkipTLSVerify bool
 | 
			
		||||
		Server        string
 | 
			
		||||
		Port          int
 | 
			
		||||
		Nick          string
 | 
			
		||||
		Channel       string
 | 
			
		||||
	}
 | 
			
		||||
	Mattermost struct {
 | 
			
		||||
		URL  string
 | 
			
		||||
		Port int
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewConfig(cfgfile string) *Config {
 | 
			
		||||
	var cfg Config
 | 
			
		||||
	content, err := ioutil.ReadFile(cfgfile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = gcfg.ReadStringInto(&cfg, string(content))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Failed to parse "+cfgfile+":", err)
 | 
			
		||||
	}
 | 
			
		||||
	return &cfg
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,35 @@ UseTLS=false
 | 
			
		||||
SkipTLSVerify=true
 | 
			
		||||
nick="matterbot"
 | 
			
		||||
channel="#matterbridge"
 | 
			
		||||
UseSlackCircumfix=false
 | 
			
		||||
#NickServNick="nickserv"
 | 
			
		||||
#NickServPassword="secret"
 | 
			
		||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
			
		||||
 | 
			
		||||
[mattermost]
 | 
			
		||||
url="http://yourdomain/hooks/yourhookkey"
 | 
			
		||||
port=9999
 | 
			
		||||
showjoinpart=true
 | 
			
		||||
#remove token when using multiple channels!
 | 
			
		||||
token=yourtokenfrommattermost
 | 
			
		||||
IconURL="http://youricon.png"
 | 
			
		||||
#SkipTLSVerify=true
 | 
			
		||||
#BindAddress="0.0.0.0"
 | 
			
		||||
PrefixMessagesWithNick=false
 | 
			
		||||
NickFormatter=plain
 | 
			
		||||
NicksPerRow=4
 | 
			
		||||
IgnoreNicks="mmbot spammer2"
 | 
			
		||||
 | 
			
		||||
[general]
 | 
			
		||||
GiphyAPIKey=dc6zaTOxFJmzC
 | 
			
		||||
 | 
			
		||||
#multiple channel config
 | 
			
		||||
#token you can find in your outgoing webhook
 | 
			
		||||
[Token "outgoingwebhooktoken1"] 
 | 
			
		||||
IRCChannel="#off-topic"
 | 
			
		||||
MMChannel="off-topic"
 | 
			
		||||
 | 
			
		||||
[Token "outgoingwebhooktoken2"]
 | 
			
		||||
IRCChannel="#testing"
 | 
			
		||||
MMChannel="testing"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,56 +1,33 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterhook"
 | 
			
		||||
	"github.com/thoj/go-ircevent"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/42wim/matterbridge-plus/bridge"
 | 
			
		||||
	log "github.com/Sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Bridge struct {
 | 
			
		||||
	i *irc.Connection
 | 
			
		||||
	m *matterhook.Client
 | 
			
		||||
	*Config
 | 
			
		||||
}
 | 
			
		||||
var Version = "0.4.2"
 | 
			
		||||
 | 
			
		||||
func NewBridge(name string, config *Config) *Bridge {
 | 
			
		||||
	b := &Bridge{}
 | 
			
		||||
	b.Config = config
 | 
			
		||||
	b.m = matterhook.New(b.Config.Mattermost.URL, matterhook.Config{Port: b.Config.Mattermost.Port})
 | 
			
		||||
	b.i = b.createIRC(name)
 | 
			
		||||
	go b.handleMatter()
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) createIRC(name string) *irc.Connection {
 | 
			
		||||
	i := irc.IRC(b.Config.IRC.Nick, b.Config.IRC.Nick)
 | 
			
		||||
	i.UseTLS = b.Config.IRC.UseTLS
 | 
			
		||||
	i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.IRC.SkipTLSVerify}
 | 
			
		||||
	i.Connect(b.Config.IRC.Server + ":" + strconv.Itoa(b.Config.IRC.Port))
 | 
			
		||||
	time.Sleep(time.Second)
 | 
			
		||||
	log.Println("Joining", b.Config.IRC.Channel, "as", b.Config.IRC.Nick)
 | 
			
		||||
	i.Join(b.Config.IRC.Channel)
 | 
			
		||||
	i.AddCallback("PRIVMSG", b.handlePrivMsg)
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handlePrivMsg(event *irc.Event) {
 | 
			
		||||
	matterMessage := matterhook.OMessage{}
 | 
			
		||||
	matterMessage.Text = event.Message()
 | 
			
		||||
	matterMessage.UserName = "irc-" + event.Nick
 | 
			
		||||
	b.m.Send(matterMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleMatter() {
 | 
			
		||||
	for {
 | 
			
		||||
		message := b.m.Receive()
 | 
			
		||||
		b.i.Privmsg(b.Config.IRC.Channel, message.UserName+": "+message.Text)
 | 
			
		||||
	}
 | 
			
		||||
func init() {
 | 
			
		||||
	log.SetFormatter(&log.TextFormatter{FullTimestamp: true})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	NewBridge("matterbot", NewConfig("matterbridge.conf"))
 | 
			
		||||
	flagConfig := flag.String("conf", "matterbridge.conf", "config file")
 | 
			
		||||
	flagDebug := flag.Bool("debug", false, "enable debug")
 | 
			
		||||
	flagVersion := flag.Bool("version", false, "show version")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if *flagVersion {
 | 
			
		||||
		fmt.Println("Version:", Version)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if *flagDebug {
 | 
			
		||||
		log.Info("enabling debug")
 | 
			
		||||
		log.SetLevel(log.DebugLevel)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("running version", Version)
 | 
			
		||||
	bridge.NewBridge("matterbot", bridge.NewConfig(*flagConfig), "legacy")
 | 
			
		||||
	select {}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
//Package matterhook provides interaction with mattermost incoming/outgoing webhooks
 | 
			
		||||
package matterhook
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/gorilla/schema"
 | 
			
		||||
@@ -14,11 +16,13 @@ import (
 | 
			
		||||
 | 
			
		||||
// OMessage for mattermost incoming webhook. (send to mattermost)
 | 
			
		||||
type OMessage struct {
 | 
			
		||||
	Channel   string `json:"channel,omitempty"`
 | 
			
		||||
	IconURL   string `json:"icon_url,omitempty"`
 | 
			
		||||
	IconEmoji string `json:"icon_emoji,omitempty"`
 | 
			
		||||
	UserName  string `json:"username,omitempty"`
 | 
			
		||||
	Text      string `json:"text"`
 | 
			
		||||
	Channel     string      `json:"channel,omitempty"`
 | 
			
		||||
	IconURL     string      `json:"icon_url,omitempty"`
 | 
			
		||||
	IconEmoji   string      `json:"icon_emoji,omitempty"`
 | 
			
		||||
	UserName    string      `json:"username,omitempty"`
 | 
			
		||||
	Text        string      `json:"text"`
 | 
			
		||||
	Attachments interface{} `json:"attachments,omitempty"`
 | 
			
		||||
	Type        string      `json:"type,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IMessage for mattermost outgoing webhook. (received from mattermost)
 | 
			
		||||
@@ -27,34 +31,47 @@ type IMessage struct {
 | 
			
		||||
	TeamID      string `schema:"team_id"`
 | 
			
		||||
	TeamDomain  string `schema:"team_domain"`
 | 
			
		||||
	ChannelID   string `schema:"channel_id"`
 | 
			
		||||
	ServiceID   string `schema:"service_id"`
 | 
			
		||||
	ChannelName string `schema:"channel_name"`
 | 
			
		||||
	Timestamp   string `schema:"timestamp"`
 | 
			
		||||
	UserID      string `schema:"user_id"`
 | 
			
		||||
	UserName    string `schema:"user_name"`
 | 
			
		||||
	PostId      string `schema:"post_id"`
 | 
			
		||||
	Text        string `schema:"text"`
 | 
			
		||||
	TriggerWord string `schema:"trigger_word"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Client for Mattermost.
 | 
			
		||||
type Client struct {
 | 
			
		||||
	url string
 | 
			
		||||
	In  chan IMessage
 | 
			
		||||
	Out chan OMessage
 | 
			
		||||
	Url        string // URL for incoming webhooks on mattermost.
 | 
			
		||||
	In         chan IMessage
 | 
			
		||||
	Out        chan OMessage
 | 
			
		||||
	httpclient *http.Client
 | 
			
		||||
	Config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Config for client.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Port int
 | 
			
		||||
	Port               int    // Port to listen on.
 | 
			
		||||
	BindAddress        string // Address to listen on
 | 
			
		||||
	Token              string // Only allow this token from Mattermost. (Allow everything when empty)
 | 
			
		||||
	InsecureSkipVerify bool   // disable certificate checking
 | 
			
		||||
	DisableServer      bool   // Do not start server for outgoing webhooks from Mattermost.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New Mattermost client.
 | 
			
		||||
func New(url string, config Config) *Client {
 | 
			
		||||
	c := &Client{url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
 | 
			
		||||
	c := &Client{Url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
 | 
			
		||||
	if c.Port == 0 {
 | 
			
		||||
		c.Port = 9999
 | 
			
		||||
	}
 | 
			
		||||
	go c.StartServer()
 | 
			
		||||
	c.BindAddress += ":"
 | 
			
		||||
	tr := &http.Transport{
 | 
			
		||||
		TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify},
 | 
			
		||||
	}
 | 
			
		||||
	c.httpclient = &http.Client{Transport: tr}
 | 
			
		||||
	if !c.DisableServer {
 | 
			
		||||
		go c.StartServer()
 | 
			
		||||
	}
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -62,14 +79,19 @@ func New(url string, config Config) *Client {
 | 
			
		||||
func (c *Client) StartServer() {
 | 
			
		||||
	mux := http.NewServeMux()
 | 
			
		||||
	mux.Handle("/", c)
 | 
			
		||||
	log.Printf("Listening on http://0.0.0.0:%v...\n", c.Port)
 | 
			
		||||
	if err := http.ListenAndServe((":" + strconv.Itoa(c.Port)), mux); err != nil {
 | 
			
		||||
	log.Printf("Listening on http://%v:%v...\n", c.BindAddress, c.Port)
 | 
			
		||||
	if err := http.ListenAndServe((c.BindAddress + strconv.Itoa(c.Port)), mux); err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implementation.
 | 
			
		||||
func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.Method != "POST" {
 | 
			
		||||
		log.Println("invalid " + r.Method + " connection from " + r.RemoteAddr)
 | 
			
		||||
		http.NotFound(w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	msg := IMessage{}
 | 
			
		||||
	err := r.ParseForm()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -85,6 +107,18 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		http.NotFound(w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if msg.Token == "" {
 | 
			
		||||
		log.Println("no token from " + r.RemoteAddr)
 | 
			
		||||
		http.NotFound(w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if c.Token != "" {
 | 
			
		||||
		if msg.Token != c.Token {
 | 
			
		||||
			log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
 | 
			
		||||
			http.NotFound(w, r)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c.In <- msg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -104,7 +138,7 @@ func (c *Client) Send(msg OMessage) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	resp, err := http.Post(c.url, "application/json", bytes.NewReader(buf))
 | 
			
		||||
	resp, err := c.httpclient.Post(c.Url, "application/json", bytes.NewReader(buf))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										202
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "{}"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright {yyyy} {name of copyright owner}
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										434
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/bridge.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										434
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/bridge.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,434 @@
 | 
			
		||||
package bridge
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"github.com/42wim/matterbridge-plus/matterclient"
 | 
			
		||||
	"github.com/42wim/matterbridge/matterhook"
 | 
			
		||||
	log "github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/peterhellberg/giphy"
 | 
			
		||||
	ircm "github.com/sorcix/irc"
 | 
			
		||||
	"github.com/thoj/go-ircevent"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//type Bridge struct {
 | 
			
		||||
type MMhook struct {
 | 
			
		||||
	mh *matterhook.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MMapi struct {
 | 
			
		||||
	mc            *matterclient.MMClient
 | 
			
		||||
	mmMap         map[string]string
 | 
			
		||||
	mmIgnoreNicks []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MMirc struct {
 | 
			
		||||
	i              *irc.Connection
 | 
			
		||||
	ircNick        string
 | 
			
		||||
	ircMap         map[string]string
 | 
			
		||||
	names          map[string][]string
 | 
			
		||||
	ircIgnoreNicks []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MMMessage struct {
 | 
			
		||||
	Text     string
 | 
			
		||||
	Channel  string
 | 
			
		||||
	Username string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Bridge struct {
 | 
			
		||||
	MMhook
 | 
			
		||||
	MMapi
 | 
			
		||||
	MMirc
 | 
			
		||||
	*Config
 | 
			
		||||
	kind string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FancyLog struct {
 | 
			
		||||
	irc *log.Entry
 | 
			
		||||
	mm  *log.Entry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var flog FancyLog
 | 
			
		||||
 | 
			
		||||
const Legacy = "legacy"
 | 
			
		||||
 | 
			
		||||
func initFLog() {
 | 
			
		||||
	flog.irc = log.WithFields(log.Fields{"module": "irc"})
 | 
			
		||||
	flog.mm = log.WithFields(log.Fields{"module": "mattermost"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewBridge(name string, config *Config, kind string) *Bridge {
 | 
			
		||||
	initFLog()
 | 
			
		||||
	b := &Bridge{}
 | 
			
		||||
	b.Config = config
 | 
			
		||||
	b.kind = kind
 | 
			
		||||
	b.ircNick = b.Config.IRC.Nick
 | 
			
		||||
	b.ircMap = make(map[string]string)
 | 
			
		||||
	b.MMirc.names = make(map[string][]string)
 | 
			
		||||
	b.ircIgnoreNicks = strings.Fields(b.Config.IRC.IgnoreNicks)
 | 
			
		||||
	b.mmIgnoreNicks = strings.Fields(b.Config.Mattermost.IgnoreNicks)
 | 
			
		||||
	if kind == Legacy {
 | 
			
		||||
		if len(b.Config.Token) > 0 {
 | 
			
		||||
			for _, val := range b.Config.Token {
 | 
			
		||||
				b.ircMap[val.IRCChannel] = val.MMChannel
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		b.mh = matterhook.New(b.Config.Mattermost.URL,
 | 
			
		||||
			matterhook.Config{Port: b.Config.Mattermost.Port, Token: b.Config.Mattermost.Token,
 | 
			
		||||
				InsecureSkipVerify: b.Config.Mattermost.SkipTLSVerify,
 | 
			
		||||
				BindAddress:        b.Config.Mattermost.BindAddress})
 | 
			
		||||
	} else {
 | 
			
		||||
		b.mmMap = make(map[string]string)
 | 
			
		||||
		if len(b.Config.Channel) > 0 {
 | 
			
		||||
			for _, val := range b.Config.Channel {
 | 
			
		||||
				b.ircMap[val.IRC] = val.Mattermost
 | 
			
		||||
				b.mmMap[val.Mattermost] = val.IRC
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		b.mc = matterclient.New(b.Config.Mattermost.Login, b.Config.Mattermost.Password,
 | 
			
		||||
			b.Config.Mattermost.Team, b.Config.Mattermost.Server)
 | 
			
		||||
		b.mc.SkipTLSVerify = b.Config.Mattermost.SkipTLSVerify
 | 
			
		||||
		b.mc.NoTLS = b.Config.Mattermost.NoTLS
 | 
			
		||||
		flog.mm.Infof("Trying login %s (team: %s) on %s", b.Config.Mattermost.Login, b.Config.Mattermost.Team, b.Config.Mattermost.Server)
 | 
			
		||||
		err := b.mc.Login()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			flog.mm.Fatal("Can not connect", err)
 | 
			
		||||
		}
 | 
			
		||||
		flog.mm.Info("Login ok")
 | 
			
		||||
		b.mc.JoinChannel(b.Config.Mattermost.Channel)
 | 
			
		||||
		if len(b.Config.Channel) > 0 {
 | 
			
		||||
			for _, val := range b.Config.Channel {
 | 
			
		||||
				b.mc.JoinChannel(val.Mattermost)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		go b.mc.WsReceiver()
 | 
			
		||||
	}
 | 
			
		||||
	flog.irc.Info("Trying IRC connection")
 | 
			
		||||
	b.i = b.createIRC(name)
 | 
			
		||||
	flog.irc.Info("Connection succeeded")
 | 
			
		||||
	go b.handleMatter()
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) createIRC(name string) *irc.Connection {
 | 
			
		||||
	i := irc.IRC(b.Config.IRC.Nick, b.Config.IRC.Nick)
 | 
			
		||||
	i.UseTLS = b.Config.IRC.UseTLS
 | 
			
		||||
	i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.IRC.SkipTLSVerify}
 | 
			
		||||
	if b.Config.IRC.Password != "" {
 | 
			
		||||
		i.Password = b.Config.IRC.Password
 | 
			
		||||
	}
 | 
			
		||||
	i.AddCallback(ircm.RPL_WELCOME, b.handleNewConnection)
 | 
			
		||||
	i.Connect(b.Config.IRC.Server + ":" + strconv.Itoa(b.Config.IRC.Port))
 | 
			
		||||
	return i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleNewConnection(event *irc.Event) {
 | 
			
		||||
	flog.irc.Info("Registering callbacks")
 | 
			
		||||
	i := b.i
 | 
			
		||||
	b.ircNick = event.Arguments[0]
 | 
			
		||||
	i.AddCallback("PRIVMSG", b.handlePrivMsg)
 | 
			
		||||
	i.AddCallback("CTCP_ACTION", b.handlePrivMsg)
 | 
			
		||||
	i.AddCallback(ircm.RPL_ENDOFNAMES, b.endNames)
 | 
			
		||||
	i.AddCallback(ircm.RPL_NAMREPLY, b.storeNames)
 | 
			
		||||
	i.AddCallback(ircm.RPL_TOPICWHOTIME, b.handleTopicWhoTime)
 | 
			
		||||
	i.AddCallback(ircm.NOTICE, b.handleNotice)
 | 
			
		||||
	i.AddCallback(ircm.RPL_MYINFO, func(e *irc.Event) { flog.irc.Infof("%s: %s", e.Code, strings.Join(e.Arguments[1:], " ")) })
 | 
			
		||||
	i.AddCallback("PING", func(e *irc.Event) {
 | 
			
		||||
		i.SendRaw("PONG :" + e.Message())
 | 
			
		||||
		flog.irc.Debugf("PING/PONG")
 | 
			
		||||
	})
 | 
			
		||||
	if b.Config.Mattermost.ShowJoinPart {
 | 
			
		||||
		i.AddCallback("JOIN", b.handleJoinPart)
 | 
			
		||||
		i.AddCallback("PART", b.handleJoinPart)
 | 
			
		||||
	}
 | 
			
		||||
	i.AddCallback("*", b.handleOther)
 | 
			
		||||
	b.setupChannels()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) setupChannels() {
 | 
			
		||||
	i := b.i
 | 
			
		||||
	if b.Config.IRC.Channel != "" {
 | 
			
		||||
		flog.irc.Infof("Joining %s as %s", b.Config.IRC.Channel, b.ircNick)
 | 
			
		||||
		i.Join(b.Config.IRC.Channel)
 | 
			
		||||
	}
 | 
			
		||||
	if b.kind == Legacy {
 | 
			
		||||
		for _, val := range b.Config.Token {
 | 
			
		||||
			flog.irc.Infof("Joining %s as %s", val.IRCChannel, b.ircNick)
 | 
			
		||||
			i.Join(val.IRCChannel)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, val := range b.Config.Channel {
 | 
			
		||||
			flog.irc.Infof("Joining %s as %s", val.IRC, b.ircNick)
 | 
			
		||||
			i.Join(val.IRC)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleIrcBotCommand(event *irc.Event) bool {
 | 
			
		||||
	parts := strings.Fields(event.Message())
 | 
			
		||||
	exp, _ := regexp.Compile("[:,]+$")
 | 
			
		||||
	channel := event.Arguments[0]
 | 
			
		||||
	command := ""
 | 
			
		||||
	if len(parts) == 2 {
 | 
			
		||||
		command = parts[1]
 | 
			
		||||
	}
 | 
			
		||||
	if exp.ReplaceAllString(parts[0], "") == b.ircNick {
 | 
			
		||||
		switch command {
 | 
			
		||||
		case "users":
 | 
			
		||||
			usernames := b.mc.UsernamesInChannel(b.getMMChannel(channel))
 | 
			
		||||
			sort.Strings(usernames)
 | 
			
		||||
			b.i.Privmsg(channel, "Users on Mattermost: "+strings.Join(usernames, ", "))
 | 
			
		||||
		default:
 | 
			
		||||
			b.i.Privmsg(channel, "Valid commands are: [users, help]")
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) ircNickFormat(nick string) string {
 | 
			
		||||
	if nick == b.ircNick {
 | 
			
		||||
		return nick
 | 
			
		||||
	}
 | 
			
		||||
	if b.Config.Mattermost.RemoteNickFormat == nil {
 | 
			
		||||
		return "irc-" + nick
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Replace(*b.Config.Mattermost.RemoteNickFormat, "{NICK}", nick, -1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handlePrivMsg(event *irc.Event) {
 | 
			
		||||
	if b.ignoreMessage(event.Nick, event.Message(), "irc") {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if b.handleIrcBotCommand(event) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	msg := ""
 | 
			
		||||
	if event.Code == "CTCP_ACTION" {
 | 
			
		||||
		msg = event.Nick + " "
 | 
			
		||||
	}
 | 
			
		||||
	msg += event.Message()
 | 
			
		||||
	b.Send(b.ircNickFormat(event.Nick), msg, b.getMMChannel(event.Arguments[0]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleJoinPart(event *irc.Event) {
 | 
			
		||||
	b.Send(b.ircNick, b.ircNickFormat(event.Nick)+" "+strings.ToLower(event.Code)+"s "+event.Message(), b.getMMChannel(event.Arguments[0]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleNotice(event *irc.Event) {
 | 
			
		||||
	if strings.Contains(event.Message(), "This nickname is registered") {
 | 
			
		||||
		b.i.Privmsg(b.Config.IRC.NickServNick, "IDENTIFY "+b.Config.IRC.NickServPassword)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) nicksPerRow() int {
 | 
			
		||||
	if b.Config.Mattermost.NicksPerRow < 1 {
 | 
			
		||||
		return 4
 | 
			
		||||
	}
 | 
			
		||||
	return b.Config.Mattermost.NicksPerRow
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) formatnicks(nicks []string, continued bool) string {
 | 
			
		||||
	switch b.Config.Mattermost.NickFormatter {
 | 
			
		||||
	case "table":
 | 
			
		||||
		return tableformatter(nicks, b.nicksPerRow(), continued)
 | 
			
		||||
	default:
 | 
			
		||||
		return plainformatter(nicks, b.nicksPerRow())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) storeNames(event *irc.Event) {
 | 
			
		||||
	channel := event.Arguments[2]
 | 
			
		||||
	b.MMirc.names[channel] = append(
 | 
			
		||||
		b.MMirc.names[channel],
 | 
			
		||||
		strings.Split(strings.TrimSpace(event.Message()), " ")...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) endNames(event *irc.Event) {
 | 
			
		||||
	channel := event.Arguments[1]
 | 
			
		||||
	sort.Strings(b.MMirc.names[channel])
 | 
			
		||||
	maxNamesPerPost := (300 / b.nicksPerRow()) * b.nicksPerRow()
 | 
			
		||||
	continued := false
 | 
			
		||||
	for len(b.MMirc.names[channel]) > maxNamesPerPost {
 | 
			
		||||
		b.Send(
 | 
			
		||||
			b.ircNick,
 | 
			
		||||
			b.formatnicks(b.MMirc.names[channel][0:maxNamesPerPost], continued),
 | 
			
		||||
			b.getMMChannel(channel))
 | 
			
		||||
		b.MMirc.names[channel] = b.MMirc.names[channel][maxNamesPerPost:]
 | 
			
		||||
		continued = true
 | 
			
		||||
	}
 | 
			
		||||
	b.Send(b.ircNick, b.formatnicks(b.MMirc.names[channel], continued), b.getMMChannel(channel))
 | 
			
		||||
	b.MMirc.names[channel] = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleTopicWhoTime(event *irc.Event) {
 | 
			
		||||
	parts := strings.Split(event.Arguments[2], "!")
 | 
			
		||||
	t, err := strconv.ParseInt(event.Arguments[3], 10, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		flog.irc.Errorf("Invalid time stamp: %s", event.Arguments[3])
 | 
			
		||||
	}
 | 
			
		||||
	user := parts[0]
 | 
			
		||||
	if len(parts) > 1 {
 | 
			
		||||
		user += " [" + parts[1] + "]"
 | 
			
		||||
	}
 | 
			
		||||
	flog.irc.Infof("%s: Topic set by %s [%s]", event.Code, user, time.Unix(t, 0))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleOther(event *irc.Event) {
 | 
			
		||||
	flog.irc.Debugf("%#v", event)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) Send(nick string, message string, channel string) error {
 | 
			
		||||
	return b.SendType(nick, message, channel, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) SendType(nick string, message string, channel string, mtype string) error {
 | 
			
		||||
	if b.Config.Mattermost.PrefixMessagesWithNick {
 | 
			
		||||
		if IsMarkup(message) {
 | 
			
		||||
			message = nick + "\n\n" + message
 | 
			
		||||
		} else {
 | 
			
		||||
			message = nick + " " + message
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if b.kind == Legacy {
 | 
			
		||||
		matterMessage := matterhook.OMessage{IconURL: b.Config.Mattermost.IconURL}
 | 
			
		||||
		matterMessage.Channel = channel
 | 
			
		||||
		matterMessage.UserName = nick
 | 
			
		||||
		matterMessage.Type = mtype
 | 
			
		||||
		matterMessage.Text = message
 | 
			
		||||
		err := b.mh.Send(matterMessage)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			flog.mm.Info(err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	flog.mm.Debug("->mattermost channel: ", channel, " ", message)
 | 
			
		||||
	b.mc.PostMessage(channel, message)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleMatterHook(mchan chan *MMMessage) {
 | 
			
		||||
	for {
 | 
			
		||||
		message := b.mh.Receive()
 | 
			
		||||
		m := &MMMessage{}
 | 
			
		||||
		m.Username = message.UserName
 | 
			
		||||
		m.Text = message.Text
 | 
			
		||||
		m.Channel = message.Token
 | 
			
		||||
		mchan <- m
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleMatterClient(mchan chan *MMMessage) {
 | 
			
		||||
	for message := range b.mc.MessageChan {
 | 
			
		||||
		// do not post our own messages back to irc
 | 
			
		||||
		if message.Raw.Action == "posted" && b.mc.User.Username != message.Username {
 | 
			
		||||
			m := &MMMessage{}
 | 
			
		||||
			m.Username = message.Username
 | 
			
		||||
			m.Channel = message.Channel
 | 
			
		||||
			m.Text = message.Text
 | 
			
		||||
			flog.mm.Debugf("<-mattermost channel: %s %#v %#v", message.Channel, message.Post, message.Raw)
 | 
			
		||||
			mchan <- m
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) handleMatter() {
 | 
			
		||||
	flog.mm.Infof("Choosing Mattermost connection type %s", b.kind)
 | 
			
		||||
	mchan := make(chan *MMMessage)
 | 
			
		||||
	if b.kind == Legacy {
 | 
			
		||||
		go b.handleMatterHook(mchan)
 | 
			
		||||
	} else {
 | 
			
		||||
		go b.handleMatterClient(mchan)
 | 
			
		||||
	}
 | 
			
		||||
	flog.mm.Info("Start listening for Mattermost messages")
 | 
			
		||||
	for message := range mchan {
 | 
			
		||||
		var username string
 | 
			
		||||
		if b.ignoreMessage(message.Username, message.Text, "mattermost") {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		username = message.Username + ": "
 | 
			
		||||
		if b.Config.IRC.RemoteNickFormat != "" {
 | 
			
		||||
			username = strings.Replace(b.Config.IRC.RemoteNickFormat, "{NICK}", message.Username, -1)
 | 
			
		||||
		} else if b.Config.IRC.UseSlackCircumfix {
 | 
			
		||||
			username = "<" + message.Username + "> "
 | 
			
		||||
		}
 | 
			
		||||
		cmds := strings.Fields(message.Text)
 | 
			
		||||
		// empty message
 | 
			
		||||
		if len(cmds) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		cmd := cmds[0]
 | 
			
		||||
		switch cmd {
 | 
			
		||||
		case "!users":
 | 
			
		||||
			flog.mm.Info("Received !users from ", message.Username)
 | 
			
		||||
			b.i.SendRaw("NAMES " + b.getIRCChannel(message.Channel))
 | 
			
		||||
			continue
 | 
			
		||||
		case "!gif":
 | 
			
		||||
			message.Text = b.giphyRandom(strings.Fields(strings.Replace(message.Text, "!gif ", "", 1)))
 | 
			
		||||
			b.Send(b.ircNick, message.Text, b.getIRCChannel(message.Channel))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		texts := strings.Split(message.Text, "\n")
 | 
			
		||||
		for _, text := range texts {
 | 
			
		||||
			flog.mm.Debug("Sending message from " + message.Username + " to " + message.Channel)
 | 
			
		||||
			b.i.Privmsg(b.getIRCChannel(message.Channel), username+text)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) giphyRandom(query []string) string {
 | 
			
		||||
	g := giphy.DefaultClient
 | 
			
		||||
	if b.Config.General.GiphyAPIKey != "" {
 | 
			
		||||
		g.APIKey = b.Config.General.GiphyAPIKey
 | 
			
		||||
	}
 | 
			
		||||
	res, err := g.Random(query)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "error"
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data.FixedHeightDownsampledURL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) getMMChannel(ircChannel string) string {
 | 
			
		||||
	mmchannel, ok := b.ircMap[ircChannel]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		mmchannel = b.Config.Mattermost.Channel
 | 
			
		||||
	}
 | 
			
		||||
	return mmchannel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) getIRCChannel(channel string) string {
 | 
			
		||||
	if b.kind == Legacy {
 | 
			
		||||
		ircchannel := b.Config.IRC.Channel
 | 
			
		||||
		_, ok := b.Config.Token[channel]
 | 
			
		||||
		if ok {
 | 
			
		||||
			ircchannel = b.Config.Token[channel].IRCChannel
 | 
			
		||||
		}
 | 
			
		||||
		return ircchannel
 | 
			
		||||
	}
 | 
			
		||||
	ircchannel, ok := b.mmMap[channel]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		ircchannel = b.Config.IRC.Channel
 | 
			
		||||
	}
 | 
			
		||||
	return ircchannel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) ignoreMessage(nick string, message string, protocol string) bool {
 | 
			
		||||
	var ignoreNicks = b.mmIgnoreNicks
 | 
			
		||||
	if protocol == "irc" {
 | 
			
		||||
		ignoreNicks = b.ircIgnoreNicks
 | 
			
		||||
	}
 | 
			
		||||
	// should we discard messages ?
 | 
			
		||||
	for _, entry := range ignoreNicks {
 | 
			
		||||
		if nick == entry {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package bridge
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"gopkg.in/gcfg.v1"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	IRC struct {
 | 
			
		||||
		UseTLS            bool
 | 
			
		||||
		SkipTLSVerify     bool
 | 
			
		||||
		Server            string
 | 
			
		||||
		Port              int
 | 
			
		||||
		Nick              string
 | 
			
		||||
		Password          string
 | 
			
		||||
		Channel           string
 | 
			
		||||
		UseSlackCircumfix bool
 | 
			
		||||
		NickServNick      string
 | 
			
		||||
		NickServPassword  string
 | 
			
		||||
		RemoteNickFormat  string
 | 
			
		||||
		IgnoreNicks       string
 | 
			
		||||
	}
 | 
			
		||||
	Mattermost struct {
 | 
			
		||||
		URL                    string
 | 
			
		||||
		Port                   int
 | 
			
		||||
		ShowJoinPart           bool
 | 
			
		||||
		Token                  string
 | 
			
		||||
		IconURL                string
 | 
			
		||||
		SkipTLSVerify          bool
 | 
			
		||||
		BindAddress            string
 | 
			
		||||
		Channel                string
 | 
			
		||||
		PrefixMessagesWithNick bool
 | 
			
		||||
		NicksPerRow            int
 | 
			
		||||
		NickFormatter          string
 | 
			
		||||
		Server                 string
 | 
			
		||||
		Team                   string
 | 
			
		||||
		Login                  string
 | 
			
		||||
		Password               string
 | 
			
		||||
		RemoteNickFormat       *string
 | 
			
		||||
		IgnoreNicks            string
 | 
			
		||||
		NoTLS                  bool
 | 
			
		||||
	}
 | 
			
		||||
	Token map[string]*struct {
 | 
			
		||||
		IRCChannel string
 | 
			
		||||
		MMChannel  string
 | 
			
		||||
	}
 | 
			
		||||
	Channel map[string]*struct {
 | 
			
		||||
		IRC        string
 | 
			
		||||
		Mattermost string
 | 
			
		||||
	}
 | 
			
		||||
	General struct {
 | 
			
		||||
		GiphyAPIKey string
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewConfig(cfgfile string) *Config {
 | 
			
		||||
	var cfg Config
 | 
			
		||||
	content, err := ioutil.ReadFile(cfgfile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = gcfg.ReadStringInto(&cfg, string(content))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("Failed to parse "+cfgfile+":", err)
 | 
			
		||||
	}
 | 
			
		||||
	return &cfg
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/helper.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/42wim/matterbridge-plus/bridge/helper.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
package bridge
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func tableformatter(nicks []string, nicksPerRow int, continued bool) string {
 | 
			
		||||
	result := "|IRC users"
 | 
			
		||||
	if continued {
 | 
			
		||||
		result = "|(continued)"
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < 2; i++ {
 | 
			
		||||
		for j := 1; j <= nicksPerRow && j <= len(nicks); j++ {
 | 
			
		||||
			if i == 0 {
 | 
			
		||||
				result += "|"
 | 
			
		||||
			} else {
 | 
			
		||||
				result += ":-|"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		result += "\r\n|"
 | 
			
		||||
	}
 | 
			
		||||
	result += nicks[0] + "|"
 | 
			
		||||
	for i := 1; i < len(nicks); i++ {
 | 
			
		||||
		if i%nicksPerRow == 0 {
 | 
			
		||||
			result += "\r\n|" + nicks[i] + "|"
 | 
			
		||||
		} else {
 | 
			
		||||
			result += nicks[i] + "|"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func plainformatter(nicks []string, nicksPerRow int) string {
 | 
			
		||||
	return strings.Join(nicks, ", ") + " currently on IRC"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsMarkup(message string) bool {
 | 
			
		||||
	switch message[0] {
 | 
			
		||||
	case '|':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '#':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '_':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '*':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '~':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '-':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case ':':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '>':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case '=':
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										202
									
								
								vendor/github.com/42wim/matterbridge-plus/matterclient/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/42wim/matterbridge-plus/matterclient/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "{}"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright {yyyy} {name of copyright owner}
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										441
									
								
								vendor/github.com/42wim/matterbridge-plus/matterclient/matterclient.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										441
									
								
								vendor/github.com/42wim/matterbridge-plus/matterclient/matterclient.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,441 @@
 | 
			
		||||
package matterclient
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"errors"
 | 
			
		||||
	log "github.com/Sirupsen/logrus"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/cookiejar"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
	"github.com/jpillora/backoff"
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Credentials struct {
 | 
			
		||||
	Login         string
 | 
			
		||||
	Team          string
 | 
			
		||||
	Pass          string
 | 
			
		||||
	Server        string
 | 
			
		||||
	NoTLS         bool
 | 
			
		||||
	SkipTLSVerify bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Message struct {
 | 
			
		||||
	Raw      *model.Message
 | 
			
		||||
	Post     *model.Post
 | 
			
		||||
	Team     string
 | 
			
		||||
	Channel  string
 | 
			
		||||
	Username string
 | 
			
		||||
	Text     string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MMClient struct {
 | 
			
		||||
	*Credentials
 | 
			
		||||
	Client       *model.Client
 | 
			
		||||
	WsClient     *websocket.Conn
 | 
			
		||||
	WsQuit       bool
 | 
			
		||||
	WsAway       bool
 | 
			
		||||
	Channels     *model.ChannelList
 | 
			
		||||
	MoreChannels *model.ChannelList
 | 
			
		||||
	User         *model.User
 | 
			
		||||
	Users        map[string]*model.User
 | 
			
		||||
	MessageChan  chan *Message
 | 
			
		||||
	Team         *model.Team
 | 
			
		||||
	log          *log.Entry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(login, pass, team, server string) *MMClient {
 | 
			
		||||
	cred := &Credentials{Login: login, Pass: pass, Team: team, Server: server}
 | 
			
		||||
	mmclient := &MMClient{Credentials: cred, MessageChan: make(chan *Message, 100)}
 | 
			
		||||
	mmclient.log = log.WithFields(log.Fields{"module": "matterclient"})
 | 
			
		||||
	log.SetFormatter(&log.TextFormatter{FullTimestamp: true})
 | 
			
		||||
	return mmclient
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) SetLogLevel(level string) {
 | 
			
		||||
	l, err := log.ParseLevel(level)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.SetLevel(log.InfoLevel)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	log.SetLevel(l)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) Login() error {
 | 
			
		||||
	if m.WsQuit {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	b := &backoff.Backoff{
 | 
			
		||||
		Min:    time.Second,
 | 
			
		||||
		Max:    5 * time.Minute,
 | 
			
		||||
		Jitter: true,
 | 
			
		||||
	}
 | 
			
		||||
	uriScheme := "https://"
 | 
			
		||||
	wsScheme := "wss://"
 | 
			
		||||
	if m.NoTLS {
 | 
			
		||||
		uriScheme = "http://"
 | 
			
		||||
		wsScheme = "ws://"
 | 
			
		||||
	}
 | 
			
		||||
	// login to mattermost
 | 
			
		||||
	m.Client = model.NewClient(uriScheme + m.Credentials.Server)
 | 
			
		||||
	m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
 | 
			
		||||
	var myinfo *model.Result
 | 
			
		||||
	var appErr *model.AppError
 | 
			
		||||
	var logmsg = "trying login"
 | 
			
		||||
	for {
 | 
			
		||||
		m.log.Debugf("%s %s %s %s", logmsg, m.Credentials.Team, m.Credentials.Login, m.Credentials.Server)
 | 
			
		||||
		if strings.Contains(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN) {
 | 
			
		||||
			m.log.Debugf(logmsg+" with ", model.SESSION_COOKIE_TOKEN)
 | 
			
		||||
			token := strings.Split(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN+"=")
 | 
			
		||||
			m.Client.HttpClient.Jar = m.createCookieJar(token[1])
 | 
			
		||||
			m.Client.MockSession(token[1])
 | 
			
		||||
			myinfo, appErr = m.Client.GetMe("")
 | 
			
		||||
			if myinfo.Data.(*model.User) == nil {
 | 
			
		||||
				m.log.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass)
 | 
			
		||||
				return errors.New("invalid " + model.SESSION_COOKIE_TOKEN)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			myinfo, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
 | 
			
		||||
		}
 | 
			
		||||
		if appErr != nil {
 | 
			
		||||
			d := b.Duration()
 | 
			
		||||
			m.log.Debug(appErr.DetailedError)
 | 
			
		||||
			if !strings.Contains(appErr.DetailedError, "connection refused") &&
 | 
			
		||||
				!strings.Contains(appErr.DetailedError, "invalid character") {
 | 
			
		||||
				if appErr.Message == "" {
 | 
			
		||||
					return errors.New(appErr.DetailedError)
 | 
			
		||||
				}
 | 
			
		||||
				return errors.New(appErr.Message)
 | 
			
		||||
			}
 | 
			
		||||
			m.log.Debugf("LOGIN: %s, reconnecting in %s", appErr, d)
 | 
			
		||||
			time.Sleep(d)
 | 
			
		||||
			logmsg = "retrying login"
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	// reset timer
 | 
			
		||||
	b.Reset()
 | 
			
		||||
 | 
			
		||||
	initLoad, _ := m.Client.GetInitialLoad()
 | 
			
		||||
	initData := initLoad.Data.(*model.InitialLoad)
 | 
			
		||||
	m.User = initData.User
 | 
			
		||||
	for _, v := range initData.Teams {
 | 
			
		||||
		m.log.Debugf("trying %s (id: %s)", v.Name, v.Id)
 | 
			
		||||
		if v.Name == m.Credentials.Team {
 | 
			
		||||
			m.Client.SetTeamId(v.Id)
 | 
			
		||||
			m.Team = v
 | 
			
		||||
			m.log.Debugf("GetallTeamListings: found id %s for team %s", v.Id, v.Name)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if m.Team == nil {
 | 
			
		||||
		return errors.New("team not found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// setup websocket connection
 | 
			
		||||
	wsurl := wsScheme + m.Credentials.Server + "/api/v3/users/websocket"
 | 
			
		||||
	header := http.Header{}
 | 
			
		||||
	header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken)
 | 
			
		||||
 | 
			
		||||
	m.log.Debug("WsClient: making connection")
 | 
			
		||||
	var err error
 | 
			
		||||
	for {
 | 
			
		||||
		wsDialer := &websocket.Dialer{Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
 | 
			
		||||
		m.WsClient, _, err = wsDialer.Dial(wsurl, header)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			d := b.Duration()
 | 
			
		||||
			m.log.Debugf("WSS: %s, reconnecting in %s", err, d)
 | 
			
		||||
			time.Sleep(d)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	b.Reset()
 | 
			
		||||
 | 
			
		||||
	// populating users
 | 
			
		||||
	m.UpdateUsers()
 | 
			
		||||
 | 
			
		||||
	// populating channels
 | 
			
		||||
	m.UpdateChannels()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) WsReceiver() {
 | 
			
		||||
	var rmsg model.Message
 | 
			
		||||
	for {
 | 
			
		||||
		if m.WsQuit {
 | 
			
		||||
			m.log.Debug("exiting WsReceiver")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if err := m.WsClient.ReadJSON(&rmsg); err != nil {
 | 
			
		||||
			m.log.Error("error:", err)
 | 
			
		||||
			// reconnect
 | 
			
		||||
			m.Login()
 | 
			
		||||
		}
 | 
			
		||||
		if rmsg.Action == "ping" {
 | 
			
		||||
			m.handleWsPing()
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		msg := &Message{Raw: &rmsg, Team: m.Credentials.Team}
 | 
			
		||||
		m.parseMessage(msg)
 | 
			
		||||
		m.MessageChan <- msg
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) handleWsPing() {
 | 
			
		||||
	m.log.Debug("Ws PING")
 | 
			
		||||
	if !m.WsQuit && !m.WsAway {
 | 
			
		||||
		m.log.Debug("Ws PONG")
 | 
			
		||||
		m.WsClient.WriteMessage(websocket.PongMessage, []byte{})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) parseMessage(rmsg *Message) {
 | 
			
		||||
	switch rmsg.Raw.Action {
 | 
			
		||||
	case model.ACTION_POSTED:
 | 
			
		||||
		m.parseActionPost(rmsg)
 | 
			
		||||
		/*
 | 
			
		||||
			case model.ACTION_USER_REMOVED:
 | 
			
		||||
				m.handleWsActionUserRemoved(&rmsg)
 | 
			
		||||
			case model.ACTION_USER_ADDED:
 | 
			
		||||
				m.handleWsActionUserAdded(&rmsg)
 | 
			
		||||
		*/
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) parseActionPost(rmsg *Message) {
 | 
			
		||||
	data := model.PostFromJson(strings.NewReader(rmsg.Raw.Props["post"]))
 | 
			
		||||
	//	log.Println("receiving userid", data.UserId)
 | 
			
		||||
	// we don't have the user, refresh the userlist
 | 
			
		||||
	if m.Users[data.UserId] == nil {
 | 
			
		||||
		m.UpdateUsers()
 | 
			
		||||
	}
 | 
			
		||||
	rmsg.Username = m.Users[data.UserId].Username
 | 
			
		||||
	rmsg.Channel = m.GetChannelName(data.ChannelId)
 | 
			
		||||
	// direct message
 | 
			
		||||
	if strings.Contains(rmsg.Channel, "__") {
 | 
			
		||||
		//log.Println("direct message")
 | 
			
		||||
		rcvusers := strings.Split(rmsg.Channel, "__")
 | 
			
		||||
		if rcvusers[0] != m.User.Id {
 | 
			
		||||
			rmsg.Channel = m.Users[rcvusers[0]].Username
 | 
			
		||||
		} else {
 | 
			
		||||
			rmsg.Channel = m.Users[rcvusers[1]].Username
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	rmsg.Text = data.Message
 | 
			
		||||
	rmsg.Post = data
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) UpdateUsers() error {
 | 
			
		||||
	mmusers, _ := m.Client.GetProfilesForDirectMessageList(m.Team.Id)
 | 
			
		||||
	m.Users = mmusers.Data.(map[string]*model.User)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) UpdateChannels() error {
 | 
			
		||||
	mmchannels, _ := m.Client.GetChannels("")
 | 
			
		||||
	m.Channels = mmchannels.Data.(*model.ChannelList)
 | 
			
		||||
	mmchannels, _ = m.Client.GetMoreChannels("")
 | 
			
		||||
	m.MoreChannels = mmchannels.Data.(*model.ChannelList)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetChannelName(id string) string {
 | 
			
		||||
	for _, channel := range append(m.Channels.Channels, m.MoreChannels.Channels...) {
 | 
			
		||||
		if channel.Id == id {
 | 
			
		||||
			return channel.Name
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// not found? could be a new direct message from mattermost. Try to update and check again
 | 
			
		||||
	m.UpdateChannels()
 | 
			
		||||
	for _, channel := range append(m.Channels.Channels, m.MoreChannels.Channels...) {
 | 
			
		||||
		if channel.Id == id {
 | 
			
		||||
			return channel.Name
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetChannelId(name string) string {
 | 
			
		||||
	for _, channel := range append(m.Channels.Channels, m.MoreChannels.Channels...) {
 | 
			
		||||
		if channel.Name == name {
 | 
			
		||||
			return channel.Id
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetChannelHeader(id string) string {
 | 
			
		||||
	for _, channel := range append(m.Channels.Channels, m.MoreChannels.Channels...) {
 | 
			
		||||
		if channel.Id == id {
 | 
			
		||||
			return channel.Header
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) PostMessage(channel string, text string) {
 | 
			
		||||
	post := &model.Post{ChannelId: m.GetChannelId(channel), Message: text}
 | 
			
		||||
	m.Client.CreatePost(post)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) JoinChannel(channel string) error {
 | 
			
		||||
	cleanChan := strings.Replace(channel, "#", "", 1)
 | 
			
		||||
	if m.GetChannelId(cleanChan) == "" {
 | 
			
		||||
		return errors.New("failed to join")
 | 
			
		||||
	}
 | 
			
		||||
	for _, c := range m.Channels.Channels {
 | 
			
		||||
		if c.Name == cleanChan {
 | 
			
		||||
			m.log.Debug("Not joining ", cleanChan, " already joined.")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.log.Debug("Joining ", cleanChan)
 | 
			
		||||
	_, err := m.Client.JoinChannel(m.GetChannelId(cleanChan))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.New("failed to join")
 | 
			
		||||
	}
 | 
			
		||||
	//	m.SyncChannel(m.getMMChannelId(strings.Replace(channel, "#", "", 1)), strings.Replace(channel, "#", "", 1))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPostsSince(channelId string, time int64) *model.PostList {
 | 
			
		||||
	res, err := m.Client.GetPostsSince(channelId, time)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data.(*model.PostList)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) SearchPosts(query string) *model.PostList {
 | 
			
		||||
	res, err := m.Client.SearchPosts(query, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data.(*model.PostList)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList {
 | 
			
		||||
	res, err := m.Client.GetPosts(channelId, 0, limit, "")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data.(*model.PostList)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPublicLink(filename string) string {
 | 
			
		||||
	res, err := m.Client.GetPublicLink(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data.(string)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetPublicLinks(filenames []string) []string {
 | 
			
		||||
	var output []string
 | 
			
		||||
	for _, f := range filenames {
 | 
			
		||||
		res, err := m.Client.GetPublicLink(f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		output = append(output, res.Data.(string))
 | 
			
		||||
	}
 | 
			
		||||
	return output
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
 | 
			
		||||
	data := make(map[string]string)
 | 
			
		||||
	data["channel_id"] = channelId
 | 
			
		||||
	data["channel_header"] = header
 | 
			
		||||
	m.log.Debugf("updating channelheader %#v, %#v", channelId, header)
 | 
			
		||||
	_, err := m.Client.UpdateChannelHeader(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) UpdateLastViewed(channelId string) {
 | 
			
		||||
	m.log.Debugf("posting lastview %#v", channelId)
 | 
			
		||||
	_, err := m.Client.UpdateLastViewedAt(channelId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		m.log.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) UsernamesInChannel(channelName string) []string {
 | 
			
		||||
	ceiRes, err := m.Client.GetChannelExtraInfo(m.GetChannelId(channelName), 5000, "")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelName, err)
 | 
			
		||||
		return []string{}
 | 
			
		||||
	}
 | 
			
		||||
	extra := ceiRes.Data.(*model.ChannelExtra)
 | 
			
		||||
	result := []string{}
 | 
			
		||||
	for _, member := range extra.Members {
 | 
			
		||||
		result = append(result, member.Username)
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) createCookieJar(token string) *cookiejar.Jar {
 | 
			
		||||
	var cookies []*http.Cookie
 | 
			
		||||
	jar, _ := cookiejar.New(nil)
 | 
			
		||||
	firstCookie := &http.Cookie{
 | 
			
		||||
		Name:   "MMAUTHTOKEN",
 | 
			
		||||
		Value:  token,
 | 
			
		||||
		Path:   "/",
 | 
			
		||||
		Domain: m.Credentials.Server,
 | 
			
		||||
	}
 | 
			
		||||
	cookies = append(cookies, firstCookie)
 | 
			
		||||
	cookieURL, _ := url.Parse("https://" + m.Credentials.Server)
 | 
			
		||||
	jar.SetCookies(cookieURL, cookies)
 | 
			
		||||
	return jar
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) GetOtherUserDM(channel string) *model.User {
 | 
			
		||||
	m.UpdateUsers()
 | 
			
		||||
	var rcvuser *model.User
 | 
			
		||||
	if strings.Contains(channel, "__") {
 | 
			
		||||
		rcvusers := strings.Split(channel, "__")
 | 
			
		||||
		if rcvusers[0] != m.User.Id {
 | 
			
		||||
			rcvuser = m.Users[rcvusers[0]]
 | 
			
		||||
		} else {
 | 
			
		||||
			rcvuser = m.Users[rcvusers[1]]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return rcvuser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MMClient) SendDirectMessage(toUserId string, msg string) {
 | 
			
		||||
	m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
 | 
			
		||||
	var channel string
 | 
			
		||||
	// We don't have a DM with this user yet.
 | 
			
		||||
	if m.GetChannelId(toUserId+"__"+m.User.Id) == "" && m.GetChannelId(m.User.Id+"__"+toUserId) == "" {
 | 
			
		||||
		// create DM channel
 | 
			
		||||
		_, err := m.Client.CreateDirectChannel(toUserId)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, err)
 | 
			
		||||
		}
 | 
			
		||||
		// update our channels
 | 
			
		||||
		mmchannels, _ := m.Client.GetChannels("")
 | 
			
		||||
		m.Channels = mmchannels.Data.(*model.ChannelList)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// build the channel name
 | 
			
		||||
	if toUserId > m.User.Id {
 | 
			
		||||
		channel = m.User.Id + "__" + toUserId
 | 
			
		||||
	} else {
 | 
			
		||||
		channel = toUserId + "__" + m.User.Id
 | 
			
		||||
	}
 | 
			
		||||
	// build & send the message
 | 
			
		||||
	msg = strings.Replace(msg, "\r", "", -1)
 | 
			
		||||
	post := &model.Post{ChannelId: m.GetChannelId(channel), Message: msg}
 | 
			
		||||
	m.Client.CreatePost(post)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/Sirupsen/logrus/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/Sirupsen/logrus/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2014 Simon Eskildsen
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/Sirupsen/logrus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/Sirupsen/logrus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/*
 | 
			
		||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The simplest way to use Logrus is simply the package-level exported logger:
 | 
			
		||||
 | 
			
		||||
  package main
 | 
			
		||||
 | 
			
		||||
  import (
 | 
			
		||||
    log "github.com/Sirupsen/logrus"
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  func main() {
 | 
			
		||||
    log.WithFields(log.Fields{
 | 
			
		||||
      "animal": "walrus",
 | 
			
		||||
      "number": 1,
 | 
			
		||||
      "size":   10,
 | 
			
		||||
    }).Info("A walrus appears")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
  time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
 | 
			
		||||
 | 
			
		||||
For a full guide visit https://github.com/Sirupsen/logrus
 | 
			
		||||
*/
 | 
			
		||||
package logrus
 | 
			
		||||
							
								
								
									
										264
									
								
								vendor/github.com/Sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/github.com/Sirupsen/logrus/entry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,264 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Defines the key when adding errors using WithError.
 | 
			
		||||
var ErrorKey = "error"
 | 
			
		||||
 | 
			
		||||
// An entry is the final or intermediate Logrus logging entry. It contains all
 | 
			
		||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
 | 
			
		||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
 | 
			
		||||
// passed around as much as you wish to avoid field duplication.
 | 
			
		||||
type Entry struct {
 | 
			
		||||
	Logger *Logger
 | 
			
		||||
 | 
			
		||||
	// Contains all the fields set by the user.
 | 
			
		||||
	Data Fields
 | 
			
		||||
 | 
			
		||||
	// Time at which the log entry was created
 | 
			
		||||
	Time time.Time
 | 
			
		||||
 | 
			
		||||
	// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
 | 
			
		||||
	Level Level
 | 
			
		||||
 | 
			
		||||
	// Message passed to Debug, Info, Warn, Error, Fatal or Panic
 | 
			
		||||
	Message string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewEntry(logger *Logger) *Entry {
 | 
			
		||||
	return &Entry{
 | 
			
		||||
		Logger: logger,
 | 
			
		||||
		// Default is three fields, give a little extra room
 | 
			
		||||
		Data: make(Fields, 5),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a reader for the entry, which is a proxy to the formatter.
 | 
			
		||||
func (entry *Entry) Reader() (*bytes.Buffer, error) {
 | 
			
		||||
	serialized, err := entry.Logger.Formatter.Format(entry)
 | 
			
		||||
	return bytes.NewBuffer(serialized), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns the string representation from the reader and ultimately the
 | 
			
		||||
// formatter.
 | 
			
		||||
func (entry *Entry) String() (string, error) {
 | 
			
		||||
	reader, err := entry.Reader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return reader.String(), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
 | 
			
		||||
func (entry *Entry) WithError(err error) *Entry {
 | 
			
		||||
	return entry.WithField(ErrorKey, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add a single field to the Entry.
 | 
			
		||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
 | 
			
		||||
	return entry.WithFields(Fields{key: value})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add a map of fields to the Entry.
 | 
			
		||||
func (entry *Entry) WithFields(fields Fields) *Entry {
 | 
			
		||||
	data := make(Fields, len(entry.Data)+len(fields))
 | 
			
		||||
	for k, v := range entry.Data {
 | 
			
		||||
		data[k] = v
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range fields {
 | 
			
		||||
		data[k] = v
 | 
			
		||||
	}
 | 
			
		||||
	return &Entry{Logger: entry.Logger, Data: data}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This function is not declared with a pointer value because otherwise
 | 
			
		||||
// race conditions will occur when using multiple goroutines
 | 
			
		||||
func (entry Entry) log(level Level, msg string) {
 | 
			
		||||
	entry.Time = time.Now()
 | 
			
		||||
	entry.Level = level
 | 
			
		||||
	entry.Message = msg
 | 
			
		||||
 | 
			
		||||
	if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
 | 
			
		||||
		entry.Logger.mu.Lock()
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
 | 
			
		||||
		entry.Logger.mu.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reader, err := entry.Reader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		entry.Logger.mu.Lock()
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
 | 
			
		||||
		entry.Logger.mu.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entry.Logger.mu.Lock()
 | 
			
		||||
	defer entry.Logger.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	_, err = io.Copy(entry.Logger.Out, reader)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// To avoid Entry#log() returning a value that only would make sense for
 | 
			
		||||
	// panic() to use in Entry#Panic(), we avoid the allocation by checking
 | 
			
		||||
	// directly here.
 | 
			
		||||
	if level <= PanicLevel {
 | 
			
		||||
		panic(&entry)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Debug(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= DebugLevel {
 | 
			
		||||
		entry.log(DebugLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Print(args ...interface{}) {
 | 
			
		||||
	entry.Info(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Info(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= InfoLevel {
 | 
			
		||||
		entry.log(InfoLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warn(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= WarnLevel {
 | 
			
		||||
		entry.log(WarnLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warning(args ...interface{}) {
 | 
			
		||||
	entry.Warn(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Error(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= ErrorLevel {
 | 
			
		||||
		entry.log(ErrorLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Fatal(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= FatalLevel {
 | 
			
		||||
		entry.log(FatalLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Panic(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= PanicLevel {
 | 
			
		||||
		entry.log(PanicLevel, fmt.Sprint(args...))
 | 
			
		||||
	}
 | 
			
		||||
	panic(fmt.Sprint(args...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Entry Printf family functions
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= DebugLevel {
 | 
			
		||||
		entry.Debug(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Infof(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= InfoLevel {
 | 
			
		||||
		entry.Info(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Printf(format string, args ...interface{}) {
 | 
			
		||||
	entry.Infof(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= WarnLevel {
 | 
			
		||||
		entry.Warn(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
 | 
			
		||||
	entry.Warnf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= ErrorLevel {
 | 
			
		||||
		entry.Error(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= FatalLevel {
 | 
			
		||||
		entry.Fatal(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= PanicLevel {
 | 
			
		||||
		entry.Panic(fmt.Sprintf(format, args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Entry Println family functions
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Debugln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= DebugLevel {
 | 
			
		||||
		entry.Debug(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Infoln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= InfoLevel {
 | 
			
		||||
		entry.Info(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Println(args ...interface{}) {
 | 
			
		||||
	entry.Infoln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warnln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= WarnLevel {
 | 
			
		||||
		entry.Warn(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Warningln(args ...interface{}) {
 | 
			
		||||
	entry.Warnln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Errorln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= ErrorLevel {
 | 
			
		||||
		entry.Error(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Fatalln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= FatalLevel {
 | 
			
		||||
		entry.Fatal(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entry *Entry) Panicln(args ...interface{}) {
 | 
			
		||||
	if entry.Logger.Level >= PanicLevel {
 | 
			
		||||
		entry.Panic(entry.sprintlnn(args...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
 | 
			
		||||
// fmt.Sprintln where spaces are always added between operands, regardless of
 | 
			
		||||
// their type. Instead of vendoring the Sprintln implementation to spare a
 | 
			
		||||
// string allocation, we do the simplest thing.
 | 
			
		||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
 | 
			
		||||
	msg := fmt.Sprintln(args...)
 | 
			
		||||
	return msg[:len(msg)-1]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var log = logrus.New()
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	log.Formatter = new(logrus.JSONFormatter)
 | 
			
		||||
	log.Formatter = new(logrus.TextFormatter) // default
 | 
			
		||||
	log.Level = logrus.DebugLevel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		err := recover()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.WithFields(logrus.Fields{
 | 
			
		||||
				"omg":    true,
 | 
			
		||||
				"err":    err,
 | 
			
		||||
				"number": 100,
 | 
			
		||||
			}).Fatal("The ice breaks!")
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"animal": "walrus",
 | 
			
		||||
		"number": 8,
 | 
			
		||||
	}).Debug("Started observing beach")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"animal": "walrus",
 | 
			
		||||
		"size":   10,
 | 
			
		||||
	}).Info("A group of walrus emerges from the ocean")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"omg":    true,
 | 
			
		||||
		"number": 122,
 | 
			
		||||
	}).Warn("The group's number increased tremendously!")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"temperature": -4,
 | 
			
		||||
	}).Debug("Temperature changes")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"animal": "orca",
 | 
			
		||||
		"size":   9009,
 | 
			
		||||
	}).Panic("It's over 9000!")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var log = logrus.New()
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	log.Formatter = new(logrus.TextFormatter) // default
 | 
			
		||||
	log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"animal": "walrus",
 | 
			
		||||
		"size":   10,
 | 
			
		||||
	}).Info("A group of walrus emerges from the ocean")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"omg":    true,
 | 
			
		||||
		"number": 122,
 | 
			
		||||
	}).Warn("The group's number increased tremendously!")
 | 
			
		||||
 | 
			
		||||
	log.WithFields(logrus.Fields{
 | 
			
		||||
		"omg":    true,
 | 
			
		||||
		"number": 100,
 | 
			
		||||
	}).Fatal("The ice breaks!")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										193
									
								
								vendor/github.com/Sirupsen/logrus/exported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/github.com/Sirupsen/logrus/exported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// std is the name of the standard logger in stdlib `log`
 | 
			
		||||
	std = New()
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func StandardLogger() *Logger {
 | 
			
		||||
	return std
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetOutput sets the standard logger output.
 | 
			
		||||
func SetOutput(out io.Writer) {
 | 
			
		||||
	std.mu.Lock()
 | 
			
		||||
	defer std.mu.Unlock()
 | 
			
		||||
	std.Out = out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetFormatter sets the standard logger formatter.
 | 
			
		||||
func SetFormatter(formatter Formatter) {
 | 
			
		||||
	std.mu.Lock()
 | 
			
		||||
	defer std.mu.Unlock()
 | 
			
		||||
	std.Formatter = formatter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLevel sets the standard logger level.
 | 
			
		||||
func SetLevel(level Level) {
 | 
			
		||||
	std.mu.Lock()
 | 
			
		||||
	defer std.mu.Unlock()
 | 
			
		||||
	std.Level = level
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetLevel returns the standard logger level.
 | 
			
		||||
func GetLevel() Level {
 | 
			
		||||
	std.mu.Lock()
 | 
			
		||||
	defer std.mu.Unlock()
 | 
			
		||||
	return std.Level
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddHook adds a hook to the standard logger hooks.
 | 
			
		||||
func AddHook(hook Hook) {
 | 
			
		||||
	std.mu.Lock()
 | 
			
		||||
	defer std.mu.Unlock()
 | 
			
		||||
	std.Hooks.Add(hook)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
 | 
			
		||||
func WithError(err error) *Entry {
 | 
			
		||||
	return std.WithField(ErrorKey, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithField creates an entry from the standard logger and adds a field to
 | 
			
		||||
// it. If you want multiple fields, use `WithFields`.
 | 
			
		||||
//
 | 
			
		||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
 | 
			
		||||
// or Panic on the Entry it returns.
 | 
			
		||||
func WithField(key string, value interface{}) *Entry {
 | 
			
		||||
	return std.WithField(key, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithFields creates an entry from the standard logger and adds multiple
 | 
			
		||||
// fields to it. This is simply a helper for `WithField`, invoking it
 | 
			
		||||
// once for each field.
 | 
			
		||||
//
 | 
			
		||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
 | 
			
		||||
// or Panic on the Entry it returns.
 | 
			
		||||
func WithFields(fields Fields) *Entry {
 | 
			
		||||
	return std.WithFields(fields)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debug logs a message at level Debug on the standard logger.
 | 
			
		||||
func Debug(args ...interface{}) {
 | 
			
		||||
	std.Debug(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Print logs a message at level Info on the standard logger.
 | 
			
		||||
func Print(args ...interface{}) {
 | 
			
		||||
	std.Print(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info logs a message at level Info on the standard logger.
 | 
			
		||||
func Info(args ...interface{}) {
 | 
			
		||||
	std.Info(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warn logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warn(args ...interface{}) {
 | 
			
		||||
	std.Warn(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warning logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warning(args ...interface{}) {
 | 
			
		||||
	std.Warning(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error logs a message at level Error on the standard logger.
 | 
			
		||||
func Error(args ...interface{}) {
 | 
			
		||||
	std.Error(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Panic logs a message at level Panic on the standard logger.
 | 
			
		||||
func Panic(args ...interface{}) {
 | 
			
		||||
	std.Panic(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fatal logs a message at level Fatal on the standard logger.
 | 
			
		||||
func Fatal(args ...interface{}) {
 | 
			
		||||
	std.Fatal(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debugf logs a message at level Debug on the standard logger.
 | 
			
		||||
func Debugf(format string, args ...interface{}) {
 | 
			
		||||
	std.Debugf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Printf logs a message at level Info on the standard logger.
 | 
			
		||||
func Printf(format string, args ...interface{}) {
 | 
			
		||||
	std.Printf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Infof logs a message at level Info on the standard logger.
 | 
			
		||||
func Infof(format string, args ...interface{}) {
 | 
			
		||||
	std.Infof(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warnf logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warnf(format string, args ...interface{}) {
 | 
			
		||||
	std.Warnf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warningf logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warningf(format string, args ...interface{}) {
 | 
			
		||||
	std.Warningf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorf logs a message at level Error on the standard logger.
 | 
			
		||||
func Errorf(format string, args ...interface{}) {
 | 
			
		||||
	std.Errorf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Panicf logs a message at level Panic on the standard logger.
 | 
			
		||||
func Panicf(format string, args ...interface{}) {
 | 
			
		||||
	std.Panicf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fatalf logs a message at level Fatal on the standard logger.
 | 
			
		||||
func Fatalf(format string, args ...interface{}) {
 | 
			
		||||
	std.Fatalf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debugln logs a message at level Debug on the standard logger.
 | 
			
		||||
func Debugln(args ...interface{}) {
 | 
			
		||||
	std.Debugln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Println logs a message at level Info on the standard logger.
 | 
			
		||||
func Println(args ...interface{}) {
 | 
			
		||||
	std.Println(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Infoln logs a message at level Info on the standard logger.
 | 
			
		||||
func Infoln(args ...interface{}) {
 | 
			
		||||
	std.Infoln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warnln logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warnln(args ...interface{}) {
 | 
			
		||||
	std.Warnln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warningln logs a message at level Warn on the standard logger.
 | 
			
		||||
func Warningln(args ...interface{}) {
 | 
			
		||||
	std.Warningln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorln logs a message at level Error on the standard logger.
 | 
			
		||||
func Errorln(args ...interface{}) {
 | 
			
		||||
	std.Errorln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Panicln logs a message at level Panic on the standard logger.
 | 
			
		||||
func Panicln(args ...interface{}) {
 | 
			
		||||
	std.Panicln(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fatalln logs a message at level Fatal on the standard logger.
 | 
			
		||||
func Fatalln(args ...interface{}) {
 | 
			
		||||
	std.Fatalln(args...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/Sirupsen/logrus/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/Sirupsen/logrus/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
const DefaultTimestampFormat = time.RFC3339
 | 
			
		||||
 | 
			
		||||
// The Formatter interface is used to implement a custom Formatter. It takes an
 | 
			
		||||
// `Entry`. It exposes all the fields, including the default ones:
 | 
			
		||||
//
 | 
			
		||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
 | 
			
		||||
// * `entry.Data["time"]`. The timestamp.
 | 
			
		||||
// * `entry.Data["level"]. The level the entry was logged at.
 | 
			
		||||
//
 | 
			
		||||
// Any additional fields added with `WithField` or `WithFields` are also in
 | 
			
		||||
// `entry.Data`. Format is expected to return an array of bytes which are then
 | 
			
		||||
// logged to `logger.Out`.
 | 
			
		||||
type Formatter interface {
 | 
			
		||||
	Format(*Entry) ([]byte, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
 | 
			
		||||
// dumping it. If this code wasn't there doing:
 | 
			
		||||
//
 | 
			
		||||
//  logrus.WithField("level", 1).Info("hello")
 | 
			
		||||
//
 | 
			
		||||
// Would just silently drop the user provided level. Instead with this code
 | 
			
		||||
// it'll logged as:
 | 
			
		||||
//
 | 
			
		||||
//  {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
 | 
			
		||||
//
 | 
			
		||||
// It's not exported because it's still using Data in an opinionated way. It's to
 | 
			
		||||
// avoid code duplication between the two default formatters.
 | 
			
		||||
func prefixFieldClashes(data Fields) {
 | 
			
		||||
	_, ok := data["time"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		data["fields.time"] = data["time"]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, ok = data["msg"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		data["fields.msg"] = data["msg"]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, ok = data["level"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		data["fields.level"] = data["level"]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
package logstash
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Formatter generates json in logstash format.
 | 
			
		||||
// Logstash site: http://logstash.net/
 | 
			
		||||
type LogstashFormatter struct {
 | 
			
		||||
	Type string // if not empty use for logstash type field.
 | 
			
		||||
 | 
			
		||||
	// TimestampFormat sets the format used for timestamps.
 | 
			
		||||
	TimestampFormat string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
 | 
			
		||||
	fields := make(logrus.Fields)
 | 
			
		||||
	for k, v := range entry.Data {
 | 
			
		||||
		fields[k] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fields["@version"] = 1
 | 
			
		||||
 | 
			
		||||
	if f.TimestampFormat == "" {
 | 
			
		||||
		f.TimestampFormat = logrus.DefaultTimestampFormat
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fields["@timestamp"] = entry.Time.Format(f.TimestampFormat)
 | 
			
		||||
 | 
			
		||||
	// set message field
 | 
			
		||||
	v, ok := entry.Data["message"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		fields["fields.message"] = v
 | 
			
		||||
	}
 | 
			
		||||
	fields["message"] = entry.Message
 | 
			
		||||
 | 
			
		||||
	// set level field
 | 
			
		||||
	v, ok = entry.Data["level"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		fields["fields.level"] = v
 | 
			
		||||
	}
 | 
			
		||||
	fields["level"] = entry.Level.String()
 | 
			
		||||
 | 
			
		||||
	// set type field
 | 
			
		||||
	if f.Type != "" {
 | 
			
		||||
		v, ok = entry.Data["type"]
 | 
			
		||||
		if ok {
 | 
			
		||||
			fields["fields.type"] = v
 | 
			
		||||
		}
 | 
			
		||||
		fields["type"] = f.Type
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialized, err := json.Marshal(fields)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return append(serialized, '\n'), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/Sirupsen/logrus/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/Sirupsen/logrus/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
// A hook to be fired when logging on the logging levels returned from
 | 
			
		||||
// `Levels()` on your implementation of the interface. Note that this is not
 | 
			
		||||
// fired in a goroutine or a channel with workers, you should handle such
 | 
			
		||||
// functionality yourself if your call is non-blocking and you don't wish for
 | 
			
		||||
// the logging calls for levels returned from `Levels()` to block.
 | 
			
		||||
type Hook interface {
 | 
			
		||||
	Levels() []Level
 | 
			
		||||
	Fire(*Entry) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Internal type for storing the hooks on a logger instance.
 | 
			
		||||
type LevelHooks map[Level][]Hook
 | 
			
		||||
 | 
			
		||||
// Add a hook to an instance of logger. This is called with
 | 
			
		||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
 | 
			
		||||
func (hooks LevelHooks) Add(hook Hook) {
 | 
			
		||||
	for _, level := range hook.Levels() {
 | 
			
		||||
		hooks[level] = append(hooks[level], hook)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
 | 
			
		||||
// appropriate hooks for a log entry.
 | 
			
		||||
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
 | 
			
		||||
	for _, hook := range hooks[level] {
 | 
			
		||||
		if err := hook.Fire(entry); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
// +build !windows,!nacl,!plan9
 | 
			
		||||
 | 
			
		||||
package logrus_syslog
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"log/syslog"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SyslogHook to send logs via syslog.
 | 
			
		||||
type SyslogHook struct {
 | 
			
		||||
	Writer        *syslog.Writer
 | 
			
		||||
	SyslogNetwork string
 | 
			
		||||
	SyslogRaddr   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Creates a hook to be added to an instance of logger. This is called with
 | 
			
		||||
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
 | 
			
		||||
// `if err == nil { log.Hooks.Add(hook) }`
 | 
			
		||||
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
 | 
			
		||||
	w, err := syslog.Dial(network, raddr, priority, tag)
 | 
			
		||||
	return &SyslogHook{w, network, raddr}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
 | 
			
		||||
	line, err := entry.String()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch entry.Level {
 | 
			
		||||
	case logrus.PanicLevel:
 | 
			
		||||
		return hook.Writer.Crit(line)
 | 
			
		||||
	case logrus.FatalLevel:
 | 
			
		||||
		return hook.Writer.Crit(line)
 | 
			
		||||
	case logrus.ErrorLevel:
 | 
			
		||||
		return hook.Writer.Err(line)
 | 
			
		||||
	case logrus.WarnLevel:
 | 
			
		||||
		return hook.Writer.Warning(line)
 | 
			
		||||
	case logrus.InfoLevel:
 | 
			
		||||
		return hook.Writer.Info(line)
 | 
			
		||||
	case logrus.DebugLevel:
 | 
			
		||||
		return hook.Writer.Debug(line)
 | 
			
		||||
	default:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (hook *SyslogHook) Levels() []logrus.Level {
 | 
			
		||||
	return logrus.AllLevels
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								vendor/github.com/Sirupsen/logrus/hooks/test/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/Sirupsen/logrus/hooks/test/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
package test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// test.Hook is a hook designed for dealing with logs in test scenarios.
 | 
			
		||||
type Hook struct {
 | 
			
		||||
	Entries []*logrus.Entry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Installs a test hook for the global logger.
 | 
			
		||||
func NewGlobal() *Hook {
 | 
			
		||||
 | 
			
		||||
	hook := new(Hook)
 | 
			
		||||
	logrus.AddHook(hook)
 | 
			
		||||
 | 
			
		||||
	return hook
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Installs a test hook for a given local logger.
 | 
			
		||||
func NewLocal(logger *logrus.Logger) *Hook {
 | 
			
		||||
 | 
			
		||||
	hook := new(Hook)
 | 
			
		||||
	logger.Hooks.Add(hook)
 | 
			
		||||
 | 
			
		||||
	return hook
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Creates a discarding logger and installs the test hook.
 | 
			
		||||
func NewNullLogger() (*logrus.Logger, *Hook) {
 | 
			
		||||
 | 
			
		||||
	logger := logrus.New()
 | 
			
		||||
	logger.Out = ioutil.Discard
 | 
			
		||||
 | 
			
		||||
	return logger, NewLocal(logger)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Hook) Fire(e *logrus.Entry) error {
 | 
			
		||||
	t.Entries = append(t.Entries, e)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Hook) Levels() []logrus.Level {
 | 
			
		||||
	return logrus.AllLevels
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LastEntry returns the last entry that was logged or nil.
 | 
			
		||||
func (t *Hook) LastEntry() (l *logrus.Entry) {
 | 
			
		||||
 | 
			
		||||
	if i := len(t.Entries) - 1; i < 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return t.Entries[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reset removes all Entries from this test hook.
 | 
			
		||||
func (t *Hook) Reset() {
 | 
			
		||||
	t.Entries = make([]*logrus.Entry, 0)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								vendor/github.com/Sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/Sirupsen/logrus/json_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type JSONFormatter struct {
 | 
			
		||||
	// TimestampFormat sets the format used for marshaling timestamps.
 | 
			
		||||
	TimestampFormat string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
 | 
			
		||||
	data := make(Fields, len(entry.Data)+3)
 | 
			
		||||
	for k, v := range entry.Data {
 | 
			
		||||
		switch v := v.(type) {
 | 
			
		||||
		case error:
 | 
			
		||||
			// Otherwise errors are ignored by `encoding/json`
 | 
			
		||||
			// https://github.com/Sirupsen/logrus/issues/137
 | 
			
		||||
			data[k] = v.Error()
 | 
			
		||||
		default:
 | 
			
		||||
			data[k] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	prefixFieldClashes(data)
 | 
			
		||||
 | 
			
		||||
	timestampFormat := f.TimestampFormat
 | 
			
		||||
	if timestampFormat == "" {
 | 
			
		||||
		timestampFormat = DefaultTimestampFormat
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data["time"] = entry.Time.Format(timestampFormat)
 | 
			
		||||
	data["msg"] = entry.Message
 | 
			
		||||
	data["level"] = entry.Level.String()
 | 
			
		||||
 | 
			
		||||
	serialized, err := json.Marshal(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	return append(serialized, '\n'), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										212
									
								
								vendor/github.com/Sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								vendor/github.com/Sirupsen/logrus/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,212 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Logger struct {
 | 
			
		||||
	// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
 | 
			
		||||
	// file, or leave it default which is `os.Stderr`. You can also set this to
 | 
			
		||||
	// something more adventorous, such as logging to Kafka.
 | 
			
		||||
	Out io.Writer
 | 
			
		||||
	// Hooks for the logger instance. These allow firing events based on logging
 | 
			
		||||
	// levels and log entries. For example, to send errors to an error tracking
 | 
			
		||||
	// service, log to StatsD or dump the core on fatal errors.
 | 
			
		||||
	Hooks LevelHooks
 | 
			
		||||
	// All log entries pass through the formatter before logged to Out. The
 | 
			
		||||
	// included formatters are `TextFormatter` and `JSONFormatter` for which
 | 
			
		||||
	// TextFormatter is the default. In development (when a TTY is attached) it
 | 
			
		||||
	// logs with colors, but to a file it wouldn't. You can easily implement your
 | 
			
		||||
	// own that implements the `Formatter` interface, see the `README` or included
 | 
			
		||||
	// formatters for examples.
 | 
			
		||||
	Formatter Formatter
 | 
			
		||||
	// The logging level the logger should log at. This is typically (and defaults
 | 
			
		||||
	// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
 | 
			
		||||
	// logged. `logrus.Debug` is useful in
 | 
			
		||||
	Level Level
 | 
			
		||||
	// Used to sync writing to the log.
 | 
			
		||||
	mu sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
 | 
			
		||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
 | 
			
		||||
// instantiate your own:
 | 
			
		||||
//
 | 
			
		||||
//    var log = &Logger{
 | 
			
		||||
//      Out: os.Stderr,
 | 
			
		||||
//      Formatter: new(JSONFormatter),
 | 
			
		||||
//      Hooks: make(LevelHooks),
 | 
			
		||||
//      Level: logrus.DebugLevel,
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
// It's recommended to make this a global instance called `log`.
 | 
			
		||||
func New() *Logger {
 | 
			
		||||
	return &Logger{
 | 
			
		||||
		Out:       os.Stderr,
 | 
			
		||||
		Formatter: new(TextFormatter),
 | 
			
		||||
		Hooks:     make(LevelHooks),
 | 
			
		||||
		Level:     InfoLevel,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds a field to the log entry, note that you it doesn't log until you call
 | 
			
		||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
 | 
			
		||||
// If you want multiple fields, use `WithFields`.
 | 
			
		||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
 | 
			
		||||
	return NewEntry(logger).WithField(key, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
 | 
			
		||||
// each `Field`.
 | 
			
		||||
func (logger *Logger) WithFields(fields Fields) *Entry {
 | 
			
		||||
	return NewEntry(logger).WithFields(fields)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add an error as single field to the log entry.  All it does is call
 | 
			
		||||
// `WithError` for the given `error`.
 | 
			
		||||
func (logger *Logger) WithError(err error) *Entry {
 | 
			
		||||
	return NewEntry(logger).WithError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= DebugLevel {
 | 
			
		||||
		NewEntry(logger).Debugf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Infof(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= InfoLevel {
 | 
			
		||||
		NewEntry(logger).Infof(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Printf(format string, args ...interface{}) {
 | 
			
		||||
	NewEntry(logger).Printf(format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warnf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warnf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= ErrorLevel {
 | 
			
		||||
		NewEntry(logger).Errorf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= FatalLevel {
 | 
			
		||||
		NewEntry(logger).Fatalf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
 | 
			
		||||
	if logger.Level >= PanicLevel {
 | 
			
		||||
		NewEntry(logger).Panicf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Debug(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= DebugLevel {
 | 
			
		||||
		NewEntry(logger).Debug(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Info(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= InfoLevel {
 | 
			
		||||
		NewEntry(logger).Info(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Print(args ...interface{}) {
 | 
			
		||||
	NewEntry(logger).Info(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warn(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warn(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warning(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warn(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Error(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= ErrorLevel {
 | 
			
		||||
		NewEntry(logger).Error(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Fatal(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= FatalLevel {
 | 
			
		||||
		NewEntry(logger).Fatal(args...)
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Panic(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= PanicLevel {
 | 
			
		||||
		NewEntry(logger).Panic(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Debugln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= DebugLevel {
 | 
			
		||||
		NewEntry(logger).Debugln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Infoln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= InfoLevel {
 | 
			
		||||
		NewEntry(logger).Infoln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Println(args ...interface{}) {
 | 
			
		||||
	NewEntry(logger).Println(args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warnln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warnln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Warningln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= WarnLevel {
 | 
			
		||||
		NewEntry(logger).Warnln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Errorln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= ErrorLevel {
 | 
			
		||||
		NewEntry(logger).Errorln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Fatalln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= FatalLevel {
 | 
			
		||||
		NewEntry(logger).Fatalln(args...)
 | 
			
		||||
	}
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Panicln(args ...interface{}) {
 | 
			
		||||
	if logger.Level >= PanicLevel {
 | 
			
		||||
		NewEntry(logger).Panicln(args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										143
									
								
								vendor/github.com/Sirupsen/logrus/logrus.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/Sirupsen/logrus/logrus.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Fields type, used to pass to `WithFields`.
 | 
			
		||||
type Fields map[string]interface{}
 | 
			
		||||
 | 
			
		||||
// Level type
 | 
			
		||||
type Level uint8
 | 
			
		||||
 | 
			
		||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
 | 
			
		||||
func (level Level) String() string {
 | 
			
		||||
	switch level {
 | 
			
		||||
	case DebugLevel:
 | 
			
		||||
		return "debug"
 | 
			
		||||
	case InfoLevel:
 | 
			
		||||
		return "info"
 | 
			
		||||
	case WarnLevel:
 | 
			
		||||
		return "warning"
 | 
			
		||||
	case ErrorLevel:
 | 
			
		||||
		return "error"
 | 
			
		||||
	case FatalLevel:
 | 
			
		||||
		return "fatal"
 | 
			
		||||
	case PanicLevel:
 | 
			
		||||
		return "panic"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "unknown"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseLevel takes a string level and returns the Logrus log level constant.
 | 
			
		||||
func ParseLevel(lvl string) (Level, error) {
 | 
			
		||||
	switch strings.ToLower(lvl) {
 | 
			
		||||
	case "panic":
 | 
			
		||||
		return PanicLevel, nil
 | 
			
		||||
	case "fatal":
 | 
			
		||||
		return FatalLevel, nil
 | 
			
		||||
	case "error":
 | 
			
		||||
		return ErrorLevel, nil
 | 
			
		||||
	case "warn", "warning":
 | 
			
		||||
		return WarnLevel, nil
 | 
			
		||||
	case "info":
 | 
			
		||||
		return InfoLevel, nil
 | 
			
		||||
	case "debug":
 | 
			
		||||
		return DebugLevel, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var l Level
 | 
			
		||||
	return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A constant exposing all logging levels
 | 
			
		||||
var AllLevels = []Level{
 | 
			
		||||
	PanicLevel,
 | 
			
		||||
	FatalLevel,
 | 
			
		||||
	ErrorLevel,
 | 
			
		||||
	WarnLevel,
 | 
			
		||||
	InfoLevel,
 | 
			
		||||
	DebugLevel,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// These are the different logging levels. You can set the logging level to log
 | 
			
		||||
// on your instance of logger, obtained with `logrus.New()`.
 | 
			
		||||
const (
 | 
			
		||||
	// PanicLevel level, highest level of severity. Logs and then calls panic with the
 | 
			
		||||
	// message passed to Debug, Info, ...
 | 
			
		||||
	PanicLevel Level = iota
 | 
			
		||||
	// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
 | 
			
		||||
	// logging level is set to Panic.
 | 
			
		||||
	FatalLevel
 | 
			
		||||
	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
 | 
			
		||||
	// Commonly used for hooks to send errors to an error tracking service.
 | 
			
		||||
	ErrorLevel
 | 
			
		||||
	// WarnLevel level. Non-critical entries that deserve eyes.
 | 
			
		||||
	WarnLevel
 | 
			
		||||
	// InfoLevel level. General operational entries about what's going on inside the
 | 
			
		||||
	// application.
 | 
			
		||||
	InfoLevel
 | 
			
		||||
	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
 | 
			
		||||
	DebugLevel
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Won't compile if StdLogger can't be realized by a log.Logger
 | 
			
		||||
var (
 | 
			
		||||
	_ StdLogger = &log.Logger{}
 | 
			
		||||
	_ StdLogger = &Entry{}
 | 
			
		||||
	_ StdLogger = &Logger{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StdLogger is what your logrus-enabled library should take, that way
 | 
			
		||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
 | 
			
		||||
// interface, this is the closest we get, unfortunately.
 | 
			
		||||
type StdLogger interface {
 | 
			
		||||
	Print(...interface{})
 | 
			
		||||
	Printf(string, ...interface{})
 | 
			
		||||
	Println(...interface{})
 | 
			
		||||
 | 
			
		||||
	Fatal(...interface{})
 | 
			
		||||
	Fatalf(string, ...interface{})
 | 
			
		||||
	Fatalln(...interface{})
 | 
			
		||||
 | 
			
		||||
	Panic(...interface{})
 | 
			
		||||
	Panicf(string, ...interface{})
 | 
			
		||||
	Panicln(...interface{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The FieldLogger interface generalizes the Entry and Logger types
 | 
			
		||||
type FieldLogger interface {
 | 
			
		||||
	WithField(key string, value interface{}) *Entry
 | 
			
		||||
	WithFields(fields Fields) *Entry
 | 
			
		||||
	WithError(err error) *Entry
 | 
			
		||||
 | 
			
		||||
	Debugf(format string, args ...interface{})
 | 
			
		||||
	Infof(format string, args ...interface{})
 | 
			
		||||
	Printf(format string, args ...interface{})
 | 
			
		||||
	Warnf(format string, args ...interface{})
 | 
			
		||||
	Warningf(format string, args ...interface{})
 | 
			
		||||
	Errorf(format string, args ...interface{})
 | 
			
		||||
	Fatalf(format string, args ...interface{})
 | 
			
		||||
	Panicf(format string, args ...interface{})
 | 
			
		||||
 | 
			
		||||
	Debug(args ...interface{})
 | 
			
		||||
	Info(args ...interface{})
 | 
			
		||||
	Print(args ...interface{})
 | 
			
		||||
	Warn(args ...interface{})
 | 
			
		||||
	Warning(args ...interface{})
 | 
			
		||||
	Error(args ...interface{})
 | 
			
		||||
	Fatal(args ...interface{})
 | 
			
		||||
	Panic(args ...interface{})
 | 
			
		||||
 | 
			
		||||
	Debugln(args ...interface{})
 | 
			
		||||
	Infoln(args ...interface{})
 | 
			
		||||
	Println(args ...interface{})
 | 
			
		||||
	Warnln(args ...interface{})
 | 
			
		||||
	Warningln(args ...interface{})
 | 
			
		||||
	Errorln(args ...interface{})
 | 
			
		||||
	Fatalln(args ...interface{})
 | 
			
		||||
	Panicln(args ...interface{})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/github.com/Sirupsen/logrus/terminal_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/Sirupsen/logrus/terminal_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
// +build darwin freebsd openbsd netbsd dragonfly
 | 
			
		||||
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import "syscall"
 | 
			
		||||
 | 
			
		||||
const ioctlReadTermios = syscall.TIOCGETA
 | 
			
		||||
 | 
			
		||||
type Termios syscall.Termios
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/github.com/Sirupsen/logrus/terminal_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/Sirupsen/logrus/terminal_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
// Based on ssh/terminal:
 | 
			
		||||
// Copyright 2013 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 logrus
 | 
			
		||||
 | 
			
		||||
import "syscall"
 | 
			
		||||
 | 
			
		||||
const ioctlReadTermios = syscall.TCGETS
 | 
			
		||||
 | 
			
		||||
type Termios syscall.Termios
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
// Based on ssh/terminal:
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// +build linux darwin freebsd openbsd netbsd dragonfly
 | 
			
		||||
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
 | 
			
		||||
func IsTerminal() bool {
 | 
			
		||||
	fd := syscall.Stderr
 | 
			
		||||
	var termios Termios
 | 
			
		||||
	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
 | 
			
		||||
	return err == 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								vendor/github.com/Sirupsen/logrus/terminal_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/Sirupsen/logrus/terminal_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
// +build solaris
 | 
			
		||||
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsTerminal returns true if the given file descriptor is a terminal.
 | 
			
		||||
func IsTerminal() bool {
 | 
			
		||||
	_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/Sirupsen/logrus/terminal_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/Sirupsen/logrus/terminal_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
// Based on ssh/terminal:
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
 | 
			
		||||
func IsTerminal() bool {
 | 
			
		||||
	fd := syscall.Stderr
 | 
			
		||||
	var st uint32
 | 
			
		||||
	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
 | 
			
		||||
	return r != 0 && e == 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										161
									
								
								vendor/github.com/Sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								vendor/github.com/Sirupsen/logrus/text_formatter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	nocolor = 0
 | 
			
		||||
	red     = 31
 | 
			
		||||
	green   = 32
 | 
			
		||||
	yellow  = 33
 | 
			
		||||
	blue    = 34
 | 
			
		||||
	gray    = 37
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	baseTimestamp time.Time
 | 
			
		||||
	isTerminal    bool
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	baseTimestamp = time.Now()
 | 
			
		||||
	isTerminal = IsTerminal()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func miniTS() int {
 | 
			
		||||
	return int(time.Since(baseTimestamp) / time.Second)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TextFormatter struct {
 | 
			
		||||
	// Set to true to bypass checking for a TTY before outputting colors.
 | 
			
		||||
	ForceColors bool
 | 
			
		||||
 | 
			
		||||
	// Force disabling colors.
 | 
			
		||||
	DisableColors bool
 | 
			
		||||
 | 
			
		||||
	// Disable timestamp logging. useful when output is redirected to logging
 | 
			
		||||
	// system that already adds timestamps.
 | 
			
		||||
	DisableTimestamp bool
 | 
			
		||||
 | 
			
		||||
	// Enable logging the full timestamp when a TTY is attached instead of just
 | 
			
		||||
	// the time passed since beginning of execution.
 | 
			
		||||
	FullTimestamp bool
 | 
			
		||||
 | 
			
		||||
	// TimestampFormat to use for display when a full timestamp is printed
 | 
			
		||||
	TimestampFormat string
 | 
			
		||||
 | 
			
		||||
	// The fields are sorted by default for a consistent output. For applications
 | 
			
		||||
	// that log extremely frequently and don't use the JSON formatter this may not
 | 
			
		||||
	// be desired.
 | 
			
		||||
	DisableSorting bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
 | 
			
		||||
	var keys []string = make([]string, 0, len(entry.Data))
 | 
			
		||||
	for k := range entry.Data {
 | 
			
		||||
		keys = append(keys, k)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !f.DisableSorting {
 | 
			
		||||
		sort.Strings(keys)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := &bytes.Buffer{}
 | 
			
		||||
 | 
			
		||||
	prefixFieldClashes(entry.Data)
 | 
			
		||||
 | 
			
		||||
	isColorTerminal := isTerminal && (runtime.GOOS != "windows")
 | 
			
		||||
	isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
 | 
			
		||||
 | 
			
		||||
	timestampFormat := f.TimestampFormat
 | 
			
		||||
	if timestampFormat == "" {
 | 
			
		||||
		timestampFormat = DefaultTimestampFormat
 | 
			
		||||
	}
 | 
			
		||||
	if isColored {
 | 
			
		||||
		f.printColored(b, entry, keys, timestampFormat)
 | 
			
		||||
	} else {
 | 
			
		||||
		if !f.DisableTimestamp {
 | 
			
		||||
			f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
 | 
			
		||||
		}
 | 
			
		||||
		f.appendKeyValue(b, "level", entry.Level.String())
 | 
			
		||||
		if entry.Message != "" {
 | 
			
		||||
			f.appendKeyValue(b, "msg", entry.Message)
 | 
			
		||||
		}
 | 
			
		||||
		for _, key := range keys {
 | 
			
		||||
			f.appendKeyValue(b, key, entry.Data[key])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.WriteByte('\n')
 | 
			
		||||
	return b.Bytes(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
 | 
			
		||||
	var levelColor int
 | 
			
		||||
	switch entry.Level {
 | 
			
		||||
	case DebugLevel:
 | 
			
		||||
		levelColor = gray
 | 
			
		||||
	case WarnLevel:
 | 
			
		||||
		levelColor = yellow
 | 
			
		||||
	case ErrorLevel, FatalLevel, PanicLevel:
 | 
			
		||||
		levelColor = red
 | 
			
		||||
	default:
 | 
			
		||||
		levelColor = blue
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	levelText := strings.ToUpper(entry.Level.String())[0:4]
 | 
			
		||||
 | 
			
		||||
	if !f.FullTimestamp {
 | 
			
		||||
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
 | 
			
		||||
	}
 | 
			
		||||
	for _, k := range keys {
 | 
			
		||||
		v := entry.Data[k]
 | 
			
		||||
		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func needsQuoting(text string) bool {
 | 
			
		||||
	for _, ch := range text {
 | 
			
		||||
		if !((ch >= 'a' && ch <= 'z') ||
 | 
			
		||||
			(ch >= 'A' && ch <= 'Z') ||
 | 
			
		||||
			(ch >= '0' && ch <= '9') ||
 | 
			
		||||
			ch == '-' || ch == '.') {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
 | 
			
		||||
 | 
			
		||||
	b.WriteString(key)
 | 
			
		||||
	b.WriteByte('=')
 | 
			
		||||
 | 
			
		||||
	switch value := value.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		if needsQuoting(value) {
 | 
			
		||||
			b.WriteString(value)
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt.Fprintf(b, "%q", value)
 | 
			
		||||
		}
 | 
			
		||||
	case error:
 | 
			
		||||
		errmsg := value.Error()
 | 
			
		||||
		if needsQuoting(errmsg) {
 | 
			
		||||
			b.WriteString(errmsg)
 | 
			
		||||
		} else {
 | 
			
		||||
			fmt.Fprintf(b, "%q", value)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Fprint(b, value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.WriteByte(' ')
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/Sirupsen/logrus/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/Sirupsen/logrus/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
package logrus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"io"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) Writer() *io.PipeWriter {
 | 
			
		||||
	reader, writer := io.Pipe()
 | 
			
		||||
 | 
			
		||||
	go logger.writerScanner(reader)
 | 
			
		||||
	runtime.SetFinalizer(writer, writerFinalizer)
 | 
			
		||||
 | 
			
		||||
	return writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (logger *Logger) writerScanner(reader *io.PipeReader) {
 | 
			
		||||
	scanner := bufio.NewScanner(reader)
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		logger.Print(scanner.Text())
 | 
			
		||||
	}
 | 
			
		||||
	if err := scanner.Err(); err != nil {
 | 
			
		||||
		logger.Errorf("Error while reading from Writer: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	reader.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writerFinalizer(writer *io.PipeWriter) {
 | 
			
		||||
	writer.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/alecthomas/log4go/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/alecthomas/log4go/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
Copyright (c) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
   documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										288
									
								
								vendor/github.com/alecthomas/log4go/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								vendor/github.com/alecthomas/log4go/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type xmlProperty struct {
 | 
			
		||||
	Name  string `xml:"name,attr"`
 | 
			
		||||
	Value string `xml:",chardata"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type xmlFilter struct {
 | 
			
		||||
	Enabled  string        `xml:"enabled,attr"`
 | 
			
		||||
	Tag      string        `xml:"tag"`
 | 
			
		||||
	Level    string        `xml:"level"`
 | 
			
		||||
	Type     string        `xml:"type"`
 | 
			
		||||
	Property []xmlProperty `xml:"property"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type xmlLoggerConfig struct {
 | 
			
		||||
	Filter []xmlFilter `xml:"filter"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Load XML configuration; see examples/example.xml for documentation
 | 
			
		||||
func (log Logger) LoadConfiguration(filename string) {
 | 
			
		||||
	log.Close()
 | 
			
		||||
 | 
			
		||||
	// Open the configuration file
 | 
			
		||||
	fd, err := os.Open(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	contents, err := ioutil.ReadAll(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	xc := new(xmlLoggerConfig)
 | 
			
		||||
	if err := xml.Unmarshal(contents, xc); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, xmlfilt := range xc.Filter {
 | 
			
		||||
		var filt LogWriter
 | 
			
		||||
		var lvl Level
 | 
			
		||||
		bad, good, enabled := false, true, false
 | 
			
		||||
 | 
			
		||||
		// Check required children
 | 
			
		||||
		if len(xmlfilt.Enabled) == 0 {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
 | 
			
		||||
			bad = true
 | 
			
		||||
		} else {
 | 
			
		||||
			enabled = xmlfilt.Enabled != "false"
 | 
			
		||||
		}
 | 
			
		||||
		if len(xmlfilt.Tag) == 0 {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
 | 
			
		||||
			bad = true
 | 
			
		||||
		}
 | 
			
		||||
		if len(xmlfilt.Type) == 0 {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
 | 
			
		||||
			bad = true
 | 
			
		||||
		}
 | 
			
		||||
		if len(xmlfilt.Level) == 0 {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
 | 
			
		||||
			bad = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch xmlfilt.Level {
 | 
			
		||||
		case "FINEST":
 | 
			
		||||
			lvl = FINEST
 | 
			
		||||
		case "FINE":
 | 
			
		||||
			lvl = FINE
 | 
			
		||||
		case "DEBUG":
 | 
			
		||||
			lvl = DEBUG
 | 
			
		||||
		case "TRACE":
 | 
			
		||||
			lvl = TRACE
 | 
			
		||||
		case "INFO":
 | 
			
		||||
			lvl = INFO
 | 
			
		||||
		case "WARNING":
 | 
			
		||||
			lvl = WARNING
 | 
			
		||||
		case "ERROR":
 | 
			
		||||
			lvl = ERROR
 | 
			
		||||
		case "CRITICAL":
 | 
			
		||||
			lvl = CRITICAL
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
 | 
			
		||||
			bad = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Just so all of the required attributes are errored at the same time if missing
 | 
			
		||||
		if bad {
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch xmlfilt.Type {
 | 
			
		||||
		case "console":
 | 
			
		||||
			filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
 | 
			
		||||
		case "file":
 | 
			
		||||
			filt, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
 | 
			
		||||
		case "xml":
 | 
			
		||||
			filt, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
 | 
			
		||||
		case "socket":
 | 
			
		||||
			filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Just so all of the required params are errored at the same time if wrong
 | 
			
		||||
		if !good {
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If we're disabled (syntax and correctness checks only), don't add to logger
 | 
			
		||||
		if !enabled {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log[xmlfilt.Tag] = &Filter{lvl, filt}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (*ConsoleLogWriter, bool) {
 | 
			
		||||
	// Parse properties
 | 
			
		||||
	for _, prop := range props {
 | 
			
		||||
		switch prop.Name {
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's disabled, we're just checking syntax
 | 
			
		||||
	if !enabled {
 | 
			
		||||
		return nil, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewConsoleLogWriter(), true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
 | 
			
		||||
func strToNumSuffix(str string, mult int) int {
 | 
			
		||||
	num := 1
 | 
			
		||||
	if len(str) > 1 {
 | 
			
		||||
		switch str[len(str)-1] {
 | 
			
		||||
		case 'G', 'g':
 | 
			
		||||
			num *= mult
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case 'M', 'm':
 | 
			
		||||
			num *= mult
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case 'K', 'k':
 | 
			
		||||
			num *= mult
 | 
			
		||||
			str = str[0 : len(str)-1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	parsed, _ := strconv.Atoi(str)
 | 
			
		||||
	return parsed * num
 | 
			
		||||
}
 | 
			
		||||
func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
 | 
			
		||||
	file := ""
 | 
			
		||||
	format := "[%D %T] [%L] (%S) %M"
 | 
			
		||||
	maxlines := 0
 | 
			
		||||
	maxsize := 0
 | 
			
		||||
	daily := false
 | 
			
		||||
	rotate := false
 | 
			
		||||
 | 
			
		||||
	// Parse properties
 | 
			
		||||
	for _, prop := range props {
 | 
			
		||||
		switch prop.Name {
 | 
			
		||||
		case "filename":
 | 
			
		||||
			file = strings.Trim(prop.Value, " \r\n")
 | 
			
		||||
		case "format":
 | 
			
		||||
			format = strings.Trim(prop.Value, " \r\n")
 | 
			
		||||
		case "maxlines":
 | 
			
		||||
			maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
 | 
			
		||||
		case "maxsize":
 | 
			
		||||
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
 | 
			
		||||
		case "daily":
 | 
			
		||||
			daily = strings.Trim(prop.Value, " \r\n") != "false"
 | 
			
		||||
		case "rotate":
 | 
			
		||||
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check properties
 | 
			
		||||
	if len(file) == 0 {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's disabled, we're just checking syntax
 | 
			
		||||
	if !enabled {
 | 
			
		||||
		return nil, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flw := NewFileLogWriter(file, rotate)
 | 
			
		||||
	flw.SetFormat(format)
 | 
			
		||||
	flw.SetRotateLines(maxlines)
 | 
			
		||||
	flw.SetRotateSize(maxsize)
 | 
			
		||||
	flw.SetRotateDaily(daily)
 | 
			
		||||
	return flw, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func xmlToXMLLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
 | 
			
		||||
	file := ""
 | 
			
		||||
	maxrecords := 0
 | 
			
		||||
	maxsize := 0
 | 
			
		||||
	daily := false
 | 
			
		||||
	rotate := false
 | 
			
		||||
 | 
			
		||||
	// Parse properties
 | 
			
		||||
	for _, prop := range props {
 | 
			
		||||
		switch prop.Name {
 | 
			
		||||
		case "filename":
 | 
			
		||||
			file = strings.Trim(prop.Value, " \r\n")
 | 
			
		||||
		case "maxrecords":
 | 
			
		||||
			maxrecords = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
 | 
			
		||||
		case "maxsize":
 | 
			
		||||
			maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
 | 
			
		||||
		case "daily":
 | 
			
		||||
			daily = strings.Trim(prop.Value, " \r\n") != "false"
 | 
			
		||||
		case "rotate":
 | 
			
		||||
			rotate = strings.Trim(prop.Value, " \r\n") != "false"
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for xml filter in %s\n", prop.Name, filename)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check properties
 | 
			
		||||
	if len(file) == 0 {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for xml filter missing in %s\n", "filename", filename)
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's disabled, we're just checking syntax
 | 
			
		||||
	if !enabled {
 | 
			
		||||
		return nil, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	xlw := NewXMLLogWriter(file, rotate)
 | 
			
		||||
	xlw.SetRotateLines(maxrecords)
 | 
			
		||||
	xlw.SetRotateSize(maxsize)
 | 
			
		||||
	xlw.SetRotateDaily(daily)
 | 
			
		||||
	return xlw, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func xmlToSocketLogWriter(filename string, props []xmlProperty, enabled bool) (SocketLogWriter, bool) {
 | 
			
		||||
	endpoint := ""
 | 
			
		||||
	protocol := "udp"
 | 
			
		||||
 | 
			
		||||
	// Parse properties
 | 
			
		||||
	for _, prop := range props {
 | 
			
		||||
		switch prop.Name {
 | 
			
		||||
		case "endpoint":
 | 
			
		||||
			endpoint = strings.Trim(prop.Value, " \r\n")
 | 
			
		||||
		case "protocol":
 | 
			
		||||
			protocol = strings.Trim(prop.Value, " \r\n")
 | 
			
		||||
		default:
 | 
			
		||||
			fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check properties
 | 
			
		||||
	if len(endpoint) == 0 {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "endpoint", filename)
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If it's disabled, we're just checking syntax
 | 
			
		||||
	if !enabled {
 | 
			
		||||
		return nil, true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewSocketLogWriter(protocol, endpoint), true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
import l4g "code.google.com/p/log4go"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	log := l4g.NewLogger()
 | 
			
		||||
	defer log.Close()
 | 
			
		||||
	log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
 | 
			
		||||
	log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
import l4g "code.google.com/p/log4go"
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	filename = "flw.log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	// Get a new logger instance
 | 
			
		||||
	log := l4g.NewLogger()
 | 
			
		||||
 | 
			
		||||
	// Create a default logger that is logging messages of FINE or higher
 | 
			
		||||
	log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false))
 | 
			
		||||
	log.Close()
 | 
			
		||||
 | 
			
		||||
	/* Can also specify manually via the following: (these are the defaults) */
 | 
			
		||||
	flw := l4g.NewFileLogWriter(filename, false)
 | 
			
		||||
	flw.SetFormat("[%D %T] [%L] (%S) %M")
 | 
			
		||||
	flw.SetRotate(false)
 | 
			
		||||
	flw.SetRotateSize(0)
 | 
			
		||||
	flw.SetRotateLines(0)
 | 
			
		||||
	flw.SetRotateDaily(false)
 | 
			
		||||
	log.AddFilter("file", l4g.FINE, flw)
 | 
			
		||||
 | 
			
		||||
	// Log some experimental messages
 | 
			
		||||
	log.Finest("Everything is created now (notice that I will not be printing to the file)")
 | 
			
		||||
	log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
 | 
			
		||||
	log.Critical("Time to close out!")
 | 
			
		||||
 | 
			
		||||
	// Close the log
 | 
			
		||||
	log.Close()
 | 
			
		||||
 | 
			
		||||
	// Print what was logged to the file (yes, I know I'm skipping error checking)
 | 
			
		||||
	fd, _ := os.Open(filename)
 | 
			
		||||
	in := bufio.NewReader(fd)
 | 
			
		||||
	fmt.Print("Messages logged to file were: (line numbers not included)\n")
 | 
			
		||||
	for lineno := 1; ; lineno++ {
 | 
			
		||||
		line, err := in.ReadString('\n')
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Printf("%3d:\t%s", lineno, line)
 | 
			
		||||
	}
 | 
			
		||||
	fd.Close()
 | 
			
		||||
 | 
			
		||||
	// Remove the file so it's not lying around
 | 
			
		||||
	os.Remove(filename)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	port = flag.String("p", "12124", "Port number to listen on")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func e(err error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("Erroring out: %s\n", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	// Bind to the port
 | 
			
		||||
	bind, err := net.ResolveUDPAddr("0.0.0.0:" + *port)
 | 
			
		||||
	e(err)
 | 
			
		||||
 | 
			
		||||
	// Create listener
 | 
			
		||||
	listener, err := net.ListenUDP("udp", bind)
 | 
			
		||||
	e(err)
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("Listening to port %s...\n", *port)
 | 
			
		||||
	for {
 | 
			
		||||
		// read into a new buffer
 | 
			
		||||
		buffer := make([]byte, 1024)
 | 
			
		||||
		_, _, err := listener.ReadFrom(buffer)
 | 
			
		||||
		e(err)
 | 
			
		||||
 | 
			
		||||
		// log to standard output
 | 
			
		||||
		fmt.Println(string(buffer))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
import l4g "code.google.com/p/log4go"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	log := l4g.NewLogger()
 | 
			
		||||
	log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
 | 
			
		||||
 | 
			
		||||
	// Run `nc -u -l -p 12124` or similar before you run this to see the following message
 | 
			
		||||
	log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
 | 
			
		||||
 | 
			
		||||
	// This makes sure the output stream buffer is written
 | 
			
		||||
	log.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import l4g "code.google.com/p/log4go"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	// Load the configuration (isn't this easy?)
 | 
			
		||||
	l4g.LoadConfiguration("example.xml")
 | 
			
		||||
 | 
			
		||||
	// And now we're ready!
 | 
			
		||||
	l4g.Finest("This will only go to those of you really cool UDP kids!  If you change enabled=true.")
 | 
			
		||||
	l4g.Debug("Oh no!  %d + %d = %d!", 2, 2, 2+2)
 | 
			
		||||
	l4g.Info("About that time, eh chaps?")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										264
									
								
								vendor/github.com/alecthomas/log4go/filelog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/github.com/alecthomas/log4go/filelog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,264 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This log writer sends output to a file
 | 
			
		||||
type FileLogWriter struct {
 | 
			
		||||
	rec chan *LogRecord
 | 
			
		||||
	rot chan bool
 | 
			
		||||
 | 
			
		||||
	// The opened file
 | 
			
		||||
	filename string
 | 
			
		||||
	file     *os.File
 | 
			
		||||
 | 
			
		||||
	// The logging format
 | 
			
		||||
	format string
 | 
			
		||||
 | 
			
		||||
	// File header/trailer
 | 
			
		||||
	header, trailer string
 | 
			
		||||
 | 
			
		||||
	// Rotate at linecount
 | 
			
		||||
	maxlines          int
 | 
			
		||||
	maxlines_curlines int
 | 
			
		||||
 | 
			
		||||
	// Rotate at size
 | 
			
		||||
	maxsize         int
 | 
			
		||||
	maxsize_cursize int
 | 
			
		||||
 | 
			
		||||
	// Rotate daily
 | 
			
		||||
	daily          bool
 | 
			
		||||
	daily_opendate int
 | 
			
		||||
 | 
			
		||||
	// Keep old logfiles (.001, .002, etc)
 | 
			
		||||
	rotate    bool
 | 
			
		||||
	maxbackup int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is the FileLogWriter's output method
 | 
			
		||||
func (w *FileLogWriter) LogWrite(rec *LogRecord) {
 | 
			
		||||
	w.rec <- rec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *FileLogWriter) Close() {
 | 
			
		||||
	close(w.rec)
 | 
			
		||||
	w.file.Sync()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewFileLogWriter creates a new LogWriter which writes to the given file and
 | 
			
		||||
// has rotation enabled if rotate is true.
 | 
			
		||||
//
 | 
			
		||||
// If rotate is true, any time a new log file is opened, the old one is renamed
 | 
			
		||||
// with a .### extension to preserve it.  The various Set* methods can be used
 | 
			
		||||
// to configure log rotation based on lines, size, and daily.
 | 
			
		||||
//
 | 
			
		||||
// The standard log-line format is:
 | 
			
		||||
//   [%D %T] [%L] (%S) %M
 | 
			
		||||
func NewFileLogWriter(fname string, rotate bool) *FileLogWriter {
 | 
			
		||||
	w := &FileLogWriter{
 | 
			
		||||
		rec:       make(chan *LogRecord, LogBufferLength),
 | 
			
		||||
		rot:       make(chan bool),
 | 
			
		||||
		filename:  fname,
 | 
			
		||||
		format:    "[%D %T] [%L] (%S) %M",
 | 
			
		||||
		rotate:    rotate,
 | 
			
		||||
		maxbackup: 999,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// open the file for the first time
 | 
			
		||||
	if err := w.intRotate(); err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if w.file != nil {
 | 
			
		||||
				fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
 | 
			
		||||
				w.file.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		for {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-w.rot:
 | 
			
		||||
				if err := w.intRotate(); err != nil {
 | 
			
		||||
					fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			case rec, ok := <-w.rec:
 | 
			
		||||
				if !ok {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				now := time.Now()
 | 
			
		||||
				if (w.maxlines > 0 && w.maxlines_curlines >= w.maxlines) ||
 | 
			
		||||
					(w.maxsize > 0 && w.maxsize_cursize >= w.maxsize) ||
 | 
			
		||||
					(w.daily && now.Day() != w.daily_opendate) {
 | 
			
		||||
					if err := w.intRotate(); err != nil {
 | 
			
		||||
						fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Perform the write
 | 
			
		||||
				n, err := fmt.Fprint(w.file, FormatLogRecord(w.format, rec))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Update the counts
 | 
			
		||||
				w.maxlines_curlines++
 | 
			
		||||
				w.maxsize_cursize += n
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Request that the logs rotate
 | 
			
		||||
func (w *FileLogWriter) Rotate() {
 | 
			
		||||
	w.rot <- true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If this is called in a threaded context, it MUST be synchronized
 | 
			
		||||
func (w *FileLogWriter) intRotate() error {
 | 
			
		||||
	// Close any log file that may be open
 | 
			
		||||
	if w.file != nil {
 | 
			
		||||
		fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
 | 
			
		||||
		w.file.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If we are keeping log files, move it to the next available number
 | 
			
		||||
	if w.rotate {
 | 
			
		||||
		_, err := os.Lstat(w.filename)
 | 
			
		||||
		if err == nil { // file exists
 | 
			
		||||
			// Find the next available number
 | 
			
		||||
			num := 1
 | 
			
		||||
			fname := ""
 | 
			
		||||
			if w.daily && time.Now().Day() != w.daily_opendate {
 | 
			
		||||
				yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
 | 
			
		||||
 | 
			
		||||
				for ; err == nil && num <= 999; num++ {
 | 
			
		||||
					fname = w.filename + fmt.Sprintf(".%s.%03d", yesterday, num)
 | 
			
		||||
					_, err = os.Lstat(fname)
 | 
			
		||||
				}
 | 
			
		||||
				// return error if the last file checked still existed
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.filename)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				num = w.maxbackup - 1
 | 
			
		||||
				for ; num >= 1; num-- {
 | 
			
		||||
					fname = w.filename + fmt.Sprintf(".%d", num)
 | 
			
		||||
					nfname := w.filename + fmt.Sprintf(".%d", num+1)
 | 
			
		||||
					_, err = os.Lstat(fname)
 | 
			
		||||
					if err == nil {
 | 
			
		||||
						os.Rename(fname, nfname)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			w.file.Close()
 | 
			
		||||
			// Rename the file to its newfound home
 | 
			
		||||
			err = os.Rename(w.filename, fname)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("Rotate: %s\n", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Open the log file
 | 
			
		||||
	fd, err := os.OpenFile(w.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	w.file = fd
 | 
			
		||||
 | 
			
		||||
	now := time.Now()
 | 
			
		||||
	fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: now}))
 | 
			
		||||
 | 
			
		||||
	// Set the daily open date to the current date
 | 
			
		||||
	w.daily_opendate = now.Day()
 | 
			
		||||
 | 
			
		||||
	// initialize rotation values
 | 
			
		||||
	w.maxlines_curlines = 0
 | 
			
		||||
	w.maxsize_cursize = 0
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set the logging format (chainable).  Must be called before the first log
 | 
			
		||||
// message is written.
 | 
			
		||||
func (w *FileLogWriter) SetFormat(format string) *FileLogWriter {
 | 
			
		||||
	w.format = format
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set the logfile header and footer (chainable).  Must be called before the first log
 | 
			
		||||
// message is written.  These are formatted similar to the FormatLogRecord (e.g.
 | 
			
		||||
// you can use %D and %T in your header/footer for date and time).
 | 
			
		||||
func (w *FileLogWriter) SetHeadFoot(head, foot string) *FileLogWriter {
 | 
			
		||||
	w.header, w.trailer = head, foot
 | 
			
		||||
	if w.maxlines_curlines == 0 {
 | 
			
		||||
		fmt.Fprint(w.file, FormatLogRecord(w.header, &LogRecord{Created: time.Now()}))
 | 
			
		||||
	}
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set rotate at linecount (chainable). Must be called before the first log
 | 
			
		||||
// message is written.
 | 
			
		||||
func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter {
 | 
			
		||||
	//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateLines: %v\n", maxlines)
 | 
			
		||||
	w.maxlines = maxlines
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set rotate at size (chainable). Must be called before the first log message
 | 
			
		||||
// is written.
 | 
			
		||||
func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter {
 | 
			
		||||
	//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateSize: %v\n", maxsize)
 | 
			
		||||
	w.maxsize = maxsize
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set rotate daily (chainable). Must be called before the first log message is
 | 
			
		||||
// written.
 | 
			
		||||
func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter {
 | 
			
		||||
	//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotateDaily: %v\n", daily)
 | 
			
		||||
	w.daily = daily
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set max backup files. Must be called before the first log message
 | 
			
		||||
// is written.
 | 
			
		||||
func (w *FileLogWriter) SetRotateMaxBackup(maxbackup int) *FileLogWriter {
 | 
			
		||||
	w.maxbackup = maxbackup
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetRotate changes whether or not the old logs are kept. (chainable) Must be
 | 
			
		||||
// called before the first log message is written.  If rotate is false, the
 | 
			
		||||
// files are overwritten; otherwise, they are rotated to another file before the
 | 
			
		||||
// new log is opened.
 | 
			
		||||
func (w *FileLogWriter) SetRotate(rotate bool) *FileLogWriter {
 | 
			
		||||
	//fmt.Fprintf(os.Stderr, "FileLogWriter.SetRotate: %v\n", rotate)
 | 
			
		||||
	w.rotate = rotate
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewXMLLogWriter is a utility method for creating a FileLogWriter set up to
 | 
			
		||||
// output XML record log messages instead of line-based ones.
 | 
			
		||||
func NewXMLLogWriter(fname string, rotate bool) *FileLogWriter {
 | 
			
		||||
	return NewFileLogWriter(fname, rotate).SetFormat(
 | 
			
		||||
		`	<record level="%L">
 | 
			
		||||
		<timestamp>%D %T</timestamp>
 | 
			
		||||
		<source>%S</source>
 | 
			
		||||
		<message>%M</message>
 | 
			
		||||
	</record>`).SetHeadFoot("<log created=\"%D %T\">", "</log>")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										484
									
								
								vendor/github.com/alecthomas/log4go/log4go.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								vendor/github.com/alecthomas/log4go/log4go.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,484 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
// Package log4go provides level-based and highly configurable logging.
 | 
			
		||||
//
 | 
			
		||||
// Enhanced Logging
 | 
			
		||||
//
 | 
			
		||||
// This is inspired by the logging functionality in Java.  Essentially, you create a Logger
 | 
			
		||||
// object and create output filters for it.  You can send whatever you want to the Logger,
 | 
			
		||||
// and it will filter that based on your settings and send it to the outputs.  This way, you
 | 
			
		||||
// can put as much debug code in your program as you want, and when you're done you can filter
 | 
			
		||||
// out the mundane messages so only the important ones show up.
 | 
			
		||||
//
 | 
			
		||||
// Utility functions are provided to make life easier. Here is some example code to get started:
 | 
			
		||||
//
 | 
			
		||||
// log := log4go.NewLogger()
 | 
			
		||||
// log.AddFilter("stdout", log4go.DEBUG, log4go.NewConsoleLogWriter())
 | 
			
		||||
// log.AddFilter("log",    log4go.FINE,  log4go.NewFileLogWriter("example.log", true))
 | 
			
		||||
// log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
 | 
			
		||||
//
 | 
			
		||||
// The first two lines can be combined with the utility NewDefaultLogger:
 | 
			
		||||
//
 | 
			
		||||
// log := log4go.NewDefaultLogger(log4go.DEBUG)
 | 
			
		||||
// log.AddFilter("log",    log4go.FINE,  log4go.NewFileLogWriter("example.log", true))
 | 
			
		||||
// log.Info("The time is now: %s", time.LocalTime().Format("15:04:05 MST 2006/01/02"))
 | 
			
		||||
//
 | 
			
		||||
// Usage notes:
 | 
			
		||||
// - The ConsoleLogWriter does not display the source of the message to standard
 | 
			
		||||
//   output, but the FileLogWriter does.
 | 
			
		||||
// - The utility functions (Info, Debug, Warn, etc) derive their source from the
 | 
			
		||||
//   calling function, and this incurs extra overhead.
 | 
			
		||||
//
 | 
			
		||||
// Changes from 2.0:
 | 
			
		||||
// - The external interface has remained mostly stable, but a lot of the
 | 
			
		||||
//   internals have been changed, so if you depended on any of this or created
 | 
			
		||||
//   your own LogWriter, then you will probably have to update your code.  In
 | 
			
		||||
//   particular, Logger is now a map and ConsoleLogWriter is now a channel
 | 
			
		||||
//   behind-the-scenes, and the LogWrite method no longer has return values.
 | 
			
		||||
//
 | 
			
		||||
// Future work: (please let me know if you think I should work on any of these particularly)
 | 
			
		||||
// - Log file rotation
 | 
			
		||||
// - Logging configuration files ala log4j
 | 
			
		||||
// - Have the ability to remove filters?
 | 
			
		||||
// - Have GetInfoChannel, GetDebugChannel, etc return a chan string that allows
 | 
			
		||||
//   for another method of logging
 | 
			
		||||
// - Add an XML filter type
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Version information
 | 
			
		||||
const (
 | 
			
		||||
	L4G_VERSION = "log4go-v3.0.1"
 | 
			
		||||
	L4G_MAJOR   = 3
 | 
			
		||||
	L4G_MINOR   = 0
 | 
			
		||||
	L4G_BUILD   = 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/****** Constants ******/
 | 
			
		||||
 | 
			
		||||
// These are the integer logging levels used by the logger
 | 
			
		||||
type Level int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	FINEST Level = iota
 | 
			
		||||
	FINE
 | 
			
		||||
	DEBUG
 | 
			
		||||
	TRACE
 | 
			
		||||
	INFO
 | 
			
		||||
	WARNING
 | 
			
		||||
	ERROR
 | 
			
		||||
	CRITICAL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Logging level strings
 | 
			
		||||
var (
 | 
			
		||||
	levelStrings = [...]string{"FNST", "FINE", "DEBG", "TRAC", "INFO", "WARN", "EROR", "CRIT"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (l Level) String() string {
 | 
			
		||||
	if l < 0 || int(l) > len(levelStrings) {
 | 
			
		||||
		return "UNKNOWN"
 | 
			
		||||
	}
 | 
			
		||||
	return levelStrings[int(l)]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****** Variables ******/
 | 
			
		||||
var (
 | 
			
		||||
	// LogBufferLength specifies how many log messages a particular log4go
 | 
			
		||||
	// logger can buffer at a time before writing them.
 | 
			
		||||
	LogBufferLength = 32
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/****** LogRecord ******/
 | 
			
		||||
 | 
			
		||||
// A LogRecord contains all of the pertinent information for each message
 | 
			
		||||
type LogRecord struct {
 | 
			
		||||
	Level   Level     // The log level
 | 
			
		||||
	Created time.Time // The time at which the log message was created (nanoseconds)
 | 
			
		||||
	Source  string    // The message source
 | 
			
		||||
	Message string    // The log message
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****** LogWriter ******/
 | 
			
		||||
 | 
			
		||||
// This is an interface for anything that should be able to write logs
 | 
			
		||||
type LogWriter interface {
 | 
			
		||||
	// This will be called to log a LogRecord message.
 | 
			
		||||
	LogWrite(rec *LogRecord)
 | 
			
		||||
 | 
			
		||||
	// This should clean up anything lingering about the LogWriter, as it is called before
 | 
			
		||||
	// the LogWriter is removed.  LogWrite should not be called after Close.
 | 
			
		||||
	Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****** Logger ******/
 | 
			
		||||
 | 
			
		||||
// A Filter represents the log level below which no log records are written to
 | 
			
		||||
// the associated LogWriter.
 | 
			
		||||
type Filter struct {
 | 
			
		||||
	Level Level
 | 
			
		||||
	LogWriter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Logger represents a collection of Filters through which log messages are
 | 
			
		||||
// written.
 | 
			
		||||
type Logger map[string]*Filter
 | 
			
		||||
 | 
			
		||||
// Create a new logger.
 | 
			
		||||
//
 | 
			
		||||
// DEPRECATED: Use make(Logger) instead.
 | 
			
		||||
func NewLogger() Logger {
 | 
			
		||||
	os.Stderr.WriteString("warning: use of deprecated NewLogger\n")
 | 
			
		||||
	return make(Logger)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new logger with a "stdout" filter configured to send log messages at
 | 
			
		||||
// or above lvl to standard output.
 | 
			
		||||
//
 | 
			
		||||
// DEPRECATED: use NewDefaultLogger instead.
 | 
			
		||||
func NewConsoleLogger(lvl Level) Logger {
 | 
			
		||||
	os.Stderr.WriteString("warning: use of deprecated NewConsoleLogger\n")
 | 
			
		||||
	return Logger{
 | 
			
		||||
		"stdout": &Filter{lvl, NewConsoleLogWriter()},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a new logger with a "stdout" filter configured to send log messages at
 | 
			
		||||
// or above lvl to standard output.
 | 
			
		||||
func NewDefaultLogger(lvl Level) Logger {
 | 
			
		||||
	return Logger{
 | 
			
		||||
		"stdout": &Filter{lvl, NewConsoleLogWriter()},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Closes all log writers in preparation for exiting the program or a
 | 
			
		||||
// reconfiguration of logging.  Calling this is not really imperative, unless
 | 
			
		||||
// you want to guarantee that all log messages are written.  Close removes
 | 
			
		||||
// all filters (and thus all LogWriters) from the logger.
 | 
			
		||||
func (log Logger) Close() {
 | 
			
		||||
	// Close all open loggers
 | 
			
		||||
	for name, filt := range log {
 | 
			
		||||
		filt.Close()
 | 
			
		||||
		delete(log, name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Add a new LogWriter to the Logger which will only log messages at lvl or
 | 
			
		||||
// higher.  This function should not be called from multiple goroutines.
 | 
			
		||||
// Returns the logger for chaining.
 | 
			
		||||
func (log Logger) AddFilter(name string, lvl Level, writer LogWriter) Logger {
 | 
			
		||||
	log[name] = &Filter{lvl, writer}
 | 
			
		||||
	return log
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******* Logging *******/
 | 
			
		||||
// Send a formatted log message internally
 | 
			
		||||
func (log Logger) intLogf(lvl Level, format string, args ...interface{}) {
 | 
			
		||||
	skip := true
 | 
			
		||||
 | 
			
		||||
	// Determine if any logging will be done
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl >= filt.Level {
 | 
			
		||||
			skip = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if skip {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Determine caller func
 | 
			
		||||
	pc, _, lineno, ok := runtime.Caller(2)
 | 
			
		||||
	src := ""
 | 
			
		||||
	if ok {
 | 
			
		||||
		src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg := format
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		msg = fmt.Sprintf(format, args...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Make the log record
 | 
			
		||||
	rec := &LogRecord{
 | 
			
		||||
		Level:   lvl,
 | 
			
		||||
		Created: time.Now(),
 | 
			
		||||
		Source:  src,
 | 
			
		||||
		Message: msg,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dispatch the logs
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl < filt.Level {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		filt.LogWrite(rec)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a closure log message internally
 | 
			
		||||
func (log Logger) intLogc(lvl Level, closure func() string) {
 | 
			
		||||
	skip := true
 | 
			
		||||
 | 
			
		||||
	// Determine if any logging will be done
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl >= filt.Level {
 | 
			
		||||
			skip = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if skip {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Determine caller func
 | 
			
		||||
	pc, _, lineno, ok := runtime.Caller(2)
 | 
			
		||||
	src := ""
 | 
			
		||||
	if ok {
 | 
			
		||||
		src = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Make the log record
 | 
			
		||||
	rec := &LogRecord{
 | 
			
		||||
		Level:   lvl,
 | 
			
		||||
		Created: time.Now(),
 | 
			
		||||
		Source:  src,
 | 
			
		||||
		Message: closure(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dispatch the logs
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl < filt.Level {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		filt.LogWrite(rec)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a log message with manual level, source, and message.
 | 
			
		||||
func (log Logger) Log(lvl Level, source, message string) {
 | 
			
		||||
	skip := true
 | 
			
		||||
 | 
			
		||||
	// Determine if any logging will be done
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl >= filt.Level {
 | 
			
		||||
			skip = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if skip {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Make the log record
 | 
			
		||||
	rec := &LogRecord{
 | 
			
		||||
		Level:   lvl,
 | 
			
		||||
		Created: time.Now(),
 | 
			
		||||
		Source:  source,
 | 
			
		||||
		Message: message,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dispatch the logs
 | 
			
		||||
	for _, filt := range log {
 | 
			
		||||
		if lvl < filt.Level {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		filt.LogWrite(rec)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logf logs a formatted log message at the given log level, using the caller as
 | 
			
		||||
// its source.
 | 
			
		||||
func (log Logger) Logf(lvl Level, format string, args ...interface{}) {
 | 
			
		||||
	log.intLogf(lvl, format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logc logs a string returned by the closure at the given log level, using the caller as
 | 
			
		||||
// its source.  If no log message would be written, the closure is never called.
 | 
			
		||||
func (log Logger) Logc(lvl Level, closure func() string) {
 | 
			
		||||
	log.intLogc(lvl, closure)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Finest logs a message at the finest log level.
 | 
			
		||||
// See Debug for an explanation of the arguments.
 | 
			
		||||
func (log Logger) Finest(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = FINEST
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		log.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		log.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fine logs a message at the fine log level.
 | 
			
		||||
// See Debug for an explanation of the arguments.
 | 
			
		||||
func (log Logger) Fine(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = FINE
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		log.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		log.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debug is a utility method for debug log messages.
 | 
			
		||||
// The behavior of Debug depends on the first argument:
 | 
			
		||||
// - arg0 is a string
 | 
			
		||||
//   When given a string as the first argument, this behaves like Logf but with
 | 
			
		||||
//   the DEBUG log level: the first argument is interpreted as a format for the
 | 
			
		||||
//   latter arguments.
 | 
			
		||||
// - arg0 is a func()string
 | 
			
		||||
//   When given a closure of type func()string, this logs the string returned by
 | 
			
		||||
//   the closure iff it will be logged.  The closure runs at most one time.
 | 
			
		||||
// - arg0 is interface{}
 | 
			
		||||
//   When given anything else, the log message will be each of the arguments
 | 
			
		||||
//   formatted with %v and separated by spaces (ala Sprint).
 | 
			
		||||
func (log Logger) Debug(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = DEBUG
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		log.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		log.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Trace logs a message at the trace log level.
 | 
			
		||||
// See Debug for an explanation of the arguments.
 | 
			
		||||
func (log Logger) Trace(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = TRACE
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		log.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		log.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info logs a message at the info log level.
 | 
			
		||||
// See Debug for an explanation of the arguments.
 | 
			
		||||
func (log Logger) Info(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = INFO
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		log.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		log.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		log.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warn logs a message at the warning log level and returns the formatted error.
 | 
			
		||||
// At the warning level and higher, there is no performance benefit if the
 | 
			
		||||
// message is not actually logged, because all formats are processed and all
 | 
			
		||||
// closures are executed to format the error message.
 | 
			
		||||
// See Debug for further explanation of the arguments.
 | 
			
		||||
func (log Logger) Warn(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = WARNING
 | 
			
		||||
	)
 | 
			
		||||
	var msg string
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		msg = fmt.Sprintf(first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		msg = first()
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
	log.intLogf(lvl, msg)
 | 
			
		||||
	return errors.New(msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error logs a message at the error log level and returns the formatted error,
 | 
			
		||||
// See Warn for an explanation of the performance and Debug for an explanation
 | 
			
		||||
// of the parameters.
 | 
			
		||||
func (log Logger) Error(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = ERROR
 | 
			
		||||
	)
 | 
			
		||||
	var msg string
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		msg = fmt.Sprintf(first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		msg = first()
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
	log.intLogf(lvl, msg)
 | 
			
		||||
	return errors.New(msg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Critical logs a message at the critical log level and returns the formatted error,
 | 
			
		||||
// See Warn for an explanation of the performance and Debug for an explanation
 | 
			
		||||
// of the parameters.
 | 
			
		||||
func (log Logger) Critical(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = CRITICAL
 | 
			
		||||
	)
 | 
			
		||||
	var msg string
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		msg = fmt.Sprintf(first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		msg = first()
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		msg = fmt.Sprintf(fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
	log.intLogf(lvl, msg)
 | 
			
		||||
	return errors.New(msg)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								vendor/github.com/alecthomas/log4go/pattlog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								vendor/github.com/alecthomas/log4go/pattlog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	FORMAT_DEFAULT = "[%D %T] [%L] (%S) %M"
 | 
			
		||||
	FORMAT_SHORT   = "[%t %d] [%L] %M"
 | 
			
		||||
	FORMAT_ABBREV  = "[%L] %M"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type formatCacheType struct {
 | 
			
		||||
	LastUpdateSeconds    int64
 | 
			
		||||
	shortTime, shortDate string
 | 
			
		||||
	longTime, longDate   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var formatCache = &formatCacheType{}
 | 
			
		||||
 | 
			
		||||
// Known format codes:
 | 
			
		||||
// %T - Time (15:04:05 MST)
 | 
			
		||||
// %t - Time (15:04)
 | 
			
		||||
// %D - Date (2006/01/02)
 | 
			
		||||
// %d - Date (01/02/06)
 | 
			
		||||
// %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
 | 
			
		||||
// %S - Source
 | 
			
		||||
// %M - Message
 | 
			
		||||
// Ignores unknown formats
 | 
			
		||||
// Recommended: "[%D %T] [%L] (%S) %M"
 | 
			
		||||
func FormatLogRecord(format string, rec *LogRecord) string {
 | 
			
		||||
	if rec == nil {
 | 
			
		||||
		return "<nil>"
 | 
			
		||||
	}
 | 
			
		||||
	if len(format) == 0 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out := bytes.NewBuffer(make([]byte, 0, 64))
 | 
			
		||||
	secs := rec.Created.UnixNano() / 1e9
 | 
			
		||||
 | 
			
		||||
	cache := *formatCache
 | 
			
		||||
	if cache.LastUpdateSeconds != secs {
 | 
			
		||||
		month, day, year := rec.Created.Month(), rec.Created.Day(), rec.Created.Year()
 | 
			
		||||
		hour, minute, second := rec.Created.Hour(), rec.Created.Minute(), rec.Created.Second()
 | 
			
		||||
		zone, _ := rec.Created.Zone()
 | 
			
		||||
		updated := &formatCacheType{
 | 
			
		||||
			LastUpdateSeconds: secs,
 | 
			
		||||
			shortTime:         fmt.Sprintf("%02d:%02d", hour, minute),
 | 
			
		||||
			shortDate:         fmt.Sprintf("%02d/%02d/%02d", day, month, year%100),
 | 
			
		||||
			longTime:          fmt.Sprintf("%02d:%02d:%02d %s", hour, minute, second, zone),
 | 
			
		||||
			longDate:          fmt.Sprintf("%04d/%02d/%02d", year, month, day),
 | 
			
		||||
		}
 | 
			
		||||
		cache = *updated
 | 
			
		||||
		formatCache = updated
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Split the string into pieces by % signs
 | 
			
		||||
	pieces := bytes.Split([]byte(format), []byte{'%'})
 | 
			
		||||
 | 
			
		||||
	// Iterate over the pieces, replacing known formats
 | 
			
		||||
	for i, piece := range pieces {
 | 
			
		||||
		if i > 0 && len(piece) > 0 {
 | 
			
		||||
			switch piece[0] {
 | 
			
		||||
			case 'T':
 | 
			
		||||
				out.WriteString(cache.longTime)
 | 
			
		||||
			case 't':
 | 
			
		||||
				out.WriteString(cache.shortTime)
 | 
			
		||||
			case 'D':
 | 
			
		||||
				out.WriteString(cache.longDate)
 | 
			
		||||
			case 'd':
 | 
			
		||||
				out.WriteString(cache.shortDate)
 | 
			
		||||
			case 'L':
 | 
			
		||||
				out.WriteString(levelStrings[rec.Level])
 | 
			
		||||
			case 'S':
 | 
			
		||||
				out.WriteString(rec.Source)
 | 
			
		||||
			case 's':
 | 
			
		||||
				slice := strings.Split(rec.Source, "/")
 | 
			
		||||
				out.WriteString(slice[len(slice)-1])
 | 
			
		||||
			case 'M':
 | 
			
		||||
				out.WriteString(rec.Message)
 | 
			
		||||
			}
 | 
			
		||||
			if len(piece) > 1 {
 | 
			
		||||
				out.Write(piece[1:])
 | 
			
		||||
			}
 | 
			
		||||
		} else if len(piece) > 0 {
 | 
			
		||||
			out.Write(piece)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	out.WriteByte('\n')
 | 
			
		||||
 | 
			
		||||
	return out.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is the standard writer that prints to standard output.
 | 
			
		||||
type FormatLogWriter chan *LogRecord
 | 
			
		||||
 | 
			
		||||
// This creates a new FormatLogWriter
 | 
			
		||||
func NewFormatLogWriter(out io.Writer, format string) FormatLogWriter {
 | 
			
		||||
	records := make(FormatLogWriter, LogBufferLength)
 | 
			
		||||
	go records.run(out, format)
 | 
			
		||||
	return records
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w FormatLogWriter) run(out io.Writer, format string) {
 | 
			
		||||
	for rec := range w {
 | 
			
		||||
		fmt.Fprint(out, FormatLogRecord(format, rec))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is the FormatLogWriter's output method.  This will block if the output
 | 
			
		||||
// buffer is full.
 | 
			
		||||
func (w FormatLogWriter) LogWrite(rec *LogRecord) {
 | 
			
		||||
	w <- rec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close stops the logger from sending messages to standard output.  Attempts to
 | 
			
		||||
// send log messages to this logger after a Close have undefined behavior.
 | 
			
		||||
func (w FormatLogWriter) Close() {
 | 
			
		||||
	close(w)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/alecthomas/log4go/socklog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/alecthomas/log4go/socklog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This log writer sends output to a socket
 | 
			
		||||
type SocketLogWriter chan *LogRecord
 | 
			
		||||
 | 
			
		||||
// This is the SocketLogWriter's output method
 | 
			
		||||
func (w SocketLogWriter) LogWrite(rec *LogRecord) {
 | 
			
		||||
	w <- rec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w SocketLogWriter) Close() {
 | 
			
		||||
	close(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewSocketLogWriter(proto, hostport string) SocketLogWriter {
 | 
			
		||||
	sock, err := net.Dial(proto, hostport)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(os.Stderr, "NewSocketLogWriter(%q): %s\n", hostport, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w := SocketLogWriter(make(chan *LogRecord, LogBufferLength))
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if sock != nil && proto == "tcp" {
 | 
			
		||||
				sock.Close()
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		for rec := range w {
 | 
			
		||||
			// Marshall into JSON
 | 
			
		||||
			js, err := json.Marshal(rec)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = sock.Write(js)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Fprint(os.Stderr, "SocketLogWriter(%q): %s", hostport, err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/alecthomas/log4go/termlog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/alecthomas/log4go/termlog.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var stdout io.Writer = os.Stdout
 | 
			
		||||
 | 
			
		||||
// This is the standard writer that prints to standard output.
 | 
			
		||||
type ConsoleLogWriter struct {
 | 
			
		||||
	format string
 | 
			
		||||
	w      chan *LogRecord
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This creates a new ConsoleLogWriter
 | 
			
		||||
func NewConsoleLogWriter() *ConsoleLogWriter {
 | 
			
		||||
	consoleWriter := &ConsoleLogWriter{
 | 
			
		||||
		format: "[%T %D] [%L] (%S) %M",
 | 
			
		||||
		w:      make(chan *LogRecord, LogBufferLength),
 | 
			
		||||
	}
 | 
			
		||||
	go consoleWriter.run(stdout)
 | 
			
		||||
	return consoleWriter
 | 
			
		||||
}
 | 
			
		||||
func (c *ConsoleLogWriter) SetFormat(format string) {
 | 
			
		||||
	c.format = format
 | 
			
		||||
}
 | 
			
		||||
func (c *ConsoleLogWriter) run(out io.Writer) {
 | 
			
		||||
	for rec := range c.w {
 | 
			
		||||
		fmt.Fprint(out, FormatLogRecord(c.format, rec))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This is the ConsoleLogWriter's output method.  This will block if the output
 | 
			
		||||
// buffer is full.
 | 
			
		||||
func (c *ConsoleLogWriter) LogWrite(rec *LogRecord) {
 | 
			
		||||
	c.w <- rec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close stops the logger from sending messages to standard output.  Attempts to
 | 
			
		||||
// send log messages to this logger after a Close have undefined behavior.
 | 
			
		||||
func (c *ConsoleLogWriter) Close() {
 | 
			
		||||
	close(c.w)
 | 
			
		||||
	time.Sleep(50 * time.Millisecond) // Try to give console I/O time to complete
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										278
									
								
								vendor/github.com/alecthomas/log4go/wrapper.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								vendor/github.com/alecthomas/log4go/wrapper.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,278 @@
 | 
			
		||||
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
package log4go
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Global Logger
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	Global = NewDefaultLogger(DEBUG)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wrapper for (*Logger).LoadConfiguration
 | 
			
		||||
func LoadConfiguration(filename string) {
 | 
			
		||||
	Global.LoadConfiguration(filename)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wrapper for (*Logger).AddFilter
 | 
			
		||||
func AddFilter(name string, lvl Level, writer LogWriter) {
 | 
			
		||||
	Global.AddFilter(name, lvl, writer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wrapper for (*Logger).Close (closes and removes all logwriters)
 | 
			
		||||
func Close() {
 | 
			
		||||
	Global.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Crash(args ...interface{}) {
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		Global.intLogf(CRITICAL, strings.Repeat(" %v", len(args))[1:], args...)
 | 
			
		||||
	}
 | 
			
		||||
	panic(args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logs the given message and crashes the program
 | 
			
		||||
func Crashf(format string, args ...interface{}) {
 | 
			
		||||
	Global.intLogf(CRITICAL, format, args...)
 | 
			
		||||
	Global.Close() // so that hopefully the messages get logged
 | 
			
		||||
	panic(fmt.Sprintf(format, args...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Exit(args ...interface{}) {
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
 | 
			
		||||
	}
 | 
			
		||||
	Global.Close() // so that hopefully the messages get logged
 | 
			
		||||
	os.Exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Exitf(format string, args ...interface{}) {
 | 
			
		||||
	Global.intLogf(ERROR, format, args...)
 | 
			
		||||
	Global.Close() // so that hopefully the messages get logged
 | 
			
		||||
	os.Exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Stderr(args ...interface{}) {
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		Global.intLogf(ERROR, strings.Repeat(" %v", len(args))[1:], args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Stderrf(format string, args ...interface{}) {
 | 
			
		||||
	Global.intLogf(ERROR, format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Stdout(args ...interface{}) {
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		Global.intLogf(INFO, strings.Repeat(" %v", len(args))[1:], args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compatibility with `log`
 | 
			
		||||
func Stdoutf(format string, args ...interface{}) {
 | 
			
		||||
	Global.intLogf(INFO, format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a log message manually
 | 
			
		||||
// Wrapper for (*Logger).Log
 | 
			
		||||
func Log(lvl Level, source, message string) {
 | 
			
		||||
	Global.Log(lvl, source, message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a formatted log message easily
 | 
			
		||||
// Wrapper for (*Logger).Logf
 | 
			
		||||
func Logf(lvl Level, format string, args ...interface{}) {
 | 
			
		||||
	Global.intLogf(lvl, format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a closure log message
 | 
			
		||||
// Wrapper for (*Logger).Logc
 | 
			
		||||
func Logc(lvl Level, closure func() string) {
 | 
			
		||||
	Global.intLogc(lvl, closure)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for finest log messages (see Debug() for parameter explanation)
 | 
			
		||||
// Wrapper for (*Logger).Finest
 | 
			
		||||
func Finest(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = FINEST
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		Global.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for fine log messages (see Debug() for parameter explanation)
 | 
			
		||||
// Wrapper for (*Logger).Fine
 | 
			
		||||
func Fine(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = FINE
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		Global.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for debug log messages
 | 
			
		||||
// When given a string as the first argument, this behaves like Logf but with the DEBUG log level (e.g. the first argument is interpreted as a format for the latter arguments)
 | 
			
		||||
// When given a closure of type func()string, this logs the string returned by the closure iff it will be logged.  The closure runs at most one time.
 | 
			
		||||
// When given anything else, the log message will be each of the arguments formatted with %v and separated by spaces (ala Sprint).
 | 
			
		||||
// Wrapper for (*Logger).Debug
 | 
			
		||||
func Debug(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = DEBUG
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		Global.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for trace log messages (see Debug() for parameter explanation)
 | 
			
		||||
// Wrapper for (*Logger).Trace
 | 
			
		||||
func Trace(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = TRACE
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		Global.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for info log messages (see Debug() for parameter explanation)
 | 
			
		||||
// Wrapper for (*Logger).Info
 | 
			
		||||
func Info(arg0 interface{}, args ...interface{}) {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = INFO
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		Global.intLogc(lvl, first)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(arg0)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for warn log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
 | 
			
		||||
// These functions will execute a closure exactly once, to build the error message for the return
 | 
			
		||||
// Wrapper for (*Logger).Warn
 | 
			
		||||
func Warn(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = WARNING
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
		return errors.New(fmt.Sprintf(first, args...))
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		str := first()
 | 
			
		||||
		Global.intLogf(lvl, "%s", str)
 | 
			
		||||
		return errors.New(str)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for error log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
 | 
			
		||||
// These functions will execute a closure exactly once, to build the error message for the return
 | 
			
		||||
// Wrapper for (*Logger).Error
 | 
			
		||||
func Error(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = ERROR
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
		return errors.New(fmt.Sprintf(first, args...))
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		str := first()
 | 
			
		||||
		Global.intLogf(lvl, "%s", str)
 | 
			
		||||
		return errors.New(str)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Utility for critical log messages (returns an error for easy function returns) (see Debug() for parameter explanation)
 | 
			
		||||
// These functions will execute a closure exactly once, to build the error message for the return
 | 
			
		||||
// Wrapper for (*Logger).Critical
 | 
			
		||||
func Critical(arg0 interface{}, args ...interface{}) error {
 | 
			
		||||
	const (
 | 
			
		||||
		lvl = CRITICAL
 | 
			
		||||
	)
 | 
			
		||||
	switch first := arg0.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		// Use the string as a format string
 | 
			
		||||
		Global.intLogf(lvl, first, args...)
 | 
			
		||||
		return errors.New(fmt.Sprintf(first, args...))
 | 
			
		||||
	case func() string:
 | 
			
		||||
		// Log the closure (no other arguments used)
 | 
			
		||||
		str := first()
 | 
			
		||||
		Global.intLogf(lvl, "%s", str)
 | 
			
		||||
		return errors.New(str)
 | 
			
		||||
	default:
 | 
			
		||||
		// Build a format string so that it will be similar to Sprint
 | 
			
		||||
		Global.intLogf(lvl, fmt.Sprint(first)+strings.Repeat(" %v", len(args)), args...)
 | 
			
		||||
		return errors.New(fmt.Sprint(first) + fmt.Sprintf(strings.Repeat(" %v", len(args)), args...))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/gorilla/schema/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/gorilla/schema/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are
 | 
			
		||||
met:
 | 
			
		||||
 | 
			
		||||
	 * Redistributions of source code must retain the above copyright
 | 
			
		||||
notice, this list of conditions and the following disclaimer.
 | 
			
		||||
	 * Redistributions in binary form must reproduce the above
 | 
			
		||||
copyright notice, this list of conditions and the following disclaimer
 | 
			
		||||
in the documentation and/or other materials provided with the
 | 
			
		||||
distribution.
 | 
			
		||||
	 * Neither the name of Google Inc. nor the names of its
 | 
			
		||||
contributors may be used to endorse or promote products derived from
 | 
			
		||||
this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										245
									
								
								vendor/github.com/gorilla/schema/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								vendor/github.com/gorilla/schema/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
// Copyright 2012 The Gorilla 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 schema
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var invalidPath = errors.New("schema: invalid path")
 | 
			
		||||
 | 
			
		||||
// newCache returns a new cache.
 | 
			
		||||
func newCache() *cache {
 | 
			
		||||
	c := cache{
 | 
			
		||||
		m:       make(map[reflect.Type]*structInfo),
 | 
			
		||||
		conv:    make(map[reflect.Kind]Converter),
 | 
			
		||||
		regconv: make(map[reflect.Type]Converter),
 | 
			
		||||
		tag:     "schema",
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range converters {
 | 
			
		||||
		c.conv[k] = v
 | 
			
		||||
	}
 | 
			
		||||
	return &c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// cache caches meta-data about a struct.
 | 
			
		||||
type cache struct {
 | 
			
		||||
	l       sync.RWMutex
 | 
			
		||||
	m       map[reflect.Type]*structInfo
 | 
			
		||||
	conv    map[reflect.Kind]Converter
 | 
			
		||||
	regconv map[reflect.Type]Converter
 | 
			
		||||
	tag     string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parsePath parses a path in dotted notation verifying that it is a valid
 | 
			
		||||
// path to a struct field.
 | 
			
		||||
//
 | 
			
		||||
// It returns "path parts" which contain indices to fields to be used by
 | 
			
		||||
// reflect.Value.FieldByString(). Multiple parts are required for slices of
 | 
			
		||||
// structs.
 | 
			
		||||
func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) {
 | 
			
		||||
	var struc *structInfo
 | 
			
		||||
	var field *fieldInfo
 | 
			
		||||
	var index64 int64
 | 
			
		||||
	var err error
 | 
			
		||||
	parts := make([]pathPart, 0)
 | 
			
		||||
	path := make([]string, 0)
 | 
			
		||||
	keys := strings.Split(p, ".")
 | 
			
		||||
	for i := 0; i < len(keys); i++ {
 | 
			
		||||
		if t.Kind() != reflect.Struct {
 | 
			
		||||
			return nil, invalidPath
 | 
			
		||||
		}
 | 
			
		||||
		if struc = c.get(t); struc == nil {
 | 
			
		||||
			return nil, invalidPath
 | 
			
		||||
		}
 | 
			
		||||
		if field = struc.get(keys[i]); field == nil {
 | 
			
		||||
			return nil, invalidPath
 | 
			
		||||
		}
 | 
			
		||||
		// Valid field. Append index.
 | 
			
		||||
		path = append(path, field.name)
 | 
			
		||||
		if field.ss {
 | 
			
		||||
			// Parse a special case: slices of structs.
 | 
			
		||||
			// i+1 must be the slice index.
 | 
			
		||||
			//
 | 
			
		||||
			// Now that struct can implements TextUnmarshaler interface,
 | 
			
		||||
			// we don't need to force the struct's fields to appear in the path.
 | 
			
		||||
			// So checking i+2 is not necessary anymore.
 | 
			
		||||
			i++
 | 
			
		||||
			if i+1 > len(keys) {
 | 
			
		||||
				return nil, invalidPath
 | 
			
		||||
			}
 | 
			
		||||
			if index64, err = strconv.ParseInt(keys[i], 10, 0); err != nil {
 | 
			
		||||
				return nil, invalidPath
 | 
			
		||||
			}
 | 
			
		||||
			parts = append(parts, pathPart{
 | 
			
		||||
				path:  path,
 | 
			
		||||
				field: field,
 | 
			
		||||
				index: int(index64),
 | 
			
		||||
			})
 | 
			
		||||
			path = make([]string, 0)
 | 
			
		||||
 | 
			
		||||
			// Get the next struct type, dropping ptrs.
 | 
			
		||||
			if field.typ.Kind() == reflect.Ptr {
 | 
			
		||||
				t = field.typ.Elem()
 | 
			
		||||
			} else {
 | 
			
		||||
				t = field.typ
 | 
			
		||||
			}
 | 
			
		||||
			if t.Kind() == reflect.Slice {
 | 
			
		||||
				t = t.Elem()
 | 
			
		||||
				if t.Kind() == reflect.Ptr {
 | 
			
		||||
					t = t.Elem()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if field.typ.Kind() == reflect.Ptr {
 | 
			
		||||
			t = field.typ.Elem()
 | 
			
		||||
		} else {
 | 
			
		||||
			t = field.typ
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Add the remaining.
 | 
			
		||||
	parts = append(parts, pathPart{
 | 
			
		||||
		path:  path,
 | 
			
		||||
		field: field,
 | 
			
		||||
		index: -1,
 | 
			
		||||
	})
 | 
			
		||||
	return parts, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get returns a cached structInfo, creating it if necessary.
 | 
			
		||||
func (c *cache) get(t reflect.Type) *structInfo {
 | 
			
		||||
	c.l.RLock()
 | 
			
		||||
	info := c.m[t]
 | 
			
		||||
	c.l.RUnlock()
 | 
			
		||||
	if info == nil {
 | 
			
		||||
		info = c.create(t, nil)
 | 
			
		||||
		c.l.Lock()
 | 
			
		||||
		c.m[t] = info
 | 
			
		||||
		c.l.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
	return info
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create creates a structInfo with meta-data about a struct.
 | 
			
		||||
func (c *cache) create(t reflect.Type, info *structInfo) *structInfo {
 | 
			
		||||
	if info == nil {
 | 
			
		||||
		info = &structInfo{fields: []*fieldInfo{}}
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < t.NumField(); i++ {
 | 
			
		||||
		field := t.Field(i)
 | 
			
		||||
		if field.Anonymous {
 | 
			
		||||
			ft := field.Type
 | 
			
		||||
			if ft.Kind() == reflect.Ptr {
 | 
			
		||||
				ft = ft.Elem()
 | 
			
		||||
			}
 | 
			
		||||
			if ft.Kind() == reflect.Struct {
 | 
			
		||||
				c.create(ft, info)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		c.createField(field, info)
 | 
			
		||||
	}
 | 
			
		||||
	return info
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// createField creates a fieldInfo for the given field.
 | 
			
		||||
func (c *cache) createField(field reflect.StructField, info *structInfo) {
 | 
			
		||||
	alias := fieldAlias(field, c.tag)
 | 
			
		||||
	if alias == "-" {
 | 
			
		||||
		// Ignore this field.
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// Check if the type is supported and don't cache it if not.
 | 
			
		||||
	// First let's get the basic type.
 | 
			
		||||
	isSlice, isStruct := false, false
 | 
			
		||||
	ft := field.Type
 | 
			
		||||
	if ft.Kind() == reflect.Ptr {
 | 
			
		||||
		ft = ft.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	if isSlice = ft.Kind() == reflect.Slice; isSlice {
 | 
			
		||||
		ft = ft.Elem()
 | 
			
		||||
		if ft.Kind() == reflect.Ptr {
 | 
			
		||||
			ft = ft.Elem()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ft.Kind() == reflect.Array {
 | 
			
		||||
		ft = ft.Elem()
 | 
			
		||||
		if ft.Kind() == reflect.Ptr {
 | 
			
		||||
			ft = ft.Elem()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if isStruct = ft.Kind() == reflect.Struct; !isStruct {
 | 
			
		||||
		if conv := c.conv[ft.Kind()]; conv == nil {
 | 
			
		||||
			// Type is not supported.
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info.fields = append(info.fields, &fieldInfo{
 | 
			
		||||
		typ:   field.Type,
 | 
			
		||||
		name:  field.Name,
 | 
			
		||||
		ss:    isSlice && isStruct,
 | 
			
		||||
		alias: alias,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// converter returns the converter for a type.
 | 
			
		||||
func (c *cache) converter(t reflect.Type) Converter {
 | 
			
		||||
	conv := c.regconv[t]
 | 
			
		||||
	if conv == nil {
 | 
			
		||||
		conv = c.conv[t.Kind()]
 | 
			
		||||
	}
 | 
			
		||||
	return conv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
type structInfo struct {
 | 
			
		||||
	fields []*fieldInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *structInfo) get(alias string) *fieldInfo {
 | 
			
		||||
	for _, field := range i.fields {
 | 
			
		||||
		if strings.EqualFold(field.alias, alias) {
 | 
			
		||||
			return field
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type fieldInfo struct {
 | 
			
		||||
	typ   reflect.Type
 | 
			
		||||
	name  string // field name in the struct.
 | 
			
		||||
	ss    bool   // true if this is a slice of structs.
 | 
			
		||||
	alias string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pathPart struct {
 | 
			
		||||
	field *fieldInfo
 | 
			
		||||
	path  []string // path to the field: walks structs using field names.
 | 
			
		||||
	index int      // struct index in slices of structs.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// fieldAlias parses a field tag to get a field alias.
 | 
			
		||||
func fieldAlias(field reflect.StructField, tagName string) string {
 | 
			
		||||
	var alias string
 | 
			
		||||
	if tag := field.Tag.Get(tagName); tag != "" {
 | 
			
		||||
		// For now tags only support the name but let's follow the
 | 
			
		||||
		// comma convention from encoding/json and others.
 | 
			
		||||
		if idx := strings.Index(tag, ","); idx == -1 {
 | 
			
		||||
			alias = tag
 | 
			
		||||
		} else {
 | 
			
		||||
			alias = tag[:idx]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if alias == "" {
 | 
			
		||||
		alias = field.Name
 | 
			
		||||
	}
 | 
			
		||||
	return alias
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								vendor/github.com/gorilla/schema/converter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								vendor/github.com/gorilla/schema/converter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
// Copyright 2012 The Gorilla 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 schema
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Converter func(string) reflect.Value
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	invalidValue = reflect.Value{}
 | 
			
		||||
	boolType     = reflect.Bool
 | 
			
		||||
	float32Type  = reflect.Float32
 | 
			
		||||
	float64Type  = reflect.Float64
 | 
			
		||||
	intType      = reflect.Int
 | 
			
		||||
	int8Type     = reflect.Int8
 | 
			
		||||
	int16Type    = reflect.Int16
 | 
			
		||||
	int32Type    = reflect.Int32
 | 
			
		||||
	int64Type    = reflect.Int64
 | 
			
		||||
	stringType   = reflect.String
 | 
			
		||||
	uintType     = reflect.Uint
 | 
			
		||||
	uint8Type    = reflect.Uint8
 | 
			
		||||
	uint16Type   = reflect.Uint16
 | 
			
		||||
	uint32Type   = reflect.Uint32
 | 
			
		||||
	uint64Type   = reflect.Uint64
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Default converters for basic types.
 | 
			
		||||
var converters = map[reflect.Kind]Converter{
 | 
			
		||||
	boolType:    convertBool,
 | 
			
		||||
	float32Type: convertFloat32,
 | 
			
		||||
	float64Type: convertFloat64,
 | 
			
		||||
	intType:     convertInt,
 | 
			
		||||
	int8Type:    convertInt8,
 | 
			
		||||
	int16Type:   convertInt16,
 | 
			
		||||
	int32Type:   convertInt32,
 | 
			
		||||
	int64Type:   convertInt64,
 | 
			
		||||
	stringType:  convertString,
 | 
			
		||||
	uintType:    convertUint,
 | 
			
		||||
	uint8Type:   convertUint8,
 | 
			
		||||
	uint16Type:  convertUint16,
 | 
			
		||||
	uint32Type:  convertUint32,
 | 
			
		||||
	uint64Type:  convertUint64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertBool(value string) reflect.Value {
 | 
			
		||||
	if value == "on" {
 | 
			
		||||
		return reflect.ValueOf(true)
 | 
			
		||||
	} else if v, err := strconv.ParseBool(value); err == nil {
 | 
			
		||||
		return reflect.ValueOf(v)
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertFloat32(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseFloat(value, 32); err == nil {
 | 
			
		||||
		return reflect.ValueOf(float32(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertFloat64(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseFloat(value, 64); err == nil {
 | 
			
		||||
		return reflect.ValueOf(v)
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseInt(value, 10, 0); err == nil {
 | 
			
		||||
		return reflect.ValueOf(int(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt8(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseInt(value, 10, 8); err == nil {
 | 
			
		||||
		return reflect.ValueOf(int8(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt16(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseInt(value, 10, 16); err == nil {
 | 
			
		||||
		return reflect.ValueOf(int16(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt32(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseInt(value, 10, 32); err == nil {
 | 
			
		||||
		return reflect.ValueOf(int32(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt64(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseInt(value, 10, 64); err == nil {
 | 
			
		||||
		return reflect.ValueOf(v)
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertString(value string) reflect.Value {
 | 
			
		||||
	return reflect.ValueOf(value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertUint(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseUint(value, 10, 0); err == nil {
 | 
			
		||||
		return reflect.ValueOf(uint(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertUint8(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseUint(value, 10, 8); err == nil {
 | 
			
		||||
		return reflect.ValueOf(uint8(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertUint16(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseUint(value, 10, 16); err == nil {
 | 
			
		||||
		return reflect.ValueOf(uint16(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertUint32(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseUint(value, 10, 32); err == nil {
 | 
			
		||||
		return reflect.ValueOf(uint32(v))
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertUint64(value string) reflect.Value {
 | 
			
		||||
	if v, err := strconv.ParseUint(value, 10, 64); err == nil {
 | 
			
		||||
		return reflect.ValueOf(v)
 | 
			
		||||
	}
 | 
			
		||||
	return invalidValue
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										299
									
								
								vendor/github.com/gorilla/schema/decoder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								vendor/github.com/gorilla/schema/decoder.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,299 @@
 | 
			
		||||
// Copyright 2012 The Gorilla 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 schema
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewDecoder returns a new Decoder.
 | 
			
		||||
func NewDecoder() *Decoder {
 | 
			
		||||
	return &Decoder{cache: newCache()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decoder decodes values from a map[string][]string to a struct.
 | 
			
		||||
type Decoder struct {
 | 
			
		||||
	cache             *cache
 | 
			
		||||
	zeroEmpty         bool
 | 
			
		||||
	ignoreUnknownKeys bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetAliasTag changes the tag used to locate custom field aliases.
 | 
			
		||||
// The default tag is "schema".
 | 
			
		||||
func (d *Decoder) SetAliasTag(tag string) {
 | 
			
		||||
	d.cache.tag = tag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ZeroEmpty controls the behaviour when the decoder encounters empty values
 | 
			
		||||
// in a map.
 | 
			
		||||
// If z is true and a key in the map has the empty string as a value
 | 
			
		||||
// then the corresponding struct field is set to the zero value.
 | 
			
		||||
// If z is false then empty strings are ignored.
 | 
			
		||||
//
 | 
			
		||||
// The default value is false, that is empty values do not change
 | 
			
		||||
// the value of the struct field.
 | 
			
		||||
func (d *Decoder) ZeroEmpty(z bool) {
 | 
			
		||||
	d.zeroEmpty = z
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IgnoreUnknownKeys controls the behaviour when the decoder encounters unknown
 | 
			
		||||
// keys in the map.
 | 
			
		||||
// If i is true and an unknown field is encountered, it is ignored. This is
 | 
			
		||||
// similar to how unknown keys are handled by encoding/json.
 | 
			
		||||
// If i is false then Decode will return an error. Note that any valid keys
 | 
			
		||||
// will still be decoded in to the target struct.
 | 
			
		||||
//
 | 
			
		||||
// To preserve backwards compatibility, the default value is false.
 | 
			
		||||
func (d *Decoder) IgnoreUnknownKeys(i bool) {
 | 
			
		||||
	d.ignoreUnknownKeys = i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegisterConverter registers a converter function for a custom type.
 | 
			
		||||
func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) {
 | 
			
		||||
	d.cache.regconv[reflect.TypeOf(value)] = converterFunc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decode decodes a map[string][]string to a struct.
 | 
			
		||||
//
 | 
			
		||||
// The first parameter must be a pointer to a struct.
 | 
			
		||||
//
 | 
			
		||||
// The second parameter is a map, typically url.Values from an HTTP request.
 | 
			
		||||
// Keys are "paths" in dotted notation to the struct fields and nested structs.
 | 
			
		||||
//
 | 
			
		||||
// See the package documentation for a full explanation of the mechanics.
 | 
			
		||||
func (d *Decoder) Decode(dst interface{}, src map[string][]string) error {
 | 
			
		||||
	v := reflect.ValueOf(dst)
 | 
			
		||||
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
 | 
			
		||||
		return errors.New("schema: interface must be a pointer to struct")
 | 
			
		||||
	}
 | 
			
		||||
	v = v.Elem()
 | 
			
		||||
	t := v.Type()
 | 
			
		||||
	errors := MultiError{}
 | 
			
		||||
	for path, values := range src {
 | 
			
		||||
		if parts, err := d.cache.parsePath(path, t); err == nil {
 | 
			
		||||
			if err = d.decode(v, path, parts, values); err != nil {
 | 
			
		||||
				errors[path] = err
 | 
			
		||||
			}
 | 
			
		||||
		} else if !d.ignoreUnknownKeys {
 | 
			
		||||
			errors[path] = fmt.Errorf("schema: invalid path %q", path)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(errors) > 0 {
 | 
			
		||||
		return errors
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// decode fills a struct field using a parsed path.
 | 
			
		||||
func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values []string) error {
 | 
			
		||||
	// Get the field walking the struct fields by index.
 | 
			
		||||
	for _, name := range parts[0].path {
 | 
			
		||||
		if v.Type().Kind() == reflect.Ptr {
 | 
			
		||||
			if v.IsNil() {
 | 
			
		||||
				v.Set(reflect.New(v.Type().Elem()))
 | 
			
		||||
			}
 | 
			
		||||
			v = v.Elem()
 | 
			
		||||
		}
 | 
			
		||||
		v = v.FieldByName(name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Don't even bother for unexported fields.
 | 
			
		||||
	if !v.CanSet() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Dereference if needed.
 | 
			
		||||
	t := v.Type()
 | 
			
		||||
	if t.Kind() == reflect.Ptr {
 | 
			
		||||
		t = t.Elem()
 | 
			
		||||
		if v.IsNil() {
 | 
			
		||||
			v.Set(reflect.New(t))
 | 
			
		||||
		}
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Slice of structs. Let's go recursive.
 | 
			
		||||
	if len(parts) > 1 {
 | 
			
		||||
		idx := parts[0].index
 | 
			
		||||
		if v.IsNil() || v.Len() < idx+1 {
 | 
			
		||||
			value := reflect.MakeSlice(t, idx+1, idx+1)
 | 
			
		||||
			if v.Len() < idx+1 {
 | 
			
		||||
				// Resize it.
 | 
			
		||||
				reflect.Copy(value, v)
 | 
			
		||||
			}
 | 
			
		||||
			v.Set(value)
 | 
			
		||||
		}
 | 
			
		||||
		return d.decode(v.Index(idx), path, parts[1:], values)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the converter early in case there is one for a slice type.
 | 
			
		||||
	conv := d.cache.converter(t)
 | 
			
		||||
	if conv == nil && t.Kind() == reflect.Slice {
 | 
			
		||||
		var items []reflect.Value
 | 
			
		||||
		elemT := t.Elem()
 | 
			
		||||
		isPtrElem := elemT.Kind() == reflect.Ptr
 | 
			
		||||
		if isPtrElem {
 | 
			
		||||
			elemT = elemT.Elem()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Try to get a converter for the element type.
 | 
			
		||||
		conv := d.cache.converter(elemT)
 | 
			
		||||
		if conv == nil {
 | 
			
		||||
			// As we are not dealing with slice of structs here, we don't need to check if the type
 | 
			
		||||
			// implements TextUnmarshaler interface
 | 
			
		||||
			return fmt.Errorf("schema: converter not found for %v", elemT)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for key, value := range values {
 | 
			
		||||
			if value == "" {
 | 
			
		||||
				if d.zeroEmpty {
 | 
			
		||||
					items = append(items, reflect.Zero(elemT))
 | 
			
		||||
				}
 | 
			
		||||
			} else if item := conv(value); item.IsValid() {
 | 
			
		||||
				if isPtrElem {
 | 
			
		||||
					ptr := reflect.New(elemT)
 | 
			
		||||
					ptr.Elem().Set(item)
 | 
			
		||||
					item = ptr
 | 
			
		||||
				}
 | 
			
		||||
				if item.Type() != elemT && !isPtrElem {
 | 
			
		||||
					item = item.Convert(elemT)
 | 
			
		||||
				}
 | 
			
		||||
				items = append(items, item)
 | 
			
		||||
			} else {
 | 
			
		||||
				if strings.Contains(value, ",") {
 | 
			
		||||
					values := strings.Split(value, ",")
 | 
			
		||||
					for _, value := range values {
 | 
			
		||||
						if value == "" {
 | 
			
		||||
							if d.zeroEmpty {
 | 
			
		||||
								items = append(items, reflect.Zero(elemT))
 | 
			
		||||
							}
 | 
			
		||||
						} else if item := conv(value); item.IsValid() {
 | 
			
		||||
							if isPtrElem {
 | 
			
		||||
								ptr := reflect.New(elemT)
 | 
			
		||||
								ptr.Elem().Set(item)
 | 
			
		||||
								item = ptr
 | 
			
		||||
							}
 | 
			
		||||
							if item.Type() != elemT && !isPtrElem {
 | 
			
		||||
								item = item.Convert(elemT)
 | 
			
		||||
							}
 | 
			
		||||
							items = append(items, item)
 | 
			
		||||
						} else {
 | 
			
		||||
							return ConversionError{
 | 
			
		||||
								Key:   path,
 | 
			
		||||
								Type:  elemT,
 | 
			
		||||
								Index: key,
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					return ConversionError{
 | 
			
		||||
						Key:   path,
 | 
			
		||||
						Type:  elemT,
 | 
			
		||||
						Index: key,
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		value := reflect.Append(reflect.MakeSlice(t, 0, 0), items...)
 | 
			
		||||
		v.Set(value)
 | 
			
		||||
	} else {
 | 
			
		||||
		val := ""
 | 
			
		||||
		// Use the last value provided if any values were provided
 | 
			
		||||
		if len(values) > 0 {
 | 
			
		||||
			val = values[len(values)-1]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if val == "" {
 | 
			
		||||
			if d.zeroEmpty {
 | 
			
		||||
				v.Set(reflect.Zero(t))
 | 
			
		||||
			}
 | 
			
		||||
		} else if conv != nil {
 | 
			
		||||
			if value := conv(val); value.IsValid() {
 | 
			
		||||
				v.Set(value.Convert(t))
 | 
			
		||||
			} else {
 | 
			
		||||
				return ConversionError{
 | 
			
		||||
					Key:   path,
 | 
			
		||||
					Type:  t,
 | 
			
		||||
					Index: -1,
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// When there's no registered conversion for the custom type, we will check if the type
 | 
			
		||||
			// implements the TextUnmarshaler interface. As the UnmarshalText function should be applied
 | 
			
		||||
			// to the pointer of the type, we convert the value to pointer.
 | 
			
		||||
			if v.CanAddr() {
 | 
			
		||||
				v = v.Addr()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
 | 
			
		||||
				if err := u.UnmarshalText([]byte(val)); err != nil {
 | 
			
		||||
					return ConversionError{
 | 
			
		||||
						Key:   path,
 | 
			
		||||
						Type:  t,
 | 
			
		||||
						Index: -1,
 | 
			
		||||
						Err:   err,
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
				return fmt.Errorf("schema: converter not found for %v", t)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errors ---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// ConversionError stores information about a failed conversion.
 | 
			
		||||
type ConversionError struct {
 | 
			
		||||
	Key   string       // key from the source map.
 | 
			
		||||
	Type  reflect.Type // expected type of elem
 | 
			
		||||
	Index int          // index for multi-value fields; -1 for single-value fields.
 | 
			
		||||
	Err   error        // low-level error (when it exists)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e ConversionError) Error() string {
 | 
			
		||||
	var output string
 | 
			
		||||
 | 
			
		||||
	if e.Index < 0 {
 | 
			
		||||
		output = fmt.Sprintf("schema: error converting value for %q", e.Key)
 | 
			
		||||
	} else {
 | 
			
		||||
		output = fmt.Sprintf("schema: error converting value for index %d of %q",
 | 
			
		||||
			e.Index, e.Key)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if e.Err != nil {
 | 
			
		||||
		output = fmt.Sprintf("%s. Details: %s", output, e.Err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return output
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MultiError stores multiple decoding errors.
 | 
			
		||||
//
 | 
			
		||||
// Borrowed from the App Engine SDK.
 | 
			
		||||
type MultiError map[string]error
 | 
			
		||||
 | 
			
		||||
func (e MultiError) Error() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	for _, err := range e {
 | 
			
		||||
		s = err.Error()
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	switch len(e) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return "(0 errors)"
 | 
			
		||||
	case 1:
 | 
			
		||||
		return s
 | 
			
		||||
	case 2:
 | 
			
		||||
		return s + " (and 1 other error)"
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%s (and %d other errors)", s, len(e)-1)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								vendor/github.com/gorilla/schema/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								vendor/github.com/gorilla/schema/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
// Copyright 2012 The Gorilla 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 gorilla/schema fills a struct with form values.
 | 
			
		||||
 | 
			
		||||
The basic usage is really simple. Given this struct:
 | 
			
		||||
 | 
			
		||||
	type Person struct {
 | 
			
		||||
		Name  string
 | 
			
		||||
		Phone string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
...we can fill it passing a map to the Load() function:
 | 
			
		||||
 | 
			
		||||
	values := map[string][]string{
 | 
			
		||||
		"Name":  {"John"},
 | 
			
		||||
		"Phone": {"999-999-999"},
 | 
			
		||||
	}
 | 
			
		||||
	person := new(Person)
 | 
			
		||||
	decoder := schema.NewDecoder()
 | 
			
		||||
	decoder.Decode(person, values)
 | 
			
		||||
 | 
			
		||||
This is just a simple example and it doesn't make a lot of sense to create
 | 
			
		||||
the map manually. Typically it will come from a http.Request object and
 | 
			
		||||
will be of type url.Values: http.Request.Form or http.Request.MultipartForm:
 | 
			
		||||
 | 
			
		||||
	func MyHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := r.ParseForm()
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Handle error
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		decoder := schema.NewDecoder()
 | 
			
		||||
		// r.PostForm is a map of our POST form values
 | 
			
		||||
		err := decoder.Decode(person, r.PostForm)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Handle error
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Do something with person.Name or person.Phone
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
Note: it is a good idea to set a Decoder instance as a package global,
 | 
			
		||||
because it caches meta-data about structs, and a instance can be shared safely:
 | 
			
		||||
 | 
			
		||||
	var decoder = schema.NewDecoder()
 | 
			
		||||
 | 
			
		||||
To define custom names for fields, use a struct tag "schema". To not populate
 | 
			
		||||
certain fields, use a dash for the name and it will be ignored:
 | 
			
		||||
 | 
			
		||||
	type Person struct {
 | 
			
		||||
		Name  string `schema:"name"`  // custom name
 | 
			
		||||
		Phone string `schema:"phone"` // custom name
 | 
			
		||||
		Admin bool   `schema:"-"`     // this field is never set
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
The supported field types in the destination struct are:
 | 
			
		||||
 | 
			
		||||
	* bool
 | 
			
		||||
	* float variants (float32, float64)
 | 
			
		||||
	* int variants (int, int8, int16, int32, int64)
 | 
			
		||||
	* string
 | 
			
		||||
	* uint variants (uint, uint8, uint16, uint32, uint64)
 | 
			
		||||
	* struct
 | 
			
		||||
	* a pointer to one of the above types
 | 
			
		||||
	* a slice or a pointer to a slice of one of the above types
 | 
			
		||||
 | 
			
		||||
Non-supported types are simply ignored, however custom types can be registered
 | 
			
		||||
to be converted.
 | 
			
		||||
 | 
			
		||||
To fill nested structs, keys must use a dotted notation as the "path" for the
 | 
			
		||||
field. So for example, to fill the struct Person below:
 | 
			
		||||
 | 
			
		||||
	type Phone struct {
 | 
			
		||||
		Label  string
 | 
			
		||||
		Number string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type Person struct {
 | 
			
		||||
		Name  string
 | 
			
		||||
		Phone Phone
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
...the source map must have the keys "Name", "Phone.Label" and "Phone.Number".
 | 
			
		||||
This means that an HTML form to fill a Person struct must look like this:
 | 
			
		||||
 | 
			
		||||
	<form>
 | 
			
		||||
		<input type="text" name="Name">
 | 
			
		||||
		<input type="text" name="Phone.Label">
 | 
			
		||||
		<input type="text" name="Phone.Number">
 | 
			
		||||
	</form>
 | 
			
		||||
 | 
			
		||||
Single values are filled using the first value for a key from the source map.
 | 
			
		||||
Slices are filled using all values for a key from the source map. So to fill
 | 
			
		||||
a Person with multiple Phone values, like:
 | 
			
		||||
 | 
			
		||||
	type Person struct {
 | 
			
		||||
		Name   string
 | 
			
		||||
		Phones []Phone
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
...an HTML form that accepts three Phone values would look like this:
 | 
			
		||||
 | 
			
		||||
	<form>
 | 
			
		||||
		<input type="text" name="Name">
 | 
			
		||||
		<input type="text" name="Phones.0.Label">
 | 
			
		||||
		<input type="text" name="Phones.0.Number">
 | 
			
		||||
		<input type="text" name="Phones.1.Label">
 | 
			
		||||
		<input type="text" name="Phones.1.Number">
 | 
			
		||||
		<input type="text" name="Phones.2.Label">
 | 
			
		||||
		<input type="text" name="Phones.2.Number">
 | 
			
		||||
	</form>
 | 
			
		||||
 | 
			
		||||
Notice that only for slices of structs the slice index is required.
 | 
			
		||||
This is needed for disambiguation: if the nested struct also had a slice
 | 
			
		||||
field, we could not translate multiple values to it if we did not use an
 | 
			
		||||
index for the parent struct.
 | 
			
		||||
 | 
			
		||||
There's also the possibility to create a custom type that implements the
 | 
			
		||||
TextUnmarshaler interface, and in this case there's no need to registry
 | 
			
		||||
a converter, like:
 | 
			
		||||
 | 
			
		||||
	type Person struct {
 | 
			
		||||
	  Emails []Email
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type Email struct {
 | 
			
		||||
	  *mail.Address
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	func (e *Email) UnmarshalText(text []byte) (err error) {
 | 
			
		||||
		e.Address, err = mail.ParseAddress(string(text))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
...an HTML form that accepts three Email values would look like this:
 | 
			
		||||
 | 
			
		||||
	<form>
 | 
			
		||||
		<input type="email" name="Emails.0">
 | 
			
		||||
		<input type="email" name="Emails.1">
 | 
			
		||||
		<input type="email" name="Emails.2">
 | 
			
		||||
	</form>
 | 
			
		||||
*/
 | 
			
		||||
package schema
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/gorilla/websocket/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/gorilla/websocket/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
  Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
  Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
  this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
  and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										350
									
								
								vendor/github.com/gorilla/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								vendor/github.com/gorilla/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,350 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrBadHandshake is returned when the server response to opening handshake is
 | 
			
		||||
// invalid.
 | 
			
		||||
var ErrBadHandshake = errors.New("websocket: bad handshake")
 | 
			
		||||
 | 
			
		||||
// NewClient creates a new client connection using the given net connection.
 | 
			
		||||
// The URL u specifies the host and request URI. Use requestHeader to specify
 | 
			
		||||
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
 | 
			
		||||
// (Cookie). Use the response.Header to get the selected subprotocol
 | 
			
		||||
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
 | 
			
		||||
//
 | 
			
		||||
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
 | 
			
		||||
// non-nil *http.Response so that callers can handle redirects, authentication,
 | 
			
		||||
// etc.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: Use Dialer instead.
 | 
			
		||||
func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
 | 
			
		||||
	d := Dialer{
 | 
			
		||||
		ReadBufferSize:  readBufSize,
 | 
			
		||||
		WriteBufferSize: writeBufSize,
 | 
			
		||||
		NetDial: func(net, addr string) (net.Conn, error) {
 | 
			
		||||
			return netConn, nil
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return d.Dial(u.String(), requestHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Dialer contains options for connecting to WebSocket server.
 | 
			
		||||
type Dialer struct {
 | 
			
		||||
	// NetDial specifies the dial function for creating TCP connections. If
 | 
			
		||||
	// NetDial is nil, net.Dial is used.
 | 
			
		||||
	NetDial func(network, addr string) (net.Conn, error)
 | 
			
		||||
 | 
			
		||||
	// Proxy specifies a function to return a proxy for a given
 | 
			
		||||
	// Request. If the function returns a non-nil error, the
 | 
			
		||||
	// request is aborted with the provided error.
 | 
			
		||||
	// If Proxy is nil or returns a nil *URL, no proxy is used.
 | 
			
		||||
	Proxy func(*http.Request) (*url.URL, error)
 | 
			
		||||
 | 
			
		||||
	// TLSClientConfig specifies the TLS configuration to use with tls.Client.
 | 
			
		||||
	// If nil, the default configuration is used.
 | 
			
		||||
	TLSClientConfig *tls.Config
 | 
			
		||||
 | 
			
		||||
	// HandshakeTimeout specifies the duration for the handshake to complete.
 | 
			
		||||
	HandshakeTimeout time.Duration
 | 
			
		||||
 | 
			
		||||
	// Input and output buffer sizes. If the buffer size is zero, then a
 | 
			
		||||
	// default value of 4096 is used.
 | 
			
		||||
	ReadBufferSize, WriteBufferSize int
 | 
			
		||||
 | 
			
		||||
	// Subprotocols specifies the client's requested subprotocols.
 | 
			
		||||
	Subprotocols []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errMalformedURL = errors.New("malformed ws or wss URL")
 | 
			
		||||
 | 
			
		||||
// parseURL parses the URL.
 | 
			
		||||
//
 | 
			
		||||
// This function is a replacement for the standard library url.Parse function.
 | 
			
		||||
// In Go 1.4 and earlier, url.Parse loses information from the path.
 | 
			
		||||
func parseURL(s string) (*url.URL, error) {
 | 
			
		||||
	// From the RFC:
 | 
			
		||||
	//
 | 
			
		||||
	// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
 | 
			
		||||
	// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
 | 
			
		||||
 | 
			
		||||
	var u url.URL
 | 
			
		||||
	switch {
 | 
			
		||||
	case strings.HasPrefix(s, "ws://"):
 | 
			
		||||
		u.Scheme = "ws"
 | 
			
		||||
		s = s[len("ws://"):]
 | 
			
		||||
	case strings.HasPrefix(s, "wss://"):
 | 
			
		||||
		u.Scheme = "wss"
 | 
			
		||||
		s = s[len("wss://"):]
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errMalformedURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if i := strings.Index(s, "?"); i >= 0 {
 | 
			
		||||
		u.RawQuery = s[i+1:]
 | 
			
		||||
		s = s[:i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if i := strings.Index(s, "/"); i >= 0 {
 | 
			
		||||
		u.Opaque = s[i:]
 | 
			
		||||
		s = s[:i]
 | 
			
		||||
	} else {
 | 
			
		||||
		u.Opaque = "/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u.Host = s
 | 
			
		||||
 | 
			
		||||
	if strings.Contains(u.Host, "@") {
 | 
			
		||||
		// Don't bother parsing user information because user information is
 | 
			
		||||
		// not allowed in websocket URIs.
 | 
			
		||||
		return nil, errMalformedURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &u, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
 | 
			
		||||
	hostPort = u.Host
 | 
			
		||||
	hostNoPort = u.Host
 | 
			
		||||
	if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
 | 
			
		||||
		hostNoPort = hostNoPort[:i]
 | 
			
		||||
	} else {
 | 
			
		||||
		switch u.Scheme {
 | 
			
		||||
		case "wss":
 | 
			
		||||
			hostPort += ":443"
 | 
			
		||||
		case "https":
 | 
			
		||||
			hostPort += ":443"
 | 
			
		||||
		default:
 | 
			
		||||
			hostPort += ":80"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return hostPort, hostNoPort
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultDialer is a dialer with all fields set to the default zero values.
 | 
			
		||||
var DefaultDialer = &Dialer{
 | 
			
		||||
	Proxy: http.ProxyFromEnvironment,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial creates a new client connection. Use requestHeader to specify the
 | 
			
		||||
// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
 | 
			
		||||
// Use the response.Header to get the selected subprotocol
 | 
			
		||||
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
 | 
			
		||||
//
 | 
			
		||||
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
 | 
			
		||||
// non-nil *http.Response so that callers can handle redirects, authentication,
 | 
			
		||||
// etcetera. The response body may not contain the entire response and does not
 | 
			
		||||
// need to be closed by the application.
 | 
			
		||||
func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
 | 
			
		||||
 | 
			
		||||
	if d == nil {
 | 
			
		||||
		d = &Dialer{
 | 
			
		||||
			Proxy: http.ProxyFromEnvironment,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	challengeKey, err := generateChallengeKey()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u, err := parseURL(urlStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch u.Scheme {
 | 
			
		||||
	case "ws":
 | 
			
		||||
		u.Scheme = "http"
 | 
			
		||||
	case "wss":
 | 
			
		||||
		u.Scheme = "https"
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, nil, errMalformedURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u.User != nil {
 | 
			
		||||
		// User name and password are not allowed in websocket URIs.
 | 
			
		||||
		return nil, nil, errMalformedURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req := &http.Request{
 | 
			
		||||
		Method:     "GET",
 | 
			
		||||
		URL:        u,
 | 
			
		||||
		Proto:      "HTTP/1.1",
 | 
			
		||||
		ProtoMajor: 1,
 | 
			
		||||
		ProtoMinor: 1,
 | 
			
		||||
		Header:     make(http.Header),
 | 
			
		||||
		Host:       u.Host,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Set the request headers using the capitalization for names and values in
 | 
			
		||||
	// RFC examples. Although the capitalization shouldn't matter, there are
 | 
			
		||||
	// servers that depend on it. The Header.Set method is not used because the
 | 
			
		||||
	// method canonicalizes the header names.
 | 
			
		||||
	req.Header["Upgrade"] = []string{"websocket"}
 | 
			
		||||
	req.Header["Connection"] = []string{"Upgrade"}
 | 
			
		||||
	req.Header["Sec-WebSocket-Key"] = []string{challengeKey}
 | 
			
		||||
	req.Header["Sec-WebSocket-Version"] = []string{"13"}
 | 
			
		||||
	if len(d.Subprotocols) > 0 {
 | 
			
		||||
		req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")}
 | 
			
		||||
	}
 | 
			
		||||
	for k, vs := range requestHeader {
 | 
			
		||||
		switch {
 | 
			
		||||
		case k == "Host":
 | 
			
		||||
			if len(vs) > 0 {
 | 
			
		||||
				req.Host = vs[0]
 | 
			
		||||
			}
 | 
			
		||||
		case k == "Upgrade" ||
 | 
			
		||||
			k == "Connection" ||
 | 
			
		||||
			k == "Sec-Websocket-Key" ||
 | 
			
		||||
			k == "Sec-Websocket-Version" ||
 | 
			
		||||
			(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0):
 | 
			
		||||
			return nil, nil, errors.New("websocket: duplicate header not allowed: " + k)
 | 
			
		||||
		default:
 | 
			
		||||
			req.Header[k] = vs
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hostPort, hostNoPort := hostPortNoPort(u)
 | 
			
		||||
 | 
			
		||||
	var proxyURL *url.URL
 | 
			
		||||
	// Check wether the proxy method has been configured
 | 
			
		||||
	if d.Proxy != nil {
 | 
			
		||||
		proxyURL, err = d.Proxy(req)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var targetHostPort string
 | 
			
		||||
	if proxyURL != nil {
 | 
			
		||||
		targetHostPort, _ = hostPortNoPort(proxyURL)
 | 
			
		||||
	} else {
 | 
			
		||||
		targetHostPort = hostPort
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var deadline time.Time
 | 
			
		||||
	if d.HandshakeTimeout != 0 {
 | 
			
		||||
		deadline = time.Now().Add(d.HandshakeTimeout)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	netDial := d.NetDial
 | 
			
		||||
	if netDial == nil {
 | 
			
		||||
		netDialer := &net.Dialer{Deadline: deadline}
 | 
			
		||||
		netDial = netDialer.Dial
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	netConn, err := netDial("tcp", targetHostPort)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if netConn != nil {
 | 
			
		||||
			netConn.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if err := netConn.SetDeadline(deadline); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if proxyURL != nil {
 | 
			
		||||
		connectHeader := make(http.Header)
 | 
			
		||||
		if user := proxyURL.User; user != nil {
 | 
			
		||||
			proxyUser := user.Username()
 | 
			
		||||
			if proxyPassword, passwordSet := user.Password(); passwordSet {
 | 
			
		||||
				credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
 | 
			
		||||
				connectHeader.Set("Proxy-Authorization", "Basic "+credential)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		connectReq := &http.Request{
 | 
			
		||||
			Method: "CONNECT",
 | 
			
		||||
			URL:    &url.URL{Opaque: hostPort},
 | 
			
		||||
			Host:   hostPort,
 | 
			
		||||
			Header: connectHeader,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		connectReq.Write(netConn)
 | 
			
		||||
 | 
			
		||||
		// Read response.
 | 
			
		||||
		// Okay to use and discard buffered reader here, because
 | 
			
		||||
		// TLS server will not speak until spoken to.
 | 
			
		||||
		br := bufio.NewReader(netConn)
 | 
			
		||||
		resp, err := http.ReadResponse(br, connectReq)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if resp.StatusCode != 200 {
 | 
			
		||||
			f := strings.SplitN(resp.Status, " ", 2)
 | 
			
		||||
			return nil, nil, errors.New(f[1])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u.Scheme == "https" {
 | 
			
		||||
		cfg := d.TLSClientConfig
 | 
			
		||||
		if cfg == nil {
 | 
			
		||||
			cfg = &tls.Config{ServerName: hostNoPort}
 | 
			
		||||
		} else if cfg.ServerName == "" {
 | 
			
		||||
			shallowCopy := *cfg
 | 
			
		||||
			cfg = &shallowCopy
 | 
			
		||||
			cfg.ServerName = hostNoPort
 | 
			
		||||
		}
 | 
			
		||||
		tlsConn := tls.Client(netConn, cfg)
 | 
			
		||||
		netConn = tlsConn
 | 
			
		||||
		if err := tlsConn.Handshake(); err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if !cfg.InsecureSkipVerify {
 | 
			
		||||
			if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
 | 
			
		||||
				return nil, nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize)
 | 
			
		||||
 | 
			
		||||
	if err := req.Write(netConn); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := http.ReadResponse(conn.br, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.StatusCode != 101 ||
 | 
			
		||||
		!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
 | 
			
		||||
		!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
 | 
			
		||||
		resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) {
 | 
			
		||||
		// Before closing the network connection on return from this
 | 
			
		||||
		// function, slurp up some of the response to aid application
 | 
			
		||||
		// debugging.
 | 
			
		||||
		buf := make([]byte, 1024)
 | 
			
		||||
		n, _ := io.ReadFull(resp.Body, buf)
 | 
			
		||||
		resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n]))
 | 
			
		||||
		return nil, resp, ErrBadHandshake
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
 | 
			
		||||
	conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
 | 
			
		||||
 | 
			
		||||
	netConn.SetDeadline(time.Time{})
 | 
			
		||||
	netConn = nil // to avoid close in defer.
 | 
			
		||||
	return conn, resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										915
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										915
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,915 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	maxFrameHeaderSize         = 2 + 8 + 4 // Fixed header + length + mask
 | 
			
		||||
	maxControlFramePayloadSize = 125
 | 
			
		||||
	finalBit                   = 1 << 7
 | 
			
		||||
	maskBit                    = 1 << 7
 | 
			
		||||
	writeWait                  = time.Second
 | 
			
		||||
 | 
			
		||||
	defaultReadBufferSize  = 4096
 | 
			
		||||
	defaultWriteBufferSize = 4096
 | 
			
		||||
 | 
			
		||||
	continuationFrame = 0
 | 
			
		||||
	noFrame           = -1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Close codes defined in RFC 6455, section 11.7.
 | 
			
		||||
const (
 | 
			
		||||
	CloseNormalClosure           = 1000
 | 
			
		||||
	CloseGoingAway               = 1001
 | 
			
		||||
	CloseProtocolError           = 1002
 | 
			
		||||
	CloseUnsupportedData         = 1003
 | 
			
		||||
	CloseNoStatusReceived        = 1005
 | 
			
		||||
	CloseAbnormalClosure         = 1006
 | 
			
		||||
	CloseInvalidFramePayloadData = 1007
 | 
			
		||||
	ClosePolicyViolation         = 1008
 | 
			
		||||
	CloseMessageTooBig           = 1009
 | 
			
		||||
	CloseMandatoryExtension      = 1010
 | 
			
		||||
	CloseInternalServerErr       = 1011
 | 
			
		||||
	CloseTLSHandshake            = 1015
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The message types are defined in RFC 6455, section 11.8.
 | 
			
		||||
const (
 | 
			
		||||
	// TextMessage denotes a text data message. The text message payload is
 | 
			
		||||
	// interpreted as UTF-8 encoded text data.
 | 
			
		||||
	TextMessage = 1
 | 
			
		||||
 | 
			
		||||
	// BinaryMessage denotes a binary data message.
 | 
			
		||||
	BinaryMessage = 2
 | 
			
		||||
 | 
			
		||||
	// CloseMessage denotes a close control message. The optional message
 | 
			
		||||
	// payload contains a numeric code and text. Use the FormatCloseMessage
 | 
			
		||||
	// function to format a close message payload.
 | 
			
		||||
	CloseMessage = 8
 | 
			
		||||
 | 
			
		||||
	// PingMessage denotes a ping control message. The optional message payload
 | 
			
		||||
	// is UTF-8 encoded text.
 | 
			
		||||
	PingMessage = 9
 | 
			
		||||
 | 
			
		||||
	// PongMessage denotes a ping control message. The optional message payload
 | 
			
		||||
	// is UTF-8 encoded text.
 | 
			
		||||
	PongMessage = 10
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrCloseSent is returned when the application writes a message to the
 | 
			
		||||
// connection after sending a close message.
 | 
			
		||||
var ErrCloseSent = errors.New("websocket: close sent")
 | 
			
		||||
 | 
			
		||||
// ErrReadLimit is returned when reading a message that is larger than the
 | 
			
		||||
// read limit set for the connection.
 | 
			
		||||
var ErrReadLimit = errors.New("websocket: read limit exceeded")
 | 
			
		||||
 | 
			
		||||
// netError satisfies the net Error interface.
 | 
			
		||||
type netError struct {
 | 
			
		||||
	msg       string
 | 
			
		||||
	temporary bool
 | 
			
		||||
	timeout   bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *netError) Error() string   { return e.msg }
 | 
			
		||||
func (e *netError) Temporary() bool { return e.temporary }
 | 
			
		||||
func (e *netError) Timeout() bool   { return e.timeout }
 | 
			
		||||
 | 
			
		||||
// CloseError represents close frame.
 | 
			
		||||
type CloseError struct {
 | 
			
		||||
 | 
			
		||||
	// Code is defined in RFC 6455, section 11.7.
 | 
			
		||||
	Code int
 | 
			
		||||
 | 
			
		||||
	// Text is the optional text payload.
 | 
			
		||||
	Text string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *CloseError) Error() string {
 | 
			
		||||
	s := []byte("websocket: close ")
 | 
			
		||||
	s = strconv.AppendInt(s, int64(e.Code), 10)
 | 
			
		||||
	switch e.Code {
 | 
			
		||||
	case CloseNormalClosure:
 | 
			
		||||
		s = append(s, " (normal)"...)
 | 
			
		||||
	case CloseGoingAway:
 | 
			
		||||
		s = append(s, " (going away)"...)
 | 
			
		||||
	case CloseProtocolError:
 | 
			
		||||
		s = append(s, " (protocol error)"...)
 | 
			
		||||
	case CloseUnsupportedData:
 | 
			
		||||
		s = append(s, " (unsupported data)"...)
 | 
			
		||||
	case CloseNoStatusReceived:
 | 
			
		||||
		s = append(s, " (no status)"...)
 | 
			
		||||
	case CloseAbnormalClosure:
 | 
			
		||||
		s = append(s, " (abnormal closure)"...)
 | 
			
		||||
	case CloseInvalidFramePayloadData:
 | 
			
		||||
		s = append(s, " (invalid payload data)"...)
 | 
			
		||||
	case ClosePolicyViolation:
 | 
			
		||||
		s = append(s, " (policy violation)"...)
 | 
			
		||||
	case CloseMessageTooBig:
 | 
			
		||||
		s = append(s, " (message too big)"...)
 | 
			
		||||
	case CloseMandatoryExtension:
 | 
			
		||||
		s = append(s, " (mandatory extension missing)"...)
 | 
			
		||||
	case CloseInternalServerErr:
 | 
			
		||||
		s = append(s, " (internal server error)"...)
 | 
			
		||||
	case CloseTLSHandshake:
 | 
			
		||||
		s = append(s, " (TLS handshake error)"...)
 | 
			
		||||
	}
 | 
			
		||||
	if e.Text != "" {
 | 
			
		||||
		s = append(s, ": "...)
 | 
			
		||||
		s = append(s, e.Text...)
 | 
			
		||||
	}
 | 
			
		||||
	return string(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsCloseError returns boolean indicating whether the error is a *CloseError
 | 
			
		||||
// with one of the specified codes.
 | 
			
		||||
func IsCloseError(err error, codes ...int) bool {
 | 
			
		||||
	if e, ok := err.(*CloseError); ok {
 | 
			
		||||
		for _, code := range codes {
 | 
			
		||||
			if e.Code == code {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsUnexpectedCloseError returns boolean indicating whether the error is a
 | 
			
		||||
// *CloseError with a code not in the list of expected codes.
 | 
			
		||||
func IsUnexpectedCloseError(err error, expectedCodes ...int) bool {
 | 
			
		||||
	if e, ok := err.(*CloseError); ok {
 | 
			
		||||
		for _, code := range expectedCodes {
 | 
			
		||||
			if e.Code == code {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errWriteTimeout        = &netError{msg: "websocket: write timeout", timeout: true, temporary: true}
 | 
			
		||||
	errUnexpectedEOF       = &CloseError{Code: CloseAbnormalClosure, Text: io.ErrUnexpectedEOF.Error()}
 | 
			
		||||
	errBadWriteOpCode      = errors.New("websocket: bad write message type")
 | 
			
		||||
	errWriteClosed         = errors.New("websocket: write closed")
 | 
			
		||||
	errInvalidControlFrame = errors.New("websocket: invalid control frame")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func hideTempErr(err error) error {
 | 
			
		||||
	if e, ok := err.(net.Error); ok && e.Temporary() {
 | 
			
		||||
		err = &netError{msg: e.Error(), timeout: e.Timeout()}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isControl(frameType int) bool {
 | 
			
		||||
	return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isData(frameType int) bool {
 | 
			
		||||
	return frameType == TextMessage || frameType == BinaryMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func maskBytes(key [4]byte, pos int, b []byte) int {
 | 
			
		||||
	for i := range b {
 | 
			
		||||
		b[i] ^= key[pos&3]
 | 
			
		||||
		pos++
 | 
			
		||||
	}
 | 
			
		||||
	return pos & 3
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMaskKey() [4]byte {
 | 
			
		||||
	n := rand.Uint32()
 | 
			
		||||
	return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conn represents a WebSocket connection.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	conn        net.Conn
 | 
			
		||||
	isServer    bool
 | 
			
		||||
	subprotocol string
 | 
			
		||||
 | 
			
		||||
	// Write fields
 | 
			
		||||
	mu        chan bool // used as mutex to protect write to conn and closeSent
 | 
			
		||||
	closeSent bool      // true if close message was sent
 | 
			
		||||
 | 
			
		||||
	// Message writer fields.
 | 
			
		||||
	writeErr       error
 | 
			
		||||
	writeBuf       []byte // frame is constructed in this buffer.
 | 
			
		||||
	writePos       int    // end of data in writeBuf.
 | 
			
		||||
	writeFrameType int    // type of the current frame.
 | 
			
		||||
	writeSeq       int    // incremented to invalidate message writers.
 | 
			
		||||
	writeDeadline  time.Time
 | 
			
		||||
	isWriting      bool // for best-effort concurrent write detection
 | 
			
		||||
 | 
			
		||||
	// Read fields
 | 
			
		||||
	readErr       error
 | 
			
		||||
	br            *bufio.Reader
 | 
			
		||||
	readRemaining int64 // bytes remaining in current frame.
 | 
			
		||||
	readFinal     bool  // true the current message has more frames.
 | 
			
		||||
	readSeq       int   // incremented to invalidate message readers.
 | 
			
		||||
	readLength    int64 // Message size.
 | 
			
		||||
	readLimit     int64 // Maximum message size.
 | 
			
		||||
	readMaskPos   int
 | 
			
		||||
	readMaskKey   [4]byte
 | 
			
		||||
	handlePong    func(string) error
 | 
			
		||||
	handlePing    func(string) error
 | 
			
		||||
	readErrCount  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
 | 
			
		||||
	mu := make(chan bool, 1)
 | 
			
		||||
	mu <- true
 | 
			
		||||
 | 
			
		||||
	if readBufferSize == 0 {
 | 
			
		||||
		readBufferSize = defaultReadBufferSize
 | 
			
		||||
	}
 | 
			
		||||
	if writeBufferSize == 0 {
 | 
			
		||||
		writeBufferSize = defaultWriteBufferSize
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := &Conn{
 | 
			
		||||
		isServer:       isServer,
 | 
			
		||||
		br:             bufio.NewReaderSize(conn, readBufferSize),
 | 
			
		||||
		conn:           conn,
 | 
			
		||||
		mu:             mu,
 | 
			
		||||
		readFinal:      true,
 | 
			
		||||
		writeBuf:       make([]byte, writeBufferSize+maxFrameHeaderSize),
 | 
			
		||||
		writeFrameType: noFrame,
 | 
			
		||||
		writePos:       maxFrameHeaderSize,
 | 
			
		||||
	}
 | 
			
		||||
	c.SetPingHandler(nil)
 | 
			
		||||
	c.SetPongHandler(nil)
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subprotocol returns the negotiated protocol for the connection.
 | 
			
		||||
func (c *Conn) Subprotocol() string {
 | 
			
		||||
	return c.subprotocol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the underlying network connection without sending or waiting for a close frame.
 | 
			
		||||
func (c *Conn) Close() error {
 | 
			
		||||
	return c.conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LocalAddr returns the local network address.
 | 
			
		||||
func (c *Conn) LocalAddr() net.Addr {
 | 
			
		||||
	return c.conn.LocalAddr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteAddr returns the remote network address.
 | 
			
		||||
func (c *Conn) RemoteAddr() net.Addr {
 | 
			
		||||
	return c.conn.RemoteAddr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write methods
 | 
			
		||||
 | 
			
		||||
func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
 | 
			
		||||
	<-c.mu
 | 
			
		||||
	defer func() { c.mu <- true }()
 | 
			
		||||
 | 
			
		||||
	if c.closeSent {
 | 
			
		||||
		return ErrCloseSent
 | 
			
		||||
	} else if frameType == CloseMessage {
 | 
			
		||||
		c.closeSent = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.conn.SetWriteDeadline(deadline)
 | 
			
		||||
	for _, buf := range bufs {
 | 
			
		||||
		if len(buf) > 0 {
 | 
			
		||||
			n, err := c.conn.Write(buf)
 | 
			
		||||
			if n != len(buf) {
 | 
			
		||||
				// Close on partial write.
 | 
			
		||||
				c.conn.Close()
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteControl writes a control message with the given deadline. The allowed
 | 
			
		||||
// message types are CloseMessage, PingMessage and PongMessage.
 | 
			
		||||
func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
 | 
			
		||||
	if !isControl(messageType) {
 | 
			
		||||
		return errBadWriteOpCode
 | 
			
		||||
	}
 | 
			
		||||
	if len(data) > maxControlFramePayloadSize {
 | 
			
		||||
		return errInvalidControlFrame
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b0 := byte(messageType) | finalBit
 | 
			
		||||
	b1 := byte(len(data))
 | 
			
		||||
	if !c.isServer {
 | 
			
		||||
		b1 |= maskBit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize)
 | 
			
		||||
	buf = append(buf, b0, b1)
 | 
			
		||||
 | 
			
		||||
	if c.isServer {
 | 
			
		||||
		buf = append(buf, data...)
 | 
			
		||||
	} else {
 | 
			
		||||
		key := newMaskKey()
 | 
			
		||||
		buf = append(buf, key[:]...)
 | 
			
		||||
		buf = append(buf, data...)
 | 
			
		||||
		maskBytes(key, 0, buf[6:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d := time.Hour * 1000
 | 
			
		||||
	if !deadline.IsZero() {
 | 
			
		||||
		d = deadline.Sub(time.Now())
 | 
			
		||||
		if d < 0 {
 | 
			
		||||
			return errWriteTimeout
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timer := time.NewTimer(d)
 | 
			
		||||
	select {
 | 
			
		||||
	case <-c.mu:
 | 
			
		||||
		timer.Stop()
 | 
			
		||||
	case <-timer.C:
 | 
			
		||||
		return errWriteTimeout
 | 
			
		||||
	}
 | 
			
		||||
	defer func() { c.mu <- true }()
 | 
			
		||||
 | 
			
		||||
	if c.closeSent {
 | 
			
		||||
		return ErrCloseSent
 | 
			
		||||
	} else if messageType == CloseMessage {
 | 
			
		||||
		c.closeSent = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.conn.SetWriteDeadline(deadline)
 | 
			
		||||
	n, err := c.conn.Write(buf)
 | 
			
		||||
	if n != 0 && n != len(buf) {
 | 
			
		||||
		c.conn.Close()
 | 
			
		||||
	}
 | 
			
		||||
	return hideTempErr(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextWriter returns a writer for the next message to send.  The writer's
 | 
			
		||||
// Close method flushes the complete message to the network.
 | 
			
		||||
//
 | 
			
		||||
// There can be at most one open writer on a connection. NextWriter closes the
 | 
			
		||||
// previous writer if the application has not already done so.
 | 
			
		||||
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
 | 
			
		||||
	if c.writeErr != nil {
 | 
			
		||||
		return nil, c.writeErr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.writeFrameType != noFrame {
 | 
			
		||||
		if err := c.flushFrame(true, nil); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !isControl(messageType) && !isData(messageType) {
 | 
			
		||||
		return nil, errBadWriteOpCode
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.writeFrameType = messageType
 | 
			
		||||
	return messageWriter{c, c.writeSeq}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) flushFrame(final bool, extra []byte) error {
 | 
			
		||||
	length := c.writePos - maxFrameHeaderSize + len(extra)
 | 
			
		||||
 | 
			
		||||
	// Check for invalid control frames.
 | 
			
		||||
	if isControl(c.writeFrameType) &&
 | 
			
		||||
		(!final || length > maxControlFramePayloadSize) {
 | 
			
		||||
		c.writeSeq++
 | 
			
		||||
		c.writeFrameType = noFrame
 | 
			
		||||
		c.writePos = maxFrameHeaderSize
 | 
			
		||||
		return errInvalidControlFrame
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b0 := byte(c.writeFrameType)
 | 
			
		||||
	if final {
 | 
			
		||||
		b0 |= finalBit
 | 
			
		||||
	}
 | 
			
		||||
	b1 := byte(0)
 | 
			
		||||
	if !c.isServer {
 | 
			
		||||
		b1 |= maskBit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assume that the frame starts at beginning of c.writeBuf.
 | 
			
		||||
	framePos := 0
 | 
			
		||||
	if c.isServer {
 | 
			
		||||
		// Adjust up if mask not included in the header.
 | 
			
		||||
		framePos = 4
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case length >= 65536:
 | 
			
		||||
		c.writeBuf[framePos] = b0
 | 
			
		||||
		c.writeBuf[framePos+1] = b1 | 127
 | 
			
		||||
		binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length))
 | 
			
		||||
	case length > 125:
 | 
			
		||||
		framePos += 6
 | 
			
		||||
		c.writeBuf[framePos] = b0
 | 
			
		||||
		c.writeBuf[framePos+1] = b1 | 126
 | 
			
		||||
		binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length))
 | 
			
		||||
	default:
 | 
			
		||||
		framePos += 8
 | 
			
		||||
		c.writeBuf[framePos] = b0
 | 
			
		||||
		c.writeBuf[framePos+1] = b1 | byte(length)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !c.isServer {
 | 
			
		||||
		key := newMaskKey()
 | 
			
		||||
		copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
 | 
			
		||||
		maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos])
 | 
			
		||||
		if len(extra) > 0 {
 | 
			
		||||
			c.writeErr = errors.New("websocket: internal error, extra used in client mode")
 | 
			
		||||
			return c.writeErr
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Write the buffers to the connection with best-effort detection of
 | 
			
		||||
	// concurrent writes. See the concurrency section in the package
 | 
			
		||||
	// documentation for more info.
 | 
			
		||||
 | 
			
		||||
	if c.isWriting {
 | 
			
		||||
		panic("concurrent write to websocket connection")
 | 
			
		||||
	}
 | 
			
		||||
	c.isWriting = true
 | 
			
		||||
 | 
			
		||||
	c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra)
 | 
			
		||||
 | 
			
		||||
	if !c.isWriting {
 | 
			
		||||
		panic("concurrent write to websocket connection")
 | 
			
		||||
	}
 | 
			
		||||
	c.isWriting = false
 | 
			
		||||
 | 
			
		||||
	// Setup for next frame.
 | 
			
		||||
	c.writePos = maxFrameHeaderSize
 | 
			
		||||
	c.writeFrameType = continuationFrame
 | 
			
		||||
	if final {
 | 
			
		||||
		c.writeSeq++
 | 
			
		||||
		c.writeFrameType = noFrame
 | 
			
		||||
	}
 | 
			
		||||
	return c.writeErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type messageWriter struct {
 | 
			
		||||
	c   *Conn
 | 
			
		||||
	seq int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) err() error {
 | 
			
		||||
	c := w.c
 | 
			
		||||
	if c.writeSeq != w.seq {
 | 
			
		||||
		return errWriteClosed
 | 
			
		||||
	}
 | 
			
		||||
	if c.writeErr != nil {
 | 
			
		||||
		return c.writeErr
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) ncopy(max int) (int, error) {
 | 
			
		||||
	n := len(w.c.writeBuf) - w.c.writePos
 | 
			
		||||
	if n <= 0 {
 | 
			
		||||
		if err := w.c.flushFrame(false, nil); err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		n = len(w.c.writeBuf) - w.c.writePos
 | 
			
		||||
	}
 | 
			
		||||
	if n > max {
 | 
			
		||||
		n = max
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) write(final bool, p []byte) (int, error) {
 | 
			
		||||
	if err := w.err(); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
 | 
			
		||||
		// Don't buffer large messages.
 | 
			
		||||
		err := w.c.flushFrame(final, p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return len(p), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nn := len(p)
 | 
			
		||||
	for len(p) > 0 {
 | 
			
		||||
		n, err := w.ncopy(len(p))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		copy(w.c.writeBuf[w.c.writePos:], p[:n])
 | 
			
		||||
		w.c.writePos += n
 | 
			
		||||
		p = p[n:]
 | 
			
		||||
	}
 | 
			
		||||
	return nn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) Write(p []byte) (int, error) {
 | 
			
		||||
	return w.write(false, p)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) WriteString(p string) (int, error) {
 | 
			
		||||
	if err := w.err(); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nn := len(p)
 | 
			
		||||
	for len(p) > 0 {
 | 
			
		||||
		n, err := w.ncopy(len(p))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		copy(w.c.writeBuf[w.c.writePos:], p[:n])
 | 
			
		||||
		w.c.writePos += n
 | 
			
		||||
		p = p[n:]
 | 
			
		||||
	}
 | 
			
		||||
	return nn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
 | 
			
		||||
	if err := w.err(); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		if w.c.writePos == len(w.c.writeBuf) {
 | 
			
		||||
			err = w.c.flushFrame(false, nil)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		var n int
 | 
			
		||||
		n, err = r.Read(w.c.writeBuf[w.c.writePos:])
 | 
			
		||||
		w.c.writePos += n
 | 
			
		||||
		nn += int64(n)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == io.EOF {
 | 
			
		||||
				err = nil
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nn, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w messageWriter) Close() error {
 | 
			
		||||
	if err := w.err(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return w.c.flushFrame(true, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteMessage is a helper method for getting a writer using NextWriter,
 | 
			
		||||
// writing the message and closing the writer.
 | 
			
		||||
func (c *Conn) WriteMessage(messageType int, data []byte) error {
 | 
			
		||||
	wr, err := c.NextWriter(messageType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	w := wr.(messageWriter)
 | 
			
		||||
	if _, err := w.write(true, data); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if c.writeSeq == w.seq {
 | 
			
		||||
		if err := c.flushFrame(true, nil); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetWriteDeadline sets the write deadline on the underlying network
 | 
			
		||||
// connection. After a write has timed out, the websocket state is corrupt and
 | 
			
		||||
// all future writes will return an error. A zero value for t means writes will
 | 
			
		||||
// not time out.
 | 
			
		||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	c.writeDeadline = t
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read methods
 | 
			
		||||
 | 
			
		||||
// readFull is like io.ReadFull except that io.EOF is never returned.
 | 
			
		||||
func (c *Conn) readFull(p []byte) (err error) {
 | 
			
		||||
	var n int
 | 
			
		||||
	for n < len(p) && err == nil {
 | 
			
		||||
		var nn int
 | 
			
		||||
		nn, err = c.br.Read(p[n:])
 | 
			
		||||
		n += nn
 | 
			
		||||
	}
 | 
			
		||||
	if n == len(p) {
 | 
			
		||||
		err = nil
 | 
			
		||||
	} else if err == io.EOF {
 | 
			
		||||
		err = errUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) advanceFrame() (int, error) {
 | 
			
		||||
 | 
			
		||||
	// 1. Skip remainder of previous frame.
 | 
			
		||||
 | 
			
		||||
	if c.readRemaining > 0 {
 | 
			
		||||
		if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 2. Read and parse first two bytes of frame header.
 | 
			
		||||
 | 
			
		||||
	var b [8]byte
 | 
			
		||||
	if err := c.readFull(b[:2]); err != nil {
 | 
			
		||||
		return noFrame, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	final := b[0]&finalBit != 0
 | 
			
		||||
	frameType := int(b[0] & 0xf)
 | 
			
		||||
	reserved := int((b[0] >> 4) & 0x7)
 | 
			
		||||
	mask := b[1]&maskBit != 0
 | 
			
		||||
	c.readRemaining = int64(b[1] & 0x7f)
 | 
			
		||||
 | 
			
		||||
	if reserved != 0 {
 | 
			
		||||
		return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch frameType {
 | 
			
		||||
	case CloseMessage, PingMessage, PongMessage:
 | 
			
		||||
		if c.readRemaining > maxControlFramePayloadSize {
 | 
			
		||||
			return noFrame, c.handleProtocolError("control frame length > 125")
 | 
			
		||||
		}
 | 
			
		||||
		if !final {
 | 
			
		||||
			return noFrame, c.handleProtocolError("control frame not final")
 | 
			
		||||
		}
 | 
			
		||||
	case TextMessage, BinaryMessage:
 | 
			
		||||
		if !c.readFinal {
 | 
			
		||||
			return noFrame, c.handleProtocolError("message start before final message frame")
 | 
			
		||||
		}
 | 
			
		||||
		c.readFinal = final
 | 
			
		||||
	case continuationFrame:
 | 
			
		||||
		if c.readFinal {
 | 
			
		||||
			return noFrame, c.handleProtocolError("continuation after final message frame")
 | 
			
		||||
		}
 | 
			
		||||
		c.readFinal = final
 | 
			
		||||
	default:
 | 
			
		||||
		return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. Read and parse frame length.
 | 
			
		||||
 | 
			
		||||
	switch c.readRemaining {
 | 
			
		||||
	case 126:
 | 
			
		||||
		if err := c.readFull(b[:2]); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
		c.readRemaining = int64(binary.BigEndian.Uint16(b[:2]))
 | 
			
		||||
	case 127:
 | 
			
		||||
		if err := c.readFull(b[:8]); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
		c.readRemaining = int64(binary.BigEndian.Uint64(b[:8]))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 4. Handle frame masking.
 | 
			
		||||
 | 
			
		||||
	if mask != c.isServer {
 | 
			
		||||
		return noFrame, c.handleProtocolError("incorrect mask flag")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if mask {
 | 
			
		||||
		c.readMaskPos = 0
 | 
			
		||||
		if err := c.readFull(c.readMaskKey[:]); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 5. For text and binary messages, enforce read limit and return.
 | 
			
		||||
 | 
			
		||||
	if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
 | 
			
		||||
 | 
			
		||||
		c.readLength += c.readRemaining
 | 
			
		||||
		if c.readLimit > 0 && c.readLength > c.readLimit {
 | 
			
		||||
			c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
 | 
			
		||||
			return noFrame, ErrReadLimit
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return frameType, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 6. Read control frame payload.
 | 
			
		||||
 | 
			
		||||
	var payload []byte
 | 
			
		||||
	if c.readRemaining > 0 {
 | 
			
		||||
		payload = make([]byte, c.readRemaining)
 | 
			
		||||
		c.readRemaining = 0
 | 
			
		||||
		if err := c.readFull(payload); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
		if c.isServer {
 | 
			
		||||
			maskBytes(c.readMaskKey, 0, payload)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 7. Process control frame payload.
 | 
			
		||||
 | 
			
		||||
	switch frameType {
 | 
			
		||||
	case PongMessage:
 | 
			
		||||
		if err := c.handlePong(string(payload)); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
	case PingMessage:
 | 
			
		||||
		if err := c.handlePing(string(payload)); err != nil {
 | 
			
		||||
			return noFrame, err
 | 
			
		||||
		}
 | 
			
		||||
	case CloseMessage:
 | 
			
		||||
		echoMessage := []byte{}
 | 
			
		||||
		closeCode := CloseNoStatusReceived
 | 
			
		||||
		closeText := ""
 | 
			
		||||
		if len(payload) >= 2 {
 | 
			
		||||
			echoMessage = payload[:2]
 | 
			
		||||
			closeCode = int(binary.BigEndian.Uint16(payload))
 | 
			
		||||
			closeText = string(payload[2:])
 | 
			
		||||
		}
 | 
			
		||||
		c.WriteControl(CloseMessage, echoMessage, time.Now().Add(writeWait))
 | 
			
		||||
		return noFrame, &CloseError{Code: closeCode, Text: closeText}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return frameType, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) handleProtocolError(message string) error {
 | 
			
		||||
	c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait))
 | 
			
		||||
	return errors.New("websocket: " + message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextReader returns the next data message received from the peer. The
 | 
			
		||||
// returned messageType is either TextMessage or BinaryMessage.
 | 
			
		||||
//
 | 
			
		||||
// There can be at most one open reader on a connection. NextReader discards
 | 
			
		||||
// the previous message if the application has not already consumed it.
 | 
			
		||||
//
 | 
			
		||||
// Applications must break out of the application's read loop when this method
 | 
			
		||||
// returns a non-nil error value. Errors returned from this method are
 | 
			
		||||
// permanent. Once this method returns a non-nil error, all subsequent calls to
 | 
			
		||||
// this method return the same error.
 | 
			
		||||
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
 | 
			
		||||
 | 
			
		||||
	c.readSeq++
 | 
			
		||||
	c.readLength = 0
 | 
			
		||||
 | 
			
		||||
	for c.readErr == nil {
 | 
			
		||||
		frameType, err := c.advanceFrame()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.readErr = hideTempErr(err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if frameType == TextMessage || frameType == BinaryMessage {
 | 
			
		||||
			return frameType, messageReader{c, c.readSeq}, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Applications that do handle the error returned from this method spin in
 | 
			
		||||
	// tight loop on connection failure. To help application developers detect
 | 
			
		||||
	// this error, panic on repeated reads to the failed connection.
 | 
			
		||||
	c.readErrCount++
 | 
			
		||||
	if c.readErrCount >= 1000 {
 | 
			
		||||
		panic("repeated read on failed websocket connection")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return noFrame, nil, c.readErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type messageReader struct {
 | 
			
		||||
	c   *Conn
 | 
			
		||||
	seq int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r messageReader) Read(b []byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
	if r.seq != r.c.readSeq {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for r.c.readErr == nil {
 | 
			
		||||
 | 
			
		||||
		if r.c.readRemaining > 0 {
 | 
			
		||||
			if int64(len(b)) > r.c.readRemaining {
 | 
			
		||||
				b = b[:r.c.readRemaining]
 | 
			
		||||
			}
 | 
			
		||||
			n, err := r.c.br.Read(b)
 | 
			
		||||
			r.c.readErr = hideTempErr(err)
 | 
			
		||||
			if r.c.isServer {
 | 
			
		||||
				r.c.readMaskPos = maskBytes(r.c.readMaskKey, r.c.readMaskPos, b[:n])
 | 
			
		||||
			}
 | 
			
		||||
			r.c.readRemaining -= int64(n)
 | 
			
		||||
			return n, r.c.readErr
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if r.c.readFinal {
 | 
			
		||||
			r.c.readSeq++
 | 
			
		||||
			return 0, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		frameType, err := r.c.advanceFrame()
 | 
			
		||||
		switch {
 | 
			
		||||
		case err != nil:
 | 
			
		||||
			r.c.readErr = hideTempErr(err)
 | 
			
		||||
		case frameType == TextMessage || frameType == BinaryMessage:
 | 
			
		||||
			r.c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := r.c.readErr
 | 
			
		||||
	if err == io.EOF && r.seq == r.c.readSeq {
 | 
			
		||||
		err = errUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return 0, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadMessage is a helper method for getting a reader using NextReader and
 | 
			
		||||
// reading from that reader to a buffer.
 | 
			
		||||
func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
 | 
			
		||||
	var r io.Reader
 | 
			
		||||
	messageType, r, err = c.NextReader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return messageType, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	p, err = ioutil.ReadAll(r)
 | 
			
		||||
	return messageType, p, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadDeadline sets the read deadline on the underlying network connection.
 | 
			
		||||
// After a read has timed out, the websocket connection state is corrupt and
 | 
			
		||||
// all future reads will return an error. A zero value for t means reads will
 | 
			
		||||
// not time out.
 | 
			
		||||
func (c *Conn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	return c.conn.SetReadDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadLimit sets the maximum size for a message read from the peer. If a
 | 
			
		||||
// message exceeds the limit, the connection sends a close frame to the peer
 | 
			
		||||
// and returns ErrReadLimit to the application.
 | 
			
		||||
func (c *Conn) SetReadLimit(limit int64) {
 | 
			
		||||
	c.readLimit = limit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetPingHandler sets the handler for ping messages received from the peer.
 | 
			
		||||
// The appData argument to h is the PING frame application data. The default
 | 
			
		||||
// ping handler sends a pong to the peer.
 | 
			
		||||
func (c *Conn) SetPingHandler(h func(appData string) error) {
 | 
			
		||||
	if h == nil {
 | 
			
		||||
		h = func(message string) error {
 | 
			
		||||
			err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
 | 
			
		||||
			if err == ErrCloseSent {
 | 
			
		||||
				return nil
 | 
			
		||||
			} else if e, ok := err.(net.Error); ok && e.Temporary() {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c.handlePing = h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetPongHandler sets the handler for pong messages received from the peer.
 | 
			
		||||
// The appData argument to h is the PONG frame application data. The default
 | 
			
		||||
// pong handler does nothing.
 | 
			
		||||
func (c *Conn) SetPongHandler(h func(appData string) error) {
 | 
			
		||||
	if h == nil {
 | 
			
		||||
		h = func(string) error { return nil }
 | 
			
		||||
	}
 | 
			
		||||
	c.handlePong = h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnderlyingConn returns the internal net.Conn. This can be used to further
 | 
			
		||||
// modifications to connection specific flags.
 | 
			
		||||
func (c *Conn) UnderlyingConn() net.Conn {
 | 
			
		||||
	return c.conn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
 | 
			
		||||
func FormatCloseMessage(closeCode int, text string) []byte {
 | 
			
		||||
	buf := make([]byte, 2+len(text))
 | 
			
		||||
	binary.BigEndian.PutUint16(buf, uint16(closeCode))
 | 
			
		||||
	copy(buf[2:], text)
 | 
			
		||||
	return buf
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										152
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket implements the WebSocket protocol defined in RFC 6455.
 | 
			
		||||
//
 | 
			
		||||
// Overview
 | 
			
		||||
//
 | 
			
		||||
// The Conn type represents a WebSocket connection. A server application uses
 | 
			
		||||
// the Upgrade function from an Upgrader object with a HTTP request handler
 | 
			
		||||
// to get a pointer to a Conn:
 | 
			
		||||
//
 | 
			
		||||
//  var upgrader = websocket.Upgrader{
 | 
			
		||||
//      ReadBufferSize:  1024,
 | 
			
		||||
//      WriteBufferSize: 1024,
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
//  func handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
//      conn, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
//      if err != nil {
 | 
			
		||||
//          log.Println(err)
 | 
			
		||||
//          return
 | 
			
		||||
//      }
 | 
			
		||||
//      ... Use conn to send and receive messages.
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
// Call the connection's WriteMessage and ReadMessage methods to send and
 | 
			
		||||
// receive messages as a slice of bytes. This snippet of code shows how to echo
 | 
			
		||||
// messages using these methods:
 | 
			
		||||
//
 | 
			
		||||
//  for {
 | 
			
		||||
//      messageType, p, err := conn.ReadMessage()
 | 
			
		||||
//      if err != nil {
 | 
			
		||||
//          return
 | 
			
		||||
//      }
 | 
			
		||||
//      if err = conn.WriteMessage(messageType, p); err != nil {
 | 
			
		||||
//          return err
 | 
			
		||||
//      }
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
// In above snippet of code, p is a []byte and messageType is an int with value
 | 
			
		||||
// websocket.BinaryMessage or websocket.TextMessage.
 | 
			
		||||
//
 | 
			
		||||
// An application can also send and receive messages using the io.WriteCloser
 | 
			
		||||
// and io.Reader interfaces. To send a message, call the connection NextWriter
 | 
			
		||||
// method to get an io.WriteCloser, write the message to the writer and close
 | 
			
		||||
// the writer when done. To receive a message, call the connection NextReader
 | 
			
		||||
// method to get an io.Reader and read until io.EOF is returned. This snippet
 | 
			
		||||
// shows how to echo messages using the NextWriter and NextReader methods:
 | 
			
		||||
//
 | 
			
		||||
//  for {
 | 
			
		||||
//      messageType, r, err := conn.NextReader()
 | 
			
		||||
//      if err != nil {
 | 
			
		||||
//          return
 | 
			
		||||
//      }
 | 
			
		||||
//      w, err := conn.NextWriter(messageType)
 | 
			
		||||
//      if err != nil {
 | 
			
		||||
//          return err
 | 
			
		||||
//      }
 | 
			
		||||
//      if _, err := io.Copy(w, r); err != nil {
 | 
			
		||||
//          return err
 | 
			
		||||
//      }
 | 
			
		||||
//      if err := w.Close(); err != nil {
 | 
			
		||||
//          return err
 | 
			
		||||
//      }
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
// Data Messages
 | 
			
		||||
//
 | 
			
		||||
// The WebSocket protocol distinguishes between text and binary data messages.
 | 
			
		||||
// Text messages are interpreted as UTF-8 encoded text. The interpretation of
 | 
			
		||||
// binary messages is left to the application.
 | 
			
		||||
//
 | 
			
		||||
// This package uses the TextMessage and BinaryMessage integer constants to
 | 
			
		||||
// identify the two data message types. The ReadMessage and NextReader methods
 | 
			
		||||
// return the type of the received message. The messageType argument to the
 | 
			
		||||
// WriteMessage and NextWriter methods specifies the type of a sent message.
 | 
			
		||||
//
 | 
			
		||||
// It is the application's responsibility to ensure that text messages are
 | 
			
		||||
// valid UTF-8 encoded text.
 | 
			
		||||
//
 | 
			
		||||
// Control Messages
 | 
			
		||||
//
 | 
			
		||||
// The WebSocket protocol defines three types of control messages: close, ping
 | 
			
		||||
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
 | 
			
		||||
// methods to send a control message to the peer.
 | 
			
		||||
//
 | 
			
		||||
// Connections handle received close messages by sending a close message to the
 | 
			
		||||
// peer and returning a *CloseError from the the NextReader, ReadMessage or the
 | 
			
		||||
// message Read method.
 | 
			
		||||
//
 | 
			
		||||
// Connections handle received ping and pong messages by invoking callback
 | 
			
		||||
// functions set with SetPingHandler and SetPongHandler methods. The callback
 | 
			
		||||
// functions are called from the NextReader, ReadMessage and the message Read
 | 
			
		||||
// methods.
 | 
			
		||||
//
 | 
			
		||||
// The default ping handler sends a pong to the peer. The application's reading
 | 
			
		||||
// goroutine can block for a short time while the handler writes the pong data
 | 
			
		||||
// to the connection.
 | 
			
		||||
//
 | 
			
		||||
// The application must read the connection to process ping, pong and close
 | 
			
		||||
// messages sent from the peer. If the application is not otherwise interested
 | 
			
		||||
// in messages from the peer, then the application should start a goroutine to
 | 
			
		||||
// read and discard messages from the peer. A simple example is:
 | 
			
		||||
//
 | 
			
		||||
//  func readLoop(c *websocket.Conn) {
 | 
			
		||||
//      for {
 | 
			
		||||
//          if _, _, err := c.NextReader(); err != nil {
 | 
			
		||||
//              c.Close()
 | 
			
		||||
//              break
 | 
			
		||||
//          }
 | 
			
		||||
//      }
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
// Concurrency
 | 
			
		||||
//
 | 
			
		||||
// Connections support one concurrent reader and one concurrent writer.
 | 
			
		||||
//
 | 
			
		||||
// Applications are responsible for ensuring that no more than one goroutine
 | 
			
		||||
// calls the write methods (NextWriter, SetWriteDeadline, WriteMessage,
 | 
			
		||||
// WriteJSON) concurrently and that no more than one goroutine calls the read
 | 
			
		||||
// methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler,
 | 
			
		||||
// SetPingHandler) concurrently.
 | 
			
		||||
//
 | 
			
		||||
// The Close and WriteControl methods can be called concurrently with all other
 | 
			
		||||
// methods.
 | 
			
		||||
//
 | 
			
		||||
// Origin Considerations
 | 
			
		||||
//
 | 
			
		||||
// Web browsers allow Javascript applications to open a WebSocket connection to
 | 
			
		||||
// any host. It's up to the server to enforce an origin policy using the Origin
 | 
			
		||||
// request header sent by the browser.
 | 
			
		||||
//
 | 
			
		||||
// The Upgrader calls the function specified in the CheckOrigin field to check
 | 
			
		||||
// the origin. If the CheckOrigin function returns false, then the Upgrade
 | 
			
		||||
// method fails the WebSocket handshake with HTTP status 403.
 | 
			
		||||
//
 | 
			
		||||
// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
 | 
			
		||||
// the handshake if the Origin request header is present and not equal to the
 | 
			
		||||
// Host request header.
 | 
			
		||||
//
 | 
			
		||||
// An application can allow connections from any origin by specifying a
 | 
			
		||||
// function that always returns true:
 | 
			
		||||
//
 | 
			
		||||
//  var upgrader = websocket.Upgrader{
 | 
			
		||||
//      CheckOrigin: func(r *http.Request) bool { return true },
 | 
			
		||||
//  }
 | 
			
		||||
//
 | 
			
		||||
// The deprecated Upgrade function does not enforce an origin policy. It's the
 | 
			
		||||
// application's responsibility to check the Origin header before calling
 | 
			
		||||
// Upgrade.
 | 
			
		||||
package websocket
 | 
			
		||||
							
								
								
									
										246
									
								
								vendor/github.com/gorilla/websocket/examples/autobahn/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								vendor/github.com/gorilla/websocket/examples/autobahn/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Command server is a test server for the Autobahn WebSockets Test Suite.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var upgrader = websocket.Upgrader{
 | 
			
		||||
	ReadBufferSize:  4096,
 | 
			
		||||
	WriteBufferSize: 4096,
 | 
			
		||||
	CheckOrigin: func(r *http.Request) bool {
 | 
			
		||||
		return true
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// echoCopy echoes messages from the client using io.Copy.
 | 
			
		||||
func echoCopy(w http.ResponseWriter, r *http.Request, writerOnly bool) {
 | 
			
		||||
	conn, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Upgrade:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
	for {
 | 
			
		||||
		mt, r, err := conn.NextReader()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err != io.EOF {
 | 
			
		||||
				log.Println("NextReader:", err)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if mt == websocket.TextMessage {
 | 
			
		||||
			r = &validator{r: r}
 | 
			
		||||
		}
 | 
			
		||||
		w, err := conn.NextWriter(mt)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("NextWriter:", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if mt == websocket.TextMessage {
 | 
			
		||||
			r = &validator{r: r}
 | 
			
		||||
		}
 | 
			
		||||
		if writerOnly {
 | 
			
		||||
			_, err = io.Copy(struct{ io.Writer }{w}, r)
 | 
			
		||||
		} else {
 | 
			
		||||
			_, err = io.Copy(w, r)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == errInvalidUTF8 {
 | 
			
		||||
				conn.WriteControl(websocket.CloseMessage,
 | 
			
		||||
					websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
 | 
			
		||||
					time.Time{})
 | 
			
		||||
			}
 | 
			
		||||
			log.Println("Copy:", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		err = w.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("Close:", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func echoCopyWriterOnly(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	echoCopy(w, r, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func echoCopyFull(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	echoCopy(w, r, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// echoReadAll echoes messages from the client by reading the entire message
 | 
			
		||||
// with ioutil.ReadAll.
 | 
			
		||||
func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
 | 
			
		||||
	conn, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Upgrade:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
	for {
 | 
			
		||||
		mt, b, err := conn.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err != io.EOF {
 | 
			
		||||
				log.Println("NextReader:", err)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if mt == websocket.TextMessage {
 | 
			
		||||
			if !utf8.Valid(b) {
 | 
			
		||||
				conn.WriteControl(websocket.CloseMessage,
 | 
			
		||||
					websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
 | 
			
		||||
					time.Time{})
 | 
			
		||||
				log.Println("ReadAll: invalid utf8")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if writeMessage {
 | 
			
		||||
			err = conn.WriteMessage(mt, b)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("WriteMessage:", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			w, err := conn.NextWriter(mt)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("NextWriter:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if _, err := w.Write(b); err != nil {
 | 
			
		||||
				log.Println("Writer:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if err := w.Close(); err != nil {
 | 
			
		||||
				log.Println("Close:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func echoReadAllWriter(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	echoReadAll(w, r, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	echoReadAll(w, r, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveHome(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		http.Error(w, "Not found.", 404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if r.Method != "GET" {
 | 
			
		||||
		http.Error(w, "Method not allowed", 405)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
	io.WriteString(w, "<html><body>Echo Server</body></html>")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var addr = flag.String("addr", ":9000", "http service address")
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	http.HandleFunc("/", serveHome)
 | 
			
		||||
	http.HandleFunc("/c", echoCopyWriterOnly)
 | 
			
		||||
	http.HandleFunc("/f", echoCopyFull)
 | 
			
		||||
	http.HandleFunc("/r", echoReadAllWriter)
 | 
			
		||||
	http.HandleFunc("/m", echoReadAllWriteMessage)
 | 
			
		||||
	err := http.ListenAndServe(*addr, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("ListenAndServe: ", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type validator struct {
 | 
			
		||||
	state int
 | 
			
		||||
	x     rune
 | 
			
		||||
	r     io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errInvalidUTF8 = errors.New("invalid utf8")
 | 
			
		||||
 | 
			
		||||
func (r *validator) Read(p []byte) (int, error) {
 | 
			
		||||
	n, err := r.r.Read(p)
 | 
			
		||||
	state := r.state
 | 
			
		||||
	x := r.x
 | 
			
		||||
	for _, b := range p[:n] {
 | 
			
		||||
		state, x = decode(state, x, b)
 | 
			
		||||
		if state == utf8Reject {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	r.state = state
 | 
			
		||||
	r.x = x
 | 
			
		||||
	if state == utf8Reject || (err == io.EOF && state != utf8Accept) {
 | 
			
		||||
		return n, errInvalidUTF8
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
 | 
			
		||||
//
 | 
			
		||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
// of this software and associated documentation files (the "Software"), to
 | 
			
		||||
// deal in the Software without restriction, including without limitation the
 | 
			
		||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 | 
			
		||||
// sell copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
// furnished to do so, subject to the following conditions:
 | 
			
		||||
//
 | 
			
		||||
// The above copyright notice and this permission notice shall be included in
 | 
			
		||||
// all copies or substantial portions of the Software.
 | 
			
		||||
//
 | 
			
		||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
// IN THE SOFTWARE.
 | 
			
		||||
var utf8d = [...]byte{
 | 
			
		||||
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
 | 
			
		||||
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
 | 
			
		||||
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
 | 
			
		||||
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
 | 
			
		||||
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
 | 
			
		||||
	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
 | 
			
		||||
	8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
 | 
			
		||||
	0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
 | 
			
		||||
	0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
 | 
			
		||||
	0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
 | 
			
		||||
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
 | 
			
		||||
	1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
 | 
			
		||||
	1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
 | 
			
		||||
	1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	utf8Accept = 0
 | 
			
		||||
	utf8Reject = 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func decode(state int, x rune, b byte) (int, rune) {
 | 
			
		||||
	t := utf8d[b]
 | 
			
		||||
	if state != utf8Accept {
 | 
			
		||||
		x = rune(b&0x3f) | (x << 6)
 | 
			
		||||
	} else {
 | 
			
		||||
		x = rune((0xff >> t) & b)
 | 
			
		||||
	}
 | 
			
		||||
	state = int(utf8d[256+state*16+int(t)])
 | 
			
		||||
	return state, x
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								vendor/github.com/gorilla/websocket/examples/chat/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/gorilla/websocket/examples/chat/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Time allowed to write a message to the peer.
 | 
			
		||||
	writeWait = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Time allowed to read the next pong message from the peer.
 | 
			
		||||
	pongWait = 60 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Send pings to peer with this period. Must be less than pongWait.
 | 
			
		||||
	pingPeriod = (pongWait * 9) / 10
 | 
			
		||||
 | 
			
		||||
	// Maximum message size allowed from peer.
 | 
			
		||||
	maxMessageSize = 512
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var upgrader = websocket.Upgrader{
 | 
			
		||||
	ReadBufferSize:  1024,
 | 
			
		||||
	WriteBufferSize: 1024,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// connection is an middleman between the websocket connection and the hub.
 | 
			
		||||
type connection struct {
 | 
			
		||||
	// The websocket connection.
 | 
			
		||||
	ws *websocket.Conn
 | 
			
		||||
 | 
			
		||||
	// Buffered channel of outbound messages.
 | 
			
		||||
	send chan []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readPump pumps messages from the websocket connection to the hub.
 | 
			
		||||
func (c *connection) readPump() {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		h.unregister <- c
 | 
			
		||||
		c.ws.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	c.ws.SetReadLimit(maxMessageSize)
 | 
			
		||||
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
 | 
			
		||||
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
 | 
			
		||||
	for {
 | 
			
		||||
		_, message, err := c.ws.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
 | 
			
		||||
				log.Printf("error: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		h.broadcast <- message
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// write writes a message with the given message type and payload.
 | 
			
		||||
func (c *connection) write(mt int, payload []byte) error {
 | 
			
		||||
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
 | 
			
		||||
	return c.ws.WriteMessage(mt, payload)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// writePump pumps messages from the hub to the websocket connection.
 | 
			
		||||
func (c *connection) writePump() {
 | 
			
		||||
	ticker := time.NewTicker(pingPeriod)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		ticker.Stop()
 | 
			
		||||
		c.ws.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case message, ok := <-c.send:
 | 
			
		||||
			if !ok {
 | 
			
		||||
				c.write(websocket.CloseMessage, []byte{})
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if err := c.write(websocket.TextMessage, message); err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serveWs handles websocket requests from the peer.
 | 
			
		||||
func serveWs(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	ws, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	c := &connection{send: make(chan []byte, 256), ws: ws}
 | 
			
		||||
	h.register <- c
 | 
			
		||||
	go c.writePump()
 | 
			
		||||
	c.readPump()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								vendor/github.com/gorilla/websocket/examples/chat/hub.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/gorilla/websocket/examples/chat/hub.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 main
 | 
			
		||||
 | 
			
		||||
// hub maintains the set of active connections and broadcasts messages to the
 | 
			
		||||
// connections.
 | 
			
		||||
type hub struct {
 | 
			
		||||
	// Registered connections.
 | 
			
		||||
	connections map[*connection]bool
 | 
			
		||||
 | 
			
		||||
	// Inbound messages from the connections.
 | 
			
		||||
	broadcast chan []byte
 | 
			
		||||
 | 
			
		||||
	// Register requests from the connections.
 | 
			
		||||
	register chan *connection
 | 
			
		||||
 | 
			
		||||
	// Unregister requests from connections.
 | 
			
		||||
	unregister chan *connection
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var h = hub{
 | 
			
		||||
	broadcast:   make(chan []byte),
 | 
			
		||||
	register:    make(chan *connection),
 | 
			
		||||
	unregister:  make(chan *connection),
 | 
			
		||||
	connections: make(map[*connection]bool),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *hub) run() {
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case c := <-h.register:
 | 
			
		||||
			h.connections[c] = true
 | 
			
		||||
		case c := <-h.unregister:
 | 
			
		||||
			if _, ok := h.connections[c]; ok {
 | 
			
		||||
				delete(h.connections, c)
 | 
			
		||||
				close(c.send)
 | 
			
		||||
			}
 | 
			
		||||
		case m := <-h.broadcast:
 | 
			
		||||
			for c := range h.connections {
 | 
			
		||||
				select {
 | 
			
		||||
				case c.send <- m:
 | 
			
		||||
				default:
 | 
			
		||||
					close(c.send)
 | 
			
		||||
					delete(h.connections, c)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/gorilla/websocket/examples/chat/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/gorilla/websocket/examples/chat/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"text/template"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var addr = flag.String("addr", ":8080", "http service address")
 | 
			
		||||
var homeTempl = template.Must(template.ParseFiles("home.html"))
 | 
			
		||||
 | 
			
		||||
func serveHome(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		http.Error(w, "Not found", 404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if r.Method != "GET" {
 | 
			
		||||
		http.Error(w, "Method not allowed", 405)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
	homeTempl.Execute(w, r.Host)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	go h.run()
 | 
			
		||||
	http.HandleFunc("/", serveHome)
 | 
			
		||||
	http.HandleFunc("/ws", serveWs)
 | 
			
		||||
	err := http.ListenAndServe(*addr, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("ListenAndServe: ", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								vendor/github.com/gorilla/websocket/examples/command/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								vendor/github.com/gorilla/websocket/examples/command/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
// Copyright 2015 The Gorilla WebSocket 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 main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"text/template"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	addr      = flag.String("addr", "127.0.0.1:8080", "http service address")
 | 
			
		||||
	cmdPath   string
 | 
			
		||||
	homeTempl = template.Must(template.ParseFiles("home.html"))
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Time allowed to write a message to the peer.
 | 
			
		||||
	writeWait = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Maximum message size allowed from peer.
 | 
			
		||||
	maxMessageSize = 8192
 | 
			
		||||
 | 
			
		||||
	// Time allowed to read the next pong message from the peer.
 | 
			
		||||
	pongWait = 60 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Send pings to peer with this period. Must be less than pongWait.
 | 
			
		||||
	pingPeriod = (pongWait * 9) / 10
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func pumpStdin(ws *websocket.Conn, w io.Writer) {
 | 
			
		||||
	defer ws.Close()
 | 
			
		||||
	ws.SetReadLimit(maxMessageSize)
 | 
			
		||||
	ws.SetReadDeadline(time.Now().Add(pongWait))
 | 
			
		||||
	ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
 | 
			
		||||
	for {
 | 
			
		||||
		_, message, err := ws.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		message = append(message, '\n')
 | 
			
		||||
		if _, err := w.Write(message); err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		ws.Close()
 | 
			
		||||
		close(done)
 | 
			
		||||
	}()
 | 
			
		||||
	s := bufio.NewScanner(r)
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		ws.SetWriteDeadline(time.Now().Add(writeWait))
 | 
			
		||||
		if err := ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if s.Err() != nil {
 | 
			
		||||
		log.Println("scan:", s.Err())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ping(ws *websocket.Conn, done chan struct{}) {
 | 
			
		||||
	ticker := time.NewTicker(pingPeriod)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
			if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
 | 
			
		||||
				log.Println("ping:", err)
 | 
			
		||||
			}
 | 
			
		||||
		case <-done:
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func internalError(ws *websocket.Conn, msg string, err error) {
 | 
			
		||||
	log.Println(msg, err)
 | 
			
		||||
	ws.WriteMessage(websocket.TextMessage, []byte("Internal server error."))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var upgrader = websocket.Upgrader{}
 | 
			
		||||
 | 
			
		||||
func serveWs(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	ws, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("upgrade:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer ws.Close()
 | 
			
		||||
 | 
			
		||||
	outr, outw, err := os.Pipe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		internalError(ws, "stdout:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer outr.Close()
 | 
			
		||||
	defer outw.Close()
 | 
			
		||||
 | 
			
		||||
	inr, inw, err := os.Pipe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		internalError(ws, "stdin:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer inr.Close()
 | 
			
		||||
	defer inw.Close()
 | 
			
		||||
 | 
			
		||||
	proc, err := os.StartProcess(cmdPath, flag.Args(), &os.ProcAttr{
 | 
			
		||||
		Files: []*os.File{inr, outw, outw},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		internalError(ws, "start:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inr.Close()
 | 
			
		||||
	outw.Close()
 | 
			
		||||
 | 
			
		||||
	stdoutDone := make(chan struct{})
 | 
			
		||||
	go pumpStdout(ws, outr, stdoutDone)
 | 
			
		||||
	go ping(ws, stdoutDone)
 | 
			
		||||
 | 
			
		||||
	pumpStdin(ws, inw)
 | 
			
		||||
 | 
			
		||||
	// Some commands will exit when stdin is closed.
 | 
			
		||||
	inw.Close()
 | 
			
		||||
 | 
			
		||||
	// Other commands need a bonk on the head.
 | 
			
		||||
	if err := proc.Signal(os.Interrupt); err != nil {
 | 
			
		||||
		log.Println("inter:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-stdoutDone:
 | 
			
		||||
	case <-time.After(time.Second):
 | 
			
		||||
		// A bigger bonk on the head.
 | 
			
		||||
		if err := proc.Signal(os.Kill); err != nil {
 | 
			
		||||
			log.Println("term:", err)
 | 
			
		||||
		}
 | 
			
		||||
		<-stdoutDone
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := proc.Wait(); err != nil {
 | 
			
		||||
		log.Println("wait:", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveHome(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		http.Error(w, "Not found", 404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if r.Method != "GET" {
 | 
			
		||||
		http.Error(w, "Method not allowed", 405)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
	homeTempl.Execute(w, r.Host)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if len(flag.Args()) < 1 {
 | 
			
		||||
		log.Fatal("must specify at least one argument")
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	cmdPath, err = exec.LookPath(flag.Args()[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	http.HandleFunc("/", serveHome)
 | 
			
		||||
	http.HandleFunc("/ws", serveWs)
 | 
			
		||||
	log.Fatal(http.ListenAndServe(*addr, nil))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								vendor/github.com/gorilla/websocket/examples/echo/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/gorilla/websocket/examples/echo/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
// Copyright 2015 The Gorilla WebSocket 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 ignore
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/signal"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var addr = flag.String("addr", "localhost:8080", "http service address")
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	log.SetFlags(0)
 | 
			
		||||
 | 
			
		||||
	interrupt := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(interrupt, os.Interrupt)
 | 
			
		||||
 | 
			
		||||
	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
 | 
			
		||||
	log.Printf("connecting to %s", u.String())
 | 
			
		||||
 | 
			
		||||
	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal("dial:", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer c.Close()
 | 
			
		||||
 | 
			
		||||
	done := make(chan struct{})
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		defer c.Close()
 | 
			
		||||
		defer close(done)
 | 
			
		||||
		for {
 | 
			
		||||
			_, message, err := c.ReadMessage()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("read:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			log.Printf("recv: %s", message)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	ticker := time.NewTicker(time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case t := <-ticker.C:
 | 
			
		||||
			err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("write:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		case <-interrupt:
 | 
			
		||||
			log.Println("interrupt")
 | 
			
		||||
			// To cleanly close a connection, a client should send a close
 | 
			
		||||
			// frame and wait for the server to close the connection.
 | 
			
		||||
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("write close:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			select {
 | 
			
		||||
			case <-done:
 | 
			
		||||
			case <-time.After(time.Second):
 | 
			
		||||
			}
 | 
			
		||||
			c.Close()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								vendor/github.com/gorilla/websocket/examples/echo/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/gorilla/websocket/examples/echo/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
// Copyright 2015 The Gorilla WebSocket 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 ignore
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var addr = flag.String("addr", "localhost:8080", "http service address")
 | 
			
		||||
 | 
			
		||||
var upgrader = websocket.Upgrader{} // use default options
 | 
			
		||||
 | 
			
		||||
func echo(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	c, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Print("upgrade:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer c.Close()
 | 
			
		||||
	for {
 | 
			
		||||
		mt, message, err := c.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("read:", err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("recv: %s", message)
 | 
			
		||||
		err = c.WriteMessage(mt, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("write:", err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func home(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	log.SetFlags(0)
 | 
			
		||||
	http.HandleFunc("/echo", echo)
 | 
			
		||||
	http.HandleFunc("/", home)
 | 
			
		||||
	log.Fatal(http.ListenAndServe(*addr, nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var homeTemplate = template.Must(template.New("").Parse(`
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<head>
 | 
			
		||||
<meta charset="utf-8">
 | 
			
		||||
<script>  
 | 
			
		||||
window.addEventListener("load", function(evt) {
 | 
			
		||||
 | 
			
		||||
    var output = document.getElementById("output");
 | 
			
		||||
    var input = document.getElementById("input");
 | 
			
		||||
    var ws;
 | 
			
		||||
 | 
			
		||||
    var print = function(message) {
 | 
			
		||||
        var d = document.createElement("div");
 | 
			
		||||
        d.innerHTML = message;
 | 
			
		||||
        output.appendChild(d);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.getElementById("open").onclick = function(evt) {
 | 
			
		||||
        if (ws) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        ws = new WebSocket("{{.}}");
 | 
			
		||||
        ws.onopen = function(evt) {
 | 
			
		||||
            print("OPEN");
 | 
			
		||||
        }
 | 
			
		||||
        ws.onclose = function(evt) {
 | 
			
		||||
            print("CLOSE");
 | 
			
		||||
            ws = null;
 | 
			
		||||
        }
 | 
			
		||||
        ws.onmessage = function(evt) {
 | 
			
		||||
            print("RESPONSE: " + evt.data);
 | 
			
		||||
        }
 | 
			
		||||
        ws.onerror = function(evt) {
 | 
			
		||||
            print("ERROR: " + evt.data);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.getElementById("send").onclick = function(evt) {
 | 
			
		||||
        if (!ws) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        print("SEND: " + input.value);
 | 
			
		||||
        ws.send(input.value);
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.getElementById("close").onclick = function(evt) {
 | 
			
		||||
        if (!ws) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        ws.close();
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<table>
 | 
			
		||||
<tr><td valign="top" width="50%">
 | 
			
		||||
<p>Click "Open" to create a connection to the server, 
 | 
			
		||||
"Send" to send a message to the server and "Close" to close the connection. 
 | 
			
		||||
You can change the message and send multiple times.
 | 
			
		||||
<p>
 | 
			
		||||
<form>
 | 
			
		||||
<button id="open">Open</button>
 | 
			
		||||
<button id="close">Close</button>
 | 
			
		||||
<p><input id="input" type="text" value="Hello world!">
 | 
			
		||||
<button id="send">Send</button>
 | 
			
		||||
</form>
 | 
			
		||||
</td><td valign="top" width="50%">
 | 
			
		||||
<div id="output"></div>
 | 
			
		||||
</td></tr></table>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
`))
 | 
			
		||||
							
								
								
									
										193
									
								
								vendor/github.com/gorilla/websocket/examples/filewatch/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								vendor/github.com/gorilla/websocket/examples/filewatch/main.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"text/template"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Time allowed to write the file to the client.
 | 
			
		||||
	writeWait = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Time allowed to read the next pong message from the client.
 | 
			
		||||
	pongWait = 60 * time.Second
 | 
			
		||||
 | 
			
		||||
	// Send pings to client with this period. Must be less than pongWait.
 | 
			
		||||
	pingPeriod = (pongWait * 9) / 10
 | 
			
		||||
 | 
			
		||||
	// Poll file for changes with this period.
 | 
			
		||||
	filePeriod = 10 * time.Second
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	addr      = flag.String("addr", ":8080", "http service address")
 | 
			
		||||
	homeTempl = template.Must(template.New("").Parse(homeHTML))
 | 
			
		||||
	filename  string
 | 
			
		||||
	upgrader  = websocket.Upgrader{
 | 
			
		||||
		ReadBufferSize:  1024,
 | 
			
		||||
		WriteBufferSize: 1024,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
 | 
			
		||||
	fi, err := os.Stat(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, lastMod, err
 | 
			
		||||
	}
 | 
			
		||||
	if !fi.ModTime().After(lastMod) {
 | 
			
		||||
		return nil, lastMod, nil
 | 
			
		||||
	}
 | 
			
		||||
	p, err := ioutil.ReadFile(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fi.ModTime(), err
 | 
			
		||||
	}
 | 
			
		||||
	return p, fi.ModTime(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reader(ws *websocket.Conn) {
 | 
			
		||||
	defer ws.Close()
 | 
			
		||||
	ws.SetReadLimit(512)
 | 
			
		||||
	ws.SetReadDeadline(time.Now().Add(pongWait))
 | 
			
		||||
	ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
 | 
			
		||||
	for {
 | 
			
		||||
		_, _, err := ws.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writer(ws *websocket.Conn, lastMod time.Time) {
 | 
			
		||||
	lastError := ""
 | 
			
		||||
	pingTicker := time.NewTicker(pingPeriod)
 | 
			
		||||
	fileTicker := time.NewTicker(filePeriod)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		pingTicker.Stop()
 | 
			
		||||
		fileTicker.Stop()
 | 
			
		||||
		ws.Close()
 | 
			
		||||
	}()
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-fileTicker.C:
 | 
			
		||||
			var p []byte
 | 
			
		||||
			var err error
 | 
			
		||||
 | 
			
		||||
			p, lastMod, err = readFileIfModified(lastMod)
 | 
			
		||||
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				if s := err.Error(); s != lastError {
 | 
			
		||||
					lastError = s
 | 
			
		||||
					p = []byte(lastError)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				lastError = ""
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if p != nil {
 | 
			
		||||
				ws.SetWriteDeadline(time.Now().Add(writeWait))
 | 
			
		||||
				if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case <-pingTicker.C:
 | 
			
		||||
			ws.SetWriteDeadline(time.Now().Add(writeWait))
 | 
			
		||||
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveWs(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	ws, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(websocket.HandshakeError); !ok {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var lastMod time.Time
 | 
			
		||||
	if n, err := strconv.ParseInt(r.FormValue("lastMod"), 16, 64); err != nil {
 | 
			
		||||
		lastMod = time.Unix(0, n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go writer(ws, lastMod)
 | 
			
		||||
	reader(ws)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveHome(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		http.Error(w, "Not found", 404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if r.Method != "GET" {
 | 
			
		||||
		http.Error(w, "Method not allowed", 405)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
			
		||||
	p, lastMod, err := readFileIfModified(time.Time{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		p = []byte(err.Error())
 | 
			
		||||
		lastMod = time.Unix(0, 0)
 | 
			
		||||
	}
 | 
			
		||||
	var v = struct {
 | 
			
		||||
		Host    string
 | 
			
		||||
		Data    string
 | 
			
		||||
		LastMod string
 | 
			
		||||
	}{
 | 
			
		||||
		r.Host,
 | 
			
		||||
		string(p),
 | 
			
		||||
		strconv.FormatInt(lastMod.UnixNano(), 16),
 | 
			
		||||
	}
 | 
			
		||||
	homeTempl.Execute(w, &v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if flag.NArg() != 1 {
 | 
			
		||||
		log.Fatal("filename not specified")
 | 
			
		||||
	}
 | 
			
		||||
	filename = flag.Args()[0]
 | 
			
		||||
	http.HandleFunc("/", serveHome)
 | 
			
		||||
	http.HandleFunc("/ws", serveWs)
 | 
			
		||||
	if err := http.ListenAndServe(*addr, nil); err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const homeHTML = `<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
    <head>
 | 
			
		||||
        <title>WebSocket Example</title>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <pre id="fileData">{{.Data}}</pre>
 | 
			
		||||
        <script type="text/javascript">
 | 
			
		||||
            (function() {
 | 
			
		||||
                var data = document.getElementById("fileData");
 | 
			
		||||
                var conn = new WebSocket("ws://{{.Host}}/ws?lastMod={{.LastMod}}");
 | 
			
		||||
                conn.onclose = function(evt) {
 | 
			
		||||
                    data.textContent = 'Connection closed';
 | 
			
		||||
                }
 | 
			
		||||
                conn.onmessage = function(evt) {
 | 
			
		||||
                    console.log('file updated');
 | 
			
		||||
                    data.textContent = evt.data;
 | 
			
		||||
                }
 | 
			
		||||
            })();
 | 
			
		||||
        </script>
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
`
 | 
			
		||||
							
								
								
									
										55
									
								
								vendor/github.com/gorilla/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/gorilla/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// WriteJSON is deprecated, use c.WriteJSON instead.
 | 
			
		||||
func WriteJSON(c *Conn, v interface{}) error {
 | 
			
		||||
	return c.WriteJSON(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteJSON writes the JSON encoding of v to the connection.
 | 
			
		||||
//
 | 
			
		||||
// See the documentation for encoding/json Marshal for details about the
 | 
			
		||||
// conversion of Go values to JSON.
 | 
			
		||||
func (c *Conn) WriteJSON(v interface{}) error {
 | 
			
		||||
	w, err := c.NextWriter(TextMessage)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err1 := json.NewEncoder(w).Encode(v)
 | 
			
		||||
	err2 := w.Close()
 | 
			
		||||
	if err1 != nil {
 | 
			
		||||
		return err1
 | 
			
		||||
	}
 | 
			
		||||
	return err2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadJSON is deprecated, use c.ReadJSON instead.
 | 
			
		||||
func ReadJSON(c *Conn, v interface{}) error {
 | 
			
		||||
	return c.ReadJSON(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadJSON reads the next JSON-encoded message from the connection and stores
 | 
			
		||||
// it in the value pointed to by v.
 | 
			
		||||
//
 | 
			
		||||
// See the documentation for the encoding/json Unmarshal function for details
 | 
			
		||||
// about the conversion of JSON to a Go value.
 | 
			
		||||
func (c *Conn) ReadJSON(v interface{}) error {
 | 
			
		||||
	_, r, err := c.NextReader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = json.NewDecoder(r).Decode(v)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		// One value is expected in the message.
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										260
									
								
								vendor/github.com/gorilla/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								vendor/github.com/gorilla/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,260 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HandshakeError describes an error with the handshake from the peer.
 | 
			
		||||
type HandshakeError struct {
 | 
			
		||||
	message string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e HandshakeError) Error() string { return e.message }
 | 
			
		||||
 | 
			
		||||
// Upgrader specifies parameters for upgrading an HTTP connection to a
 | 
			
		||||
// WebSocket connection.
 | 
			
		||||
type Upgrader struct {
 | 
			
		||||
	// HandshakeTimeout specifies the duration for the handshake to complete.
 | 
			
		||||
	HandshakeTimeout time.Duration
 | 
			
		||||
 | 
			
		||||
	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
 | 
			
		||||
	// size is zero, then a default value of 4096 is used. The I/O buffer sizes
 | 
			
		||||
	// do not limit the size of the messages that can be sent or received.
 | 
			
		||||
	ReadBufferSize, WriteBufferSize int
 | 
			
		||||
 | 
			
		||||
	// Subprotocols specifies the server's supported protocols in order of
 | 
			
		||||
	// preference. If this field is set, then the Upgrade method negotiates a
 | 
			
		||||
	// subprotocol by selecting the first match in this list with a protocol
 | 
			
		||||
	// requested by the client.
 | 
			
		||||
	Subprotocols []string
 | 
			
		||||
 | 
			
		||||
	// Error specifies the function for generating HTTP error responses. If Error
 | 
			
		||||
	// is nil, then http.Error is used to generate the HTTP response.
 | 
			
		||||
	Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
 | 
			
		||||
 | 
			
		||||
	// CheckOrigin returns true if the request Origin header is acceptable. If
 | 
			
		||||
	// CheckOrigin is nil, the host in the Origin header must not be set or
 | 
			
		||||
	// must match the host of the request.
 | 
			
		||||
	CheckOrigin func(r *http.Request) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
 | 
			
		||||
	err := HandshakeError{reason}
 | 
			
		||||
	if u.Error != nil {
 | 
			
		||||
		u.Error(w, r, status, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		http.Error(w, http.StatusText(status), status)
 | 
			
		||||
	}
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
 | 
			
		||||
func checkSameOrigin(r *http.Request) bool {
 | 
			
		||||
	origin := r.Header["Origin"]
 | 
			
		||||
	if len(origin) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	u, err := url.Parse(origin[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return u.Host == r.Host
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
 | 
			
		||||
	if u.Subprotocols != nil {
 | 
			
		||||
		clientProtocols := Subprotocols(r)
 | 
			
		||||
		for _, serverProtocol := range u.Subprotocols {
 | 
			
		||||
			for _, clientProtocol := range clientProtocols {
 | 
			
		||||
				if clientProtocol == serverProtocol {
 | 
			
		||||
					return clientProtocol
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if responseHeader != nil {
 | 
			
		||||
		return responseHeader.Get("Sec-Websocket-Protocol")
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
 | 
			
		||||
//
 | 
			
		||||
// The responseHeader is included in the response to the client's upgrade
 | 
			
		||||
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
 | 
			
		||||
// application negotiated subprotocol (Sec-Websocket-Protocol).
 | 
			
		||||
//
 | 
			
		||||
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
 | 
			
		||||
// response.
 | 
			
		||||
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
 | 
			
		||||
	if r.Method != "GET" {
 | 
			
		||||
		return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method not GET")
 | 
			
		||||
	}
 | 
			
		||||
	if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
 | 
			
		||||
		return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
 | 
			
		||||
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
 | 
			
		||||
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	checkOrigin := u.CheckOrigin
 | 
			
		||||
	if checkOrigin == nil {
 | 
			
		||||
		checkOrigin = checkSameOrigin
 | 
			
		||||
	}
 | 
			
		||||
	if !checkOrigin(r) {
 | 
			
		||||
		return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	challengeKey := r.Header.Get("Sec-Websocket-Key")
 | 
			
		||||
	if challengeKey == "" {
 | 
			
		||||
		return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	subprotocol := u.selectSubprotocol(r, responseHeader)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		netConn net.Conn
 | 
			
		||||
		br      *bufio.Reader
 | 
			
		||||
		err     error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	h, ok := w.(http.Hijacker)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
 | 
			
		||||
	}
 | 
			
		||||
	var rw *bufio.ReadWriter
 | 
			
		||||
	netConn, rw, err = h.Hijack()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return u.returnError(w, r, http.StatusInternalServerError, err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	br = rw.Reader
 | 
			
		||||
 | 
			
		||||
	if br.Buffered() > 0 {
 | 
			
		||||
		netConn.Close()
 | 
			
		||||
		return nil, errors.New("websocket: client sent data before handshake is complete")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
 | 
			
		||||
	c.subprotocol = subprotocol
 | 
			
		||||
 | 
			
		||||
	p := c.writeBuf[:0]
 | 
			
		||||
	p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
 | 
			
		||||
	p = append(p, computeAcceptKey(challengeKey)...)
 | 
			
		||||
	p = append(p, "\r\n"...)
 | 
			
		||||
	if c.subprotocol != "" {
 | 
			
		||||
		p = append(p, "Sec-Websocket-Protocol: "...)
 | 
			
		||||
		p = append(p, c.subprotocol...)
 | 
			
		||||
		p = append(p, "\r\n"...)
 | 
			
		||||
	}
 | 
			
		||||
	for k, vs := range responseHeader {
 | 
			
		||||
		if k == "Sec-Websocket-Protocol" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for _, v := range vs {
 | 
			
		||||
			p = append(p, k...)
 | 
			
		||||
			p = append(p, ": "...)
 | 
			
		||||
			for i := 0; i < len(v); i++ {
 | 
			
		||||
				b := v[i]
 | 
			
		||||
				if b <= 31 {
 | 
			
		||||
					// prevent response splitting.
 | 
			
		||||
					b = ' '
 | 
			
		||||
				}
 | 
			
		||||
				p = append(p, b)
 | 
			
		||||
			}
 | 
			
		||||
			p = append(p, "\r\n"...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p = append(p, "\r\n"...)
 | 
			
		||||
 | 
			
		||||
	// Clear deadlines set by HTTP server.
 | 
			
		||||
	netConn.SetDeadline(time.Time{})
 | 
			
		||||
 | 
			
		||||
	if u.HandshakeTimeout > 0 {
 | 
			
		||||
		netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = netConn.Write(p); err != nil {
 | 
			
		||||
		netConn.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if u.HandshakeTimeout > 0 {
 | 
			
		||||
		netConn.SetWriteDeadline(time.Time{})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
 | 
			
		||||
//
 | 
			
		||||
// This function is deprecated, use websocket.Upgrader instead.
 | 
			
		||||
//
 | 
			
		||||
// The application is responsible for checking the request origin before
 | 
			
		||||
// calling Upgrade. An example implementation of the same origin policy is:
 | 
			
		||||
//
 | 
			
		||||
//	if req.Header.Get("Origin") != "http://"+req.Host {
 | 
			
		||||
//		http.Error(w, "Origin not allowed", 403)
 | 
			
		||||
//		return
 | 
			
		||||
//	}
 | 
			
		||||
//
 | 
			
		||||
// If the endpoint supports subprotocols, then the application is responsible
 | 
			
		||||
// for negotiating the protocol used on the connection. Use the Subprotocols()
 | 
			
		||||
// function to get the subprotocols requested by the client. Use the
 | 
			
		||||
// Sec-Websocket-Protocol response header to specify the subprotocol selected
 | 
			
		||||
// by the application.
 | 
			
		||||
//
 | 
			
		||||
// The responseHeader is included in the response to the client's upgrade
 | 
			
		||||
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
 | 
			
		||||
// negotiated subprotocol (Sec-Websocket-Protocol).
 | 
			
		||||
//
 | 
			
		||||
// The connection buffers IO to the underlying network connection. The
 | 
			
		||||
// readBufSize and writeBufSize parameters specify the size of the buffers to
 | 
			
		||||
// use. Messages can be larger than the buffers.
 | 
			
		||||
//
 | 
			
		||||
// If the request is not a valid WebSocket handshake, then Upgrade returns an
 | 
			
		||||
// error of type HandshakeError. Applications should handle this error by
 | 
			
		||||
// replying to the client with an HTTP error response.
 | 
			
		||||
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
 | 
			
		||||
	u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
 | 
			
		||||
	u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
 | 
			
		||||
		// don't return errors to maintain backwards compatibility
 | 
			
		||||
	}
 | 
			
		||||
	u.CheckOrigin = func(r *http.Request) bool {
 | 
			
		||||
		// allow all connections by default
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return u.Upgrade(w, r, responseHeader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subprotocols returns the subprotocols requested by the client in the
 | 
			
		||||
// Sec-Websocket-Protocol header.
 | 
			
		||||
func Subprotocols(r *http.Request) []string {
 | 
			
		||||
	h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
 | 
			
		||||
	if h == "" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	protocols := strings.Split(h, ",")
 | 
			
		||||
	for i := range protocols {
 | 
			
		||||
		protocols[i] = strings.TrimSpace(protocols[i])
 | 
			
		||||
	}
 | 
			
		||||
	return protocols
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsWebSocketUpgrade returns true if the client requested upgrade to the
 | 
			
		||||
// WebSocket protocol.
 | 
			
		||||
func IsWebSocketUpgrade(r *http.Request) bool {
 | 
			
		||||
	return tokenListContainsValue(r.Header, "Connection", "upgrade") &&
 | 
			
		||||
		tokenListContainsValue(r.Header, "Upgrade", "websocket")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/github.com/gorilla/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/gorilla/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
// Copyright 2013 The Gorilla WebSocket 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 websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// tokenListContainsValue returns true if the 1#token header with the given
 | 
			
		||||
// name contains token.
 | 
			
		||||
func tokenListContainsValue(header http.Header, name string, value string) bool {
 | 
			
		||||
	for _, v := range header[name] {
 | 
			
		||||
		for _, s := range strings.Split(v, ",") {
 | 
			
		||||
			if strings.EqualFold(value, strings.TrimSpace(s)) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
 | 
			
		||||
 | 
			
		||||
func computeAcceptKey(challengeKey string) string {
 | 
			
		||||
	h := sha1.New()
 | 
			
		||||
	h.Write([]byte(challengeKey))
 | 
			
		||||
	h.Write(keyGUID)
 | 
			
		||||
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func generateChallengeKey() (string, error) {
 | 
			
		||||
	p := make([]byte, 16)
 | 
			
		||||
	if _, err := io.ReadFull(rand.Reader, p); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return base64.StdEncoding.EncodeToString(p), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								vendor/github.com/jpillora/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/jpillora/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//Backoff is a time.Duration counter. It starts at Min.
 | 
			
		||||
//After every call to Duration() it is  multiplied by Factor.
 | 
			
		||||
//It is capped at Max. It returns to Min on every call to Reset().
 | 
			
		||||
//Used in conjunction with the time package.
 | 
			
		||||
//
 | 
			
		||||
// Backoff is not threadsafe, but the ForAttempt method can be
 | 
			
		||||
// used concurrently if non-zero values for Factor, Max, and Min
 | 
			
		||||
// are set on the Backoff shared among threads.
 | 
			
		||||
type Backoff struct {
 | 
			
		||||
	//Factor is the multiplying factor for each increment step
 | 
			
		||||
	attempts, Factor float64
 | 
			
		||||
	//Jitter eases contention by randomizing backoff steps
 | 
			
		||||
	Jitter bool
 | 
			
		||||
	//Min and Max are the minimum and maximum values of the counter
 | 
			
		||||
	Min, Max time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Returns the current value of the counter and then
 | 
			
		||||
//multiplies it Factor
 | 
			
		||||
func (b *Backoff) Duration() time.Duration {
 | 
			
		||||
	d := b.ForAttempt(b.attempts)
 | 
			
		||||
	b.attempts++
 | 
			
		||||
	return d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForAttempt returns the duration for a specific attempt. This is useful if
 | 
			
		||||
// you have a large number of independent Backoffs, but don't want use
 | 
			
		||||
// unnecessary memory storing the Backoff parameters per Backoff. The first
 | 
			
		||||
// attempt should be 0.
 | 
			
		||||
//
 | 
			
		||||
// ForAttempt is threadsafe iff non-zero values for Factor, Max, and Min
 | 
			
		||||
// are set before any calls to ForAttempt are made.
 | 
			
		||||
func (b *Backoff) ForAttempt(attempt float64) time.Duration {
 | 
			
		||||
	//Zero-values are nonsensical, so we use
 | 
			
		||||
	//them to apply defaults
 | 
			
		||||
	if b.Min == 0 {
 | 
			
		||||
		b.Min = 100 * time.Millisecond
 | 
			
		||||
	}
 | 
			
		||||
	if b.Max == 0 {
 | 
			
		||||
		b.Max = 10 * time.Second
 | 
			
		||||
	}
 | 
			
		||||
	if b.Factor == 0 {
 | 
			
		||||
		b.Factor = 2
 | 
			
		||||
	}
 | 
			
		||||
	//calculate this duration
 | 
			
		||||
	dur := float64(b.Min) * math.Pow(b.Factor, attempt)
 | 
			
		||||
	if b.Jitter == true {
 | 
			
		||||
		dur = rand.Float64()*(dur-float64(b.Min)) + float64(b.Min)
 | 
			
		||||
	}
 | 
			
		||||
	//cap!
 | 
			
		||||
	if dur > float64(b.Max) {
 | 
			
		||||
		return b.Max
 | 
			
		||||
	}
 | 
			
		||||
	//return as a time.Duration
 | 
			
		||||
	return time.Duration(dur)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Resets the current value of the counter back to Min
 | 
			
		||||
func (b *Backoff) Reset() {
 | 
			
		||||
	b.attempts = 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										897
									
								
								vendor/github.com/mattermost/platform/einterfaces/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										897
									
								
								vendor/github.com/mattermost/platform/einterfaces/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,897 @@
 | 
			
		||||
Mattermost Licensing
 | 
			
		||||
 | 
			
		||||
SOFTWARE LICENSING 
 | 
			
		||||
 | 
			
		||||
You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE 
 | 
			
		||||
 | 
			
		||||
-	See MIT-COMPILED-LICENSE.md included in compiled versions for details
 | 
			
		||||
 | 
			
		||||
You may be licensed to use source code to create compiled versions not produced by Mattermost, Inc. in one of two ways:
 | 
			
		||||
 | 
			
		||||
1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or 
 | 
			
		||||
2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com 
 | 
			
		||||
 | 
			
		||||
You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/, 
 | 
			
		||||
webapp/client, webapp/fonts, webapp/i18n, webapp/images and all subdirectories thereof) under the Apache License v2.0.
 | 
			
		||||
 | 
			
		||||
We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not 
 | 
			
		||||
link to the Mattermost Platform directly, but exclusively uses the Mattermost Admin Tools and Configuration Files, and
 | 
			
		||||
(b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of 
 | 
			
		||||
a “modified version” or “work based on” Mattermost as these terms are defined in the AGPL v3.0 license.
 | 
			
		||||
 | 
			
		||||
MATTERMOST TRADEMARK GUIDELINES
 | 
			
		||||
 | 
			
		||||
Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark 
 | 
			
		||||
Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions 
 | 
			
		||||
you have about using these trademarks, please email trademark@mattermost.com 
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
                               
 | 
			
		||||
                               Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
The software is released under the terms of the GNU Affero General Public
 | 
			
		||||
License, version 3.
 | 
			
		||||
 | 
			
		||||
                    GNU AFFERO GENERAL PUBLIC LICENSE
 | 
			
		||||
                       Version 3, 19 November 2007
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
                            Preamble
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is a free, copyleft license for
 | 
			
		||||
software and other kinds of works, specifically designed to ensure
 | 
			
		||||
cooperation with the community in the case of network server software.
 | 
			
		||||
 | 
			
		||||
  The licenses for most software and other practical works are designed
 | 
			
		||||
to take away your freedom to share and change the works.  By contrast,
 | 
			
		||||
our General Public Licenses are intended to guarantee your freedom to
 | 
			
		||||
share and change all versions of a program--to make sure it remains free
 | 
			
		||||
software for all its users.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
them if you wish), that you receive source code or can get it if you
 | 
			
		||||
want it, that you can change the software or use pieces of it in new
 | 
			
		||||
free programs, and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  Developers that use our General Public Licenses protect your rights
 | 
			
		||||
with two steps: (1) assert copyright on the software, and (2) offer
 | 
			
		||||
you this License which gives you legal permission to copy, distribute
 | 
			
		||||
and/or modify the software.
 | 
			
		||||
 | 
			
		||||
  A secondary benefit of defending all users' freedom is that
 | 
			
		||||
improvements made in alternate versions of the program, if they
 | 
			
		||||
receive widespread use, become available for other developers to
 | 
			
		||||
incorporate.  Many developers of free software are heartened and
 | 
			
		||||
encouraged by the resulting cooperation.  However, in the case of
 | 
			
		||||
software used on network servers, this result may fail to come about.
 | 
			
		||||
The GNU General Public License permits making a modified version and
 | 
			
		||||
letting the public access it on a server without ever releasing its
 | 
			
		||||
source code to the public.
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is designed specifically to
 | 
			
		||||
ensure that, in such cases, the modified source code becomes available
 | 
			
		||||
to the community.  It requires the operator of a network server to
 | 
			
		||||
provide the source code of the modified version running there to the
 | 
			
		||||
users of that server.  Therefore, public use of a modified version, on
 | 
			
		||||
a publicly accessible server, gives the public access to the source
 | 
			
		||||
code of the modified version.
 | 
			
		||||
 | 
			
		||||
  An older license, called the Affero General Public License and
 | 
			
		||||
published by Affero, was designed to accomplish similar goals.  This is
 | 
			
		||||
a different license, not a version of the Affero GPL, but Affero has
 | 
			
		||||
released a new version of the Affero GPL which permits relicensing under
 | 
			
		||||
this license.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
                       TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
  0. Definitions.
 | 
			
		||||
 | 
			
		||||
  "This License" refers to version 3 of the GNU Affero General Public License.
 | 
			
		||||
 | 
			
		||||
  "Copyright" also means copyright-like laws that apply to other kinds of
 | 
			
		||||
works, such as semiconductor masks.
 | 
			
		||||
 | 
			
		||||
  "The Program" refers to any copyrightable work licensed under this
 | 
			
		||||
License.  Each licensee is addressed as "you".  "Licensees" and
 | 
			
		||||
"recipients" may be individuals or organizations.
 | 
			
		||||
 | 
			
		||||
  To "modify" a work means to copy from or adapt all or part of the work
 | 
			
		||||
in a fashion requiring copyright permission, other than the making of an
 | 
			
		||||
exact copy.  The resulting work is called a "modified version" of the
 | 
			
		||||
earlier work or a work "based on" the earlier work.
 | 
			
		||||
 | 
			
		||||
  A "covered work" means either the unmodified Program or a work based
 | 
			
		||||
on the Program.
 | 
			
		||||
 | 
			
		||||
  To "propagate" a work means to do anything with it that, without
 | 
			
		||||
permission, would make you directly or secondarily liable for
 | 
			
		||||
infringement under applicable copyright law, except executing it on a
 | 
			
		||||
computer or modifying a private copy.  Propagation includes copying,
 | 
			
		||||
distribution (with or without modification), making available to the
 | 
			
		||||
public, and in some countries other activities as well.
 | 
			
		||||
 | 
			
		||||
  To "convey" a work means any kind of propagation that enables other
 | 
			
		||||
parties to make or receive copies.  Mere interaction with a user through
 | 
			
		||||
a computer network, with no transfer of a copy, is not conveying.
 | 
			
		||||
 | 
			
		||||
  An interactive user interface displays "Appropriate Legal Notices"
 | 
			
		||||
to the extent that it includes a convenient and prominently visible
 | 
			
		||||
feature that (1) displays an appropriate copyright notice, and (2)
 | 
			
		||||
tells the user that there is no warranty for the work (except to the
 | 
			
		||||
extent that warranties are provided), that licensees may convey the
 | 
			
		||||
work under this License, and how to view a copy of this License.  If
 | 
			
		||||
the interface presents a list of user commands or options, such as a
 | 
			
		||||
menu, a prominent item in the list meets this criterion.
 | 
			
		||||
 | 
			
		||||
  1. Source Code.
 | 
			
		||||
 | 
			
		||||
  The "source code" for a work means the preferred form of the work
 | 
			
		||||
for making modifications to it.  "Object code" means any non-source
 | 
			
		||||
form of a work.
 | 
			
		||||
 | 
			
		||||
  A "Standard Interface" means an interface that either is an official
 | 
			
		||||
standard defined by a recognized standards body, or, in the case of
 | 
			
		||||
interfaces specified for a particular programming language, one that
 | 
			
		||||
is widely used among developers working in that language.
 | 
			
		||||
 | 
			
		||||
  The "System Libraries" of an executable work include anything, other
 | 
			
		||||
than the work as a whole, that (a) is included in the normal form of
 | 
			
		||||
packaging a Major Component, but which is not part of that Major
 | 
			
		||||
Component, and (b) serves only to enable use of the work with that
 | 
			
		||||
Major Component, or to implement a Standard Interface for which an
 | 
			
		||||
implementation is available to the public in source code form.  A
 | 
			
		||||
"Major Component", in this context, means a major essential component
 | 
			
		||||
(kernel, window system, and so on) of the specific operating system
 | 
			
		||||
(if any) on which the executable work runs, or a compiler used to
 | 
			
		||||
produce the work, or an object code interpreter used to run it.
 | 
			
		||||
 | 
			
		||||
  The "Corresponding Source" for a work in object code form means all
 | 
			
		||||
the source code needed to generate, install, and (for an executable
 | 
			
		||||
work) run the object code and to modify the work, including scripts to
 | 
			
		||||
control those activities.  However, it does not include the work's
 | 
			
		||||
System Libraries, or general-purpose tools or generally available free
 | 
			
		||||
programs which are used unmodified in performing those activities but
 | 
			
		||||
which are not part of the work.  For example, Corresponding Source
 | 
			
		||||
includes interface definition files associated with source files for
 | 
			
		||||
the work, and the source code for shared libraries and dynamically
 | 
			
		||||
linked subprograms that the work is specifically designed to require,
 | 
			
		||||
such as by intimate data communication or control flow between those
 | 
			
		||||
subprograms and other parts of the work.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source need not include anything that users
 | 
			
		||||
can regenerate automatically from other parts of the Corresponding
 | 
			
		||||
Source.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source for a work in source code form is that
 | 
			
		||||
same work.
 | 
			
		||||
 | 
			
		||||
  2. Basic Permissions.
 | 
			
		||||
 | 
			
		||||
  All rights granted under this License are granted for the term of
 | 
			
		||||
copyright on the Program, and are irrevocable provided the stated
 | 
			
		||||
conditions are met.  This License explicitly affirms your unlimited
 | 
			
		||||
permission to run the unmodified Program.  The output from running a
 | 
			
		||||
covered work is covered by this License only if the output, given its
 | 
			
		||||
content, constitutes a covered work.  This License acknowledges your
 | 
			
		||||
rights of fair use or other equivalent, as provided by copyright law.
 | 
			
		||||
 | 
			
		||||
  You may make, run and propagate covered works that you do not
 | 
			
		||||
convey, without conditions so long as your license otherwise remains
 | 
			
		||||
in force.  You may convey covered works to others for the sole purpose
 | 
			
		||||
of having them make modifications exclusively for you, or provide you
 | 
			
		||||
with facilities for running those works, provided that you comply with
 | 
			
		||||
the terms of this License in conveying all material for which you do
 | 
			
		||||
not control copyright.  Those thus making or running the covered works
 | 
			
		||||
for you must do so exclusively on your behalf, under your direction
 | 
			
		||||
and control, on terms that prohibit them from making any copies of
 | 
			
		||||
your copyrighted material outside their relationship with you.
 | 
			
		||||
 | 
			
		||||
  Conveying under any other circumstances is permitted solely under
 | 
			
		||||
the conditions stated below.  Sublicensing is not allowed; section 10
 | 
			
		||||
makes it unnecessary.
 | 
			
		||||
 | 
			
		||||
  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 | 
			
		||||
 | 
			
		||||
  No covered work shall be deemed part of an effective technological
 | 
			
		||||
measure under any applicable law fulfilling obligations under article
 | 
			
		||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
 | 
			
		||||
similar laws prohibiting or restricting circumvention of such
 | 
			
		||||
measures.
 | 
			
		||||
 | 
			
		||||
  When you convey a covered work, you waive any legal power to forbid
 | 
			
		||||
circumvention of technological measures to the extent such circumvention
 | 
			
		||||
is effected by exercising rights under this License with respect to
 | 
			
		||||
the covered work, and you disclaim any intention to limit operation or
 | 
			
		||||
modification of the work as a means of enforcing, against the work's
 | 
			
		||||
users, your or third parties' legal rights to forbid circumvention of
 | 
			
		||||
technological measures.
 | 
			
		||||
 | 
			
		||||
  4. Conveying Verbatim Copies.
 | 
			
		||||
 | 
			
		||||
  You may convey verbatim copies of the Program's source code as you
 | 
			
		||||
receive it, in any medium, provided that you conspicuously and
 | 
			
		||||
appropriately publish on each copy an appropriate copyright notice;
 | 
			
		||||
keep intact all notices stating that this License and any
 | 
			
		||||
non-permissive terms added in accord with section 7 apply to the code;
 | 
			
		||||
keep intact all notices of the absence of any warranty; and give all
 | 
			
		||||
recipients a copy of this License along with the Program.
 | 
			
		||||
 | 
			
		||||
  You may charge any price or no price for each copy that you convey,
 | 
			
		||||
and you may offer support or warranty protection for a fee.
 | 
			
		||||
 | 
			
		||||
  5. Conveying Modified Source Versions.
 | 
			
		||||
 | 
			
		||||
  You may convey a work based on the Program, or the modifications to
 | 
			
		||||
produce it from the Program, in the form of source code under the
 | 
			
		||||
terms of section 4, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) The work must carry prominent notices stating that you modified
 | 
			
		||||
    it, and giving a relevant date.
 | 
			
		||||
 | 
			
		||||
    b) The work must carry prominent notices stating that it is
 | 
			
		||||
    released under this License and any conditions added under section
 | 
			
		||||
    7.  This requirement modifies the requirement in section 4 to
 | 
			
		||||
    "keep intact all notices".
 | 
			
		||||
 | 
			
		||||
    c) You must license the entire work, as a whole, under this
 | 
			
		||||
    License to anyone who comes into possession of a copy.  This
 | 
			
		||||
    License will therefore apply, along with any applicable section 7
 | 
			
		||||
    additional terms, to the whole of the work, and all its parts,
 | 
			
		||||
    regardless of how they are packaged.  This License gives no
 | 
			
		||||
    permission to license the work in any other way, but it does not
 | 
			
		||||
    invalidate such permission if you have separately received it.
 | 
			
		||||
 | 
			
		||||
    d) If the work has interactive user interfaces, each must display
 | 
			
		||||
    Appropriate Legal Notices; however, if the Program has interactive
 | 
			
		||||
    interfaces that do not display Appropriate Legal Notices, your
 | 
			
		||||
    work need not make them do so.
 | 
			
		||||
 | 
			
		||||
  A compilation of a covered work with other separate and independent
 | 
			
		||||
works, which are not by their nature extensions of the covered work,
 | 
			
		||||
and which are not combined with it such as to form a larger program,
 | 
			
		||||
in or on a volume of a storage or distribution medium, is called an
 | 
			
		||||
"aggregate" if the compilation and its resulting copyright are not
 | 
			
		||||
used to limit the access or legal rights of the compilation's users
 | 
			
		||||
beyond what the individual works permit.  Inclusion of a covered work
 | 
			
		||||
in an aggregate does not cause this License to apply to the other
 | 
			
		||||
parts of the aggregate.
 | 
			
		||||
 | 
			
		||||
  6. Conveying Non-Source Forms.
 | 
			
		||||
 | 
			
		||||
  You may convey a covered work in object code form under the terms
 | 
			
		||||
of sections 4 and 5, provided that you also convey the
 | 
			
		||||
machine-readable Corresponding Source under the terms of this License,
 | 
			
		||||
in one of these ways:
 | 
			
		||||
 | 
			
		||||
    a) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by the
 | 
			
		||||
    Corresponding Source fixed on a durable physical medium
 | 
			
		||||
    customarily used for software interchange.
 | 
			
		||||
 | 
			
		||||
    b) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by a
 | 
			
		||||
    written offer, valid for at least three years and valid for as
 | 
			
		||||
    long as you offer spare parts or customer support for that product
 | 
			
		||||
    model, to give anyone who possesses the object code either (1) a
 | 
			
		||||
    copy of the Corresponding Source for all the software in the
 | 
			
		||||
    product that is covered by this License, on a durable physical
 | 
			
		||||
    medium customarily used for software interchange, for a price no
 | 
			
		||||
    more than your reasonable cost of physically performing this
 | 
			
		||||
    conveying of source, or (2) access to copy the
 | 
			
		||||
    Corresponding Source from a network server at no charge.
 | 
			
		||||
 | 
			
		||||
    c) Convey individual copies of the object code with a copy of the
 | 
			
		||||
    written offer to provide the Corresponding Source.  This
 | 
			
		||||
    alternative is allowed only occasionally and noncommercially, and
 | 
			
		||||
    only if you received the object code with such an offer, in accord
 | 
			
		||||
    with subsection 6b.
 | 
			
		||||
 | 
			
		||||
    d) Convey the object code by offering access from a designated
 | 
			
		||||
    place (gratis or for a charge), and offer equivalent access to the
 | 
			
		||||
    Corresponding Source in the same way through the same place at no
 | 
			
		||||
    further charge.  You need not require recipients to copy the
 | 
			
		||||
    Corresponding Source along with the object code.  If the place to
 | 
			
		||||
    copy the object code is a network server, the Corresponding Source
 | 
			
		||||
    may be on a different server (operated by you or a third party)
 | 
			
		||||
    that supports equivalent copying facilities, provided you maintain
 | 
			
		||||
    clear directions next to the object code saying where to find the
 | 
			
		||||
    Corresponding Source.  Regardless of what server hosts the
 | 
			
		||||
    Corresponding Source, you remain obligated to ensure that it is
 | 
			
		||||
    available for as long as needed to satisfy these requirements.
 | 
			
		||||
 | 
			
		||||
    e) Convey the object code using peer-to-peer transmission, provided
 | 
			
		||||
    you inform other peers where the object code and Corresponding
 | 
			
		||||
    Source of the work are being offered to the general public at no
 | 
			
		||||
    charge under subsection 6d.
 | 
			
		||||
 | 
			
		||||
  A separable portion of the object code, whose source code is excluded
 | 
			
		||||
from the Corresponding Source as a System Library, need not be
 | 
			
		||||
included in conveying the object code work.
 | 
			
		||||
 | 
			
		||||
  A "User Product" is either (1) a "consumer product", which means any
 | 
			
		||||
tangible personal property which is normally used for personal, family,
 | 
			
		||||
or household purposes, or (2) anything designed or sold for incorporation
 | 
			
		||||
into a dwelling.  In determining whether a product is a consumer product,
 | 
			
		||||
doubtful cases shall be resolved in favor of coverage.  For a particular
 | 
			
		||||
product received by a particular user, "normally used" refers to a
 | 
			
		||||
typical or common use of that class of product, regardless of the status
 | 
			
		||||
of the particular user or of the way in which the particular user
 | 
			
		||||
actually uses, or expects or is expected to use, the product.  A product
 | 
			
		||||
is a consumer product regardless of whether the product has substantial
 | 
			
		||||
commercial, industrial or non-consumer uses, unless such uses represent
 | 
			
		||||
the only significant mode of use of the product.
 | 
			
		||||
 | 
			
		||||
  "Installation Information" for a User Product means any methods,
 | 
			
		||||
procedures, authorization keys, or other information required to install
 | 
			
		||||
and execute modified versions of a covered work in that User Product from
 | 
			
		||||
a modified version of its Corresponding Source.  The information must
 | 
			
		||||
suffice to ensure that the continued functioning of the modified object
 | 
			
		||||
code is in no case prevented or interfered with solely because
 | 
			
		||||
modification has been made.
 | 
			
		||||
 | 
			
		||||
  If you convey an object code work under this section in, or with, or
 | 
			
		||||
specifically for use in, a User Product, and the conveying occurs as
 | 
			
		||||
part of a transaction in which the right of possession and use of the
 | 
			
		||||
User Product is transferred to the recipient in perpetuity or for a
 | 
			
		||||
fixed term (regardless of how the transaction is characterized), the
 | 
			
		||||
Corresponding Source conveyed under this section must be accompanied
 | 
			
		||||
by the Installation Information.  But this requirement does not apply
 | 
			
		||||
if neither you nor any third party retains the ability to install
 | 
			
		||||
modified object code on the User Product (for example, the work has
 | 
			
		||||
been installed in ROM).
 | 
			
		||||
 | 
			
		||||
  The requirement to provide Installation Information does not include a
 | 
			
		||||
requirement to continue to provide support service, warranty, or updates
 | 
			
		||||
for a work that has been modified or installed by the recipient, or for
 | 
			
		||||
the User Product in which it has been modified or installed.  Access to a
 | 
			
		||||
network may be denied when the modification itself materially and
 | 
			
		||||
adversely affects the operation of the network or violates the rules and
 | 
			
		||||
protocols for communication across the network.
 | 
			
		||||
 | 
			
		||||
  Corresponding Source conveyed, and Installation Information provided,
 | 
			
		||||
in accord with this section must be in a format that is publicly
 | 
			
		||||
documented (and with an implementation available to the public in
 | 
			
		||||
source code form), and must require no special password or key for
 | 
			
		||||
unpacking, reading or copying.
 | 
			
		||||
 | 
			
		||||
  7. Additional Terms.
 | 
			
		||||
 | 
			
		||||
  "Additional permissions" are terms that supplement the terms of this
 | 
			
		||||
License by making exceptions from one or more of its conditions.
 | 
			
		||||
Additional permissions that are applicable to the entire Program shall
 | 
			
		||||
be treated as though they were included in this License, to the extent
 | 
			
		||||
that they are valid under applicable law.  If additional permissions
 | 
			
		||||
apply only to part of the Program, that part may be used separately
 | 
			
		||||
under those permissions, but the entire Program remains governed by
 | 
			
		||||
this License without regard to the additional permissions.
 | 
			
		||||
 | 
			
		||||
  When you convey a copy of a covered work, you may at your option
 | 
			
		||||
remove any additional permissions from that copy, or from any part of
 | 
			
		||||
it.  (Additional permissions may be written to require their own
 | 
			
		||||
removal in certain cases when you modify the work.)  You may place
 | 
			
		||||
additional permissions on material, added by you to a covered work,
 | 
			
		||||
for which you have or can give appropriate copyright permission.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, for material you
 | 
			
		||||
add to a covered work, you may (if authorized by the copyright holders of
 | 
			
		||||
that material) supplement the terms of this License with terms:
 | 
			
		||||
 | 
			
		||||
    a) Disclaiming warranty or limiting liability differently from the
 | 
			
		||||
    terms of sections 15 and 16 of this License; or
 | 
			
		||||
 | 
			
		||||
    b) Requiring preservation of specified reasonable legal notices or
 | 
			
		||||
    author attributions in that material or in the Appropriate Legal
 | 
			
		||||
    Notices displayed by works containing it; or
 | 
			
		||||
 | 
			
		||||
    c) Prohibiting misrepresentation of the origin of that material, or
 | 
			
		||||
    requiring that modified versions of such material be marked in
 | 
			
		||||
    reasonable ways as different from the original version; or
 | 
			
		||||
 | 
			
		||||
    d) Limiting the use for publicity purposes of names of licensors or
 | 
			
		||||
    authors of the material; or
 | 
			
		||||
 | 
			
		||||
    e) Declining to grant rights under trademark law for use of some
 | 
			
		||||
    trade names, trademarks, or service marks; or
 | 
			
		||||
 | 
			
		||||
    f) Requiring indemnification of licensors and authors of that
 | 
			
		||||
    material by anyone who conveys the material (or modified versions of
 | 
			
		||||
    it) with contractual assumptions of liability to the recipient, for
 | 
			
		||||
    any liability that these contractual assumptions directly impose on
 | 
			
		||||
    those licensors and authors.
 | 
			
		||||
 | 
			
		||||
  All other non-permissive additional terms are considered "further
 | 
			
		||||
restrictions" within the meaning of section 10.  If the Program as you
 | 
			
		||||
received it, or any part of it, contains a notice stating that it is
 | 
			
		||||
governed by this License along with a term that is a further
 | 
			
		||||
restriction, you may remove that term.  If a license document contains
 | 
			
		||||
a further restriction but permits relicensing or conveying under this
 | 
			
		||||
License, you may add to a covered work material governed by the terms
 | 
			
		||||
of that license document, provided that the further restriction does
 | 
			
		||||
not survive such relicensing or conveying.
 | 
			
		||||
 | 
			
		||||
  If you add terms to a covered work in accord with this section, you
 | 
			
		||||
must place, in the relevant source files, a statement of the
 | 
			
		||||
additional terms that apply to those files, or a notice indicating
 | 
			
		||||
where to find the applicable terms.
 | 
			
		||||
 | 
			
		||||
  Additional terms, permissive or non-permissive, may be stated in the
 | 
			
		||||
form of a separately written license, or stated as exceptions;
 | 
			
		||||
the above requirements apply either way.
 | 
			
		||||
 | 
			
		||||
  8. Termination.
 | 
			
		||||
 | 
			
		||||
  You may not propagate or modify a covered work except as expressly
 | 
			
		||||
provided under this License.  Any attempt otherwise to propagate or
 | 
			
		||||
modify it is void, and will automatically terminate your rights under
 | 
			
		||||
this License (including any patent licenses granted under the third
 | 
			
		||||
paragraph of section 11).
 | 
			
		||||
 | 
			
		||||
  However, if you cease all violation of this License, then your
 | 
			
		||||
license from a particular copyright holder is reinstated (a)
 | 
			
		||||
provisionally, unless and until the copyright holder explicitly and
 | 
			
		||||
finally terminates your license, and (b) permanently, if the copyright
 | 
			
		||||
holder fails to notify you of the violation by some reasonable means
 | 
			
		||||
prior to 60 days after the cessation.
 | 
			
		||||
 | 
			
		||||
  Moreover, your license from a particular copyright holder is
 | 
			
		||||
reinstated permanently if the copyright holder notifies you of the
 | 
			
		||||
violation by some reasonable means, this is the first time you have
 | 
			
		||||
received notice of violation of this License (for any work) from that
 | 
			
		||||
copyright holder, and you cure the violation prior to 30 days after
 | 
			
		||||
your receipt of the notice.
 | 
			
		||||
 | 
			
		||||
  Termination of your rights under this section does not terminate the
 | 
			
		||||
licenses of parties who have received copies or rights from you under
 | 
			
		||||
this License.  If your rights have been terminated and not permanently
 | 
			
		||||
reinstated, you do not qualify to receive new licenses for the same
 | 
			
		||||
material under section 10.
 | 
			
		||||
 | 
			
		||||
  9. Acceptance Not Required for Having Copies.
 | 
			
		||||
 | 
			
		||||
  You are not required to accept this License in order to receive or
 | 
			
		||||
run a copy of the Program.  Ancillary propagation of a covered work
 | 
			
		||||
occurring solely as a consequence of using peer-to-peer transmission
 | 
			
		||||
to receive a copy likewise does not require acceptance.  However,
 | 
			
		||||
nothing other than this License grants you permission to propagate or
 | 
			
		||||
modify any covered work.  These actions infringe copyright if you do
 | 
			
		||||
not accept this License.  Therefore, by modifying or propagating a
 | 
			
		||||
covered work, you indicate your acceptance of this License to do so.
 | 
			
		||||
 | 
			
		||||
  10. Automatic Licensing of Downstream Recipients.
 | 
			
		||||
 | 
			
		||||
  Each time you convey a covered work, the recipient automatically
 | 
			
		||||
receives a license from the original licensors, to run, modify and
 | 
			
		||||
propagate that work, subject to this License.  You are not responsible
 | 
			
		||||
for enforcing compliance by third parties with this License.
 | 
			
		||||
 | 
			
		||||
  An "entity transaction" is a transaction transferring control of an
 | 
			
		||||
organization, or substantially all assets of one, or subdividing an
 | 
			
		||||
organization, or merging organizations.  If propagation of a covered
 | 
			
		||||
work results from an entity transaction, each party to that
 | 
			
		||||
transaction who receives a copy of the work also receives whatever
 | 
			
		||||
licenses to the work the party's predecessor in interest had or could
 | 
			
		||||
give under the previous paragraph, plus a right to possession of the
 | 
			
		||||
Corresponding Source of the work from the predecessor in interest, if
 | 
			
		||||
the predecessor has it or can get it with reasonable efforts.
 | 
			
		||||
 | 
			
		||||
  You may not impose any further restrictions on the exercise of the
 | 
			
		||||
rights granted or affirmed under this License.  For example, you may
 | 
			
		||||
not impose a license fee, royalty, or other charge for exercise of
 | 
			
		||||
rights granted under this License, and you may not initiate litigation
 | 
			
		||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
 | 
			
		||||
any patent claim is infringed by making, using, selling, offering for
 | 
			
		||||
sale, or importing the Program or any portion of it.
 | 
			
		||||
 | 
			
		||||
  11. Patents.
 | 
			
		||||
 | 
			
		||||
  A "contributor" is a copyright holder who authorizes use under this
 | 
			
		||||
License of the Program or a work on which the Program is based.  The
 | 
			
		||||
work thus licensed is called the contributor's "contributor version".
 | 
			
		||||
 | 
			
		||||
  A contributor's "essential patent claims" are all patent claims
 | 
			
		||||
owned or controlled by the contributor, whether already acquired or
 | 
			
		||||
hereafter acquired, that would be infringed by some manner, permitted
 | 
			
		||||
by this License, of making, using, or selling its contributor version,
 | 
			
		||||
but do not include claims that would be infringed only as a
 | 
			
		||||
consequence of further modification of the contributor version.  For
 | 
			
		||||
purposes of this definition, "control" includes the right to grant
 | 
			
		||||
patent sublicenses in a manner consistent with the requirements of
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  Each contributor grants you a non-exclusive, worldwide, royalty-free
 | 
			
		||||
patent license under the contributor's essential patent claims, to
 | 
			
		||||
make, use, sell, offer for sale, import and otherwise run, modify and
 | 
			
		||||
propagate the contents of its contributor version.
 | 
			
		||||
 | 
			
		||||
  In the following three paragraphs, a "patent license" is any express
 | 
			
		||||
agreement or commitment, however denominated, not to enforce a patent
 | 
			
		||||
(such as an express permission to practice a patent or covenant not to
 | 
			
		||||
sue for patent infringement).  To "grant" such a patent license to a
 | 
			
		||||
party means to make such an agreement or commitment not to enforce a
 | 
			
		||||
patent against the party.
 | 
			
		||||
 | 
			
		||||
  If you convey a covered work, knowingly relying on a patent license,
 | 
			
		||||
and the Corresponding Source of the work is not available for anyone
 | 
			
		||||
to copy, free of charge and under the terms of this License, through a
 | 
			
		||||
publicly available network server or other readily accessible means,
 | 
			
		||||
then you must either (1) cause the Corresponding Source to be so
 | 
			
		||||
available, or (2) arrange to deprive yourself of the benefit of the
 | 
			
		||||
patent license for this particular work, or (3) arrange, in a manner
 | 
			
		||||
consistent with the requirements of this License, to extend the patent
 | 
			
		||||
license to downstream recipients.  "Knowingly relying" means you have
 | 
			
		||||
actual knowledge that, but for the patent license, your conveying the
 | 
			
		||||
covered work in a country, or your recipient's use of the covered work
 | 
			
		||||
in a country, would infringe one or more identifiable patents in that
 | 
			
		||||
country that you have reason to believe are valid.
 | 
			
		||||
 | 
			
		||||
  If, pursuant to or in connection with a single transaction or
 | 
			
		||||
arrangement, you convey, or propagate by procuring conveyance of, a
 | 
			
		||||
covered work, and grant a patent license to some of the parties
 | 
			
		||||
receiving the covered work authorizing them to use, propagate, modify
 | 
			
		||||
or convey a specific copy of the covered work, then the patent license
 | 
			
		||||
you grant is automatically extended to all recipients of the covered
 | 
			
		||||
work and works based on it.
 | 
			
		||||
 | 
			
		||||
  A patent license is "discriminatory" if it does not include within
 | 
			
		||||
the scope of its coverage, prohibits the exercise of, or is
 | 
			
		||||
conditioned on the non-exercise of one or more of the rights that are
 | 
			
		||||
specifically granted under this License.  You may not convey a covered
 | 
			
		||||
work if you are a party to an arrangement with a third party that is
 | 
			
		||||
in the business of distributing software, under which you make payment
 | 
			
		||||
to the third party based on the extent of your activity of conveying
 | 
			
		||||
the work, and under which the third party grants, to any of the
 | 
			
		||||
parties who would receive the covered work from you, a discriminatory
 | 
			
		||||
patent license (a) in connection with copies of the covered work
 | 
			
		||||
conveyed by you (or copies made from those copies), or (b) primarily
 | 
			
		||||
for and in connection with specific products or compilations that
 | 
			
		||||
contain the covered work, unless you entered into that arrangement,
 | 
			
		||||
or that patent license was granted, prior to 28 March 2007.
 | 
			
		||||
 | 
			
		||||
  Nothing in this License shall be construed as excluding or limiting
 | 
			
		||||
any implied license or other defenses to infringement that may
 | 
			
		||||
otherwise be available to you under applicable patent law.
 | 
			
		||||
 | 
			
		||||
  12. No Surrender of Others' Freedom.
 | 
			
		||||
 | 
			
		||||
  If conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot convey a
 | 
			
		||||
covered work so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you may
 | 
			
		||||
not convey it at all.  For example, if you agree to terms that obligate you
 | 
			
		||||
to collect a royalty for further conveying from those to whom you convey
 | 
			
		||||
the Program, the only way you could satisfy both those terms and this
 | 
			
		||||
License would be to refrain entirely from conveying the Program.
 | 
			
		||||
 | 
			
		||||
  13. Remote Network Interaction; Use with the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, if you modify the
 | 
			
		||||
Program, your modified version must prominently offer all users
 | 
			
		||||
interacting with it remotely through a computer network (if your version
 | 
			
		||||
supports such interaction) an opportunity to receive the Corresponding
 | 
			
		||||
Source of your version by providing access to the Corresponding Source
 | 
			
		||||
from a network server at no charge, through some standard or customary
 | 
			
		||||
means of facilitating copying of software.  This Corresponding Source
 | 
			
		||||
shall include the Corresponding Source for any work covered by version 3
 | 
			
		||||
of the GNU General Public License that is incorporated pursuant to the
 | 
			
		||||
following paragraph.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, you have
 | 
			
		||||
permission to link or combine any covered work with a work licensed
 | 
			
		||||
under version 3 of the GNU General Public License into a single
 | 
			
		||||
combined work, and to convey the resulting work.  The terms of this
 | 
			
		||||
License will continue to apply to the part which is the covered work,
 | 
			
		||||
but the work with which it is combined will remain governed by version
 | 
			
		||||
3 of the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  14. Revised Versions of this License.
 | 
			
		||||
 | 
			
		||||
  The Free Software Foundation may publish revised and/or new versions of
 | 
			
		||||
the GNU Affero General Public License from time to time.  Such new versions
 | 
			
		||||
will be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
  Each version is given a distinguishing version number.  If the
 | 
			
		||||
Program specifies that a certain numbered version of the GNU Affero General
 | 
			
		||||
Public License "or any later version" applies to it, you have the
 | 
			
		||||
option of following the terms and conditions either of that numbered
 | 
			
		||||
version or of any later version published by the Free Software
 | 
			
		||||
Foundation.  If the Program does not specify a version number of the
 | 
			
		||||
GNU Affero General Public License, you may choose any version ever published
 | 
			
		||||
by the Free Software Foundation.
 | 
			
		||||
 | 
			
		||||
  If the Program specifies that a proxy can decide which future
 | 
			
		||||
versions of the GNU Affero General Public License can be used, that proxy's
 | 
			
		||||
public statement of acceptance of a version permanently authorizes you
 | 
			
		||||
to choose that version for the Program.
 | 
			
		||||
 | 
			
		||||
  Later license versions may give you additional or different
 | 
			
		||||
permissions.  However, no additional obligations are imposed on any
 | 
			
		||||
author or copyright holder as a result of your choosing to follow a
 | 
			
		||||
later version.
 | 
			
		||||
 | 
			
		||||
  15. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 | 
			
		||||
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 | 
			
		||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 | 
			
		||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 | 
			
		||||
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 | 
			
		||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  16. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 | 
			
		||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 | 
			
		||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 | 
			
		||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 | 
			
		||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 | 
			
		||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 | 
			
		||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
  17. Interpretation of Sections 15 and 16.
 | 
			
		||||
 | 
			
		||||
  If the disclaimer of warranty and limitation of liability provided
 | 
			
		||||
above cannot be given local legal effect according to their terms,
 | 
			
		||||
reviewing courts shall apply local law that most closely approximates
 | 
			
		||||
an absolute waiver of all civil liability in connection with the
 | 
			
		||||
Program, unless a warranty or assumption of liability accompanies a
 | 
			
		||||
copy of the Program in return for a fee.
 | 
			
		||||
 | 
			
		||||
                     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
            How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
state the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) <year>  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
  If your software can interact with users remotely through a computer
 | 
			
		||||
network, you should also make sure that it provides a way for users to
 | 
			
		||||
get its source.  For example, if your program is a web application, its
 | 
			
		||||
interface could display a "Source" link that leads users to an archive
 | 
			
		||||
of the code.  There are many ways you could offer source, and different
 | 
			
		||||
solutions will be better for different programs; see section 13 for the
 | 
			
		||||
specific requirements.
 | 
			
		||||
 | 
			
		||||
  You should also get your employer (if you work as a programmer) or school,
 | 
			
		||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
 | 
			
		||||
For more information on this, and how to apply and follow the GNU AGPL, see
 | 
			
		||||
<http://www.gnu.org/licenses/>.
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/mattermost/platform/einterfaces/brand.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/mattermost/platform/einterfaces/brand.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package einterfaces
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
	"mime/multipart"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BrandInterface interface {
 | 
			
		||||
	SaveBrandImage(*multipart.FileHeader) *model.AppError
 | 
			
		||||
	GetBrandImage() ([]byte, *model.AppError)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var theBrandInterface BrandInterface
 | 
			
		||||
 | 
			
		||||
func RegisterBrandInterface(newInterface BrandInterface) {
 | 
			
		||||
	theBrandInterface = newInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetBrandInterface() BrandInterface {
 | 
			
		||||
	return theBrandInterface
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/mattermost/platform/einterfaces/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/mattermost/platform/einterfaces/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package einterfaces
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ComplianceInterface interface {
 | 
			
		||||
	StartComplianceDailyJob()
 | 
			
		||||
	RunComplianceJob(job *model.Compliance) *model.AppError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var theComplianceInterface ComplianceInterface
 | 
			
		||||
 | 
			
		||||
func RegisterComplianceInterface(newInterface ComplianceInterface) {
 | 
			
		||||
	theComplianceInterface = newInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetComplianceInterface() ComplianceInterface {
 | 
			
		||||
	return theComplianceInterface
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/mattermost/platform/einterfaces/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/mattermost/platform/einterfaces/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package einterfaces
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LdapInterface interface {
 | 
			
		||||
	DoLogin(id string, password string) (*model.User, *model.AppError)
 | 
			
		||||
	GetUser(id string) (*model.User, *model.AppError)
 | 
			
		||||
	CheckPassword(id string, password string) *model.AppError
 | 
			
		||||
	SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
 | 
			
		||||
	ValidateFilter(filter string) *model.AppError
 | 
			
		||||
	Syncronize() *model.AppError
 | 
			
		||||
	StartLdapSyncJob()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var theLdapInterface LdapInterface
 | 
			
		||||
 | 
			
		||||
func RegisterLdapInterface(newInterface LdapInterface) {
 | 
			
		||||
	theLdapInterface = newInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetLdapInterface() LdapInterface {
 | 
			
		||||
	return theLdapInterface
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/mfa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/mfa.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package einterfaces
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MfaInterface interface {
 | 
			
		||||
	GenerateQrCode(user *model.User) ([]byte, *model.AppError)
 | 
			
		||||
	Activate(user *model.User, token string) *model.AppError
 | 
			
		||||
	Deactivate(userId string) *model.AppError
 | 
			
		||||
	ValidateToken(secret, token string) (bool, *model.AppError)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var theMfaInterface MfaInterface
 | 
			
		||||
 | 
			
		||||
func RegisterMfaInterface(newInterface MfaInterface) {
 | 
			
		||||
	theMfaInterface = newInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetMfaInterface() MfaInterface {
 | 
			
		||||
	return theMfaInterface
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/mattermost/platform/einterfaces/oauthproviders.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/mattermost/platform/einterfaces/oauthproviders.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package einterfaces
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type OauthProvider interface {
 | 
			
		||||
	GetIdentifier() string
 | 
			
		||||
	GetUserFromJson(data io.Reader) *model.User
 | 
			
		||||
	GetAuthDataFromJson(data io.Reader) string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var oauthProviders = make(map[string]OauthProvider)
 | 
			
		||||
 | 
			
		||||
func RegisterOauthProvider(name string, newProvider OauthProvider) {
 | 
			
		||||
	oauthProviders[name] = newProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetOauthProvider(name string) OauthProvider {
 | 
			
		||||
	provider, ok := oauthProviders[name]
 | 
			
		||||
	if ok {
 | 
			
		||||
		return provider
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										897
									
								
								vendor/github.com/mattermost/platform/model/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										897
									
								
								vendor/github.com/mattermost/platform/model/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,897 @@
 | 
			
		||||
Mattermost Licensing
 | 
			
		||||
 | 
			
		||||
SOFTWARE LICENSING 
 | 
			
		||||
 | 
			
		||||
You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE 
 | 
			
		||||
 | 
			
		||||
-	See MIT-COMPILED-LICENSE.md included in compiled versions for details
 | 
			
		||||
 | 
			
		||||
You may be licensed to use source code to create compiled versions not produced by Mattermost, Inc. in one of two ways:
 | 
			
		||||
 | 
			
		||||
1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or 
 | 
			
		||||
2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com 
 | 
			
		||||
 | 
			
		||||
You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/, 
 | 
			
		||||
webapp/client, webapp/fonts, webapp/i18n, webapp/images and all subdirectories thereof) under the Apache License v2.0.
 | 
			
		||||
 | 
			
		||||
We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not 
 | 
			
		||||
link to the Mattermost Platform directly, but exclusively uses the Mattermost Admin Tools and Configuration Files, and
 | 
			
		||||
(b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of 
 | 
			
		||||
a “modified version” or “work based on” Mattermost as these terms are defined in the AGPL v3.0 license.
 | 
			
		||||
 | 
			
		||||
MATTERMOST TRADEMARK GUIDELINES
 | 
			
		||||
 | 
			
		||||
Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark 
 | 
			
		||||
Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions 
 | 
			
		||||
you have about using these trademarks, please email trademark@mattermost.com 
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
                               
 | 
			
		||||
                               Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
The software is released under the terms of the GNU Affero General Public
 | 
			
		||||
License, version 3.
 | 
			
		||||
 | 
			
		||||
                    GNU AFFERO GENERAL PUBLIC LICENSE
 | 
			
		||||
                       Version 3, 19 November 2007
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
                            Preamble
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is a free, copyleft license for
 | 
			
		||||
software and other kinds of works, specifically designed to ensure
 | 
			
		||||
cooperation with the community in the case of network server software.
 | 
			
		||||
 | 
			
		||||
  The licenses for most software and other practical works are designed
 | 
			
		||||
to take away your freedom to share and change the works.  By contrast,
 | 
			
		||||
our General Public Licenses are intended to guarantee your freedom to
 | 
			
		||||
share and change all versions of a program--to make sure it remains free
 | 
			
		||||
software for all its users.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
them if you wish), that you receive source code or can get it if you
 | 
			
		||||
want it, that you can change the software or use pieces of it in new
 | 
			
		||||
free programs, and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  Developers that use our General Public Licenses protect your rights
 | 
			
		||||
with two steps: (1) assert copyright on the software, and (2) offer
 | 
			
		||||
you this License which gives you legal permission to copy, distribute
 | 
			
		||||
and/or modify the software.
 | 
			
		||||
 | 
			
		||||
  A secondary benefit of defending all users' freedom is that
 | 
			
		||||
improvements made in alternate versions of the program, if they
 | 
			
		||||
receive widespread use, become available for other developers to
 | 
			
		||||
incorporate.  Many developers of free software are heartened and
 | 
			
		||||
encouraged by the resulting cooperation.  However, in the case of
 | 
			
		||||
software used on network servers, this result may fail to come about.
 | 
			
		||||
The GNU General Public License permits making a modified version and
 | 
			
		||||
letting the public access it on a server without ever releasing its
 | 
			
		||||
source code to the public.
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is designed specifically to
 | 
			
		||||
ensure that, in such cases, the modified source code becomes available
 | 
			
		||||
to the community.  It requires the operator of a network server to
 | 
			
		||||
provide the source code of the modified version running there to the
 | 
			
		||||
users of that server.  Therefore, public use of a modified version, on
 | 
			
		||||
a publicly accessible server, gives the public access to the source
 | 
			
		||||
code of the modified version.
 | 
			
		||||
 | 
			
		||||
  An older license, called the Affero General Public License and
 | 
			
		||||
published by Affero, was designed to accomplish similar goals.  This is
 | 
			
		||||
a different license, not a version of the Affero GPL, but Affero has
 | 
			
		||||
released a new version of the Affero GPL which permits relicensing under
 | 
			
		||||
this license.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
                       TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
  0. Definitions.
 | 
			
		||||
 | 
			
		||||
  "This License" refers to version 3 of the GNU Affero General Public License.
 | 
			
		||||
 | 
			
		||||
  "Copyright" also means copyright-like laws that apply to other kinds of
 | 
			
		||||
works, such as semiconductor masks.
 | 
			
		||||
 | 
			
		||||
  "The Program" refers to any copyrightable work licensed under this
 | 
			
		||||
License.  Each licensee is addressed as "you".  "Licensees" and
 | 
			
		||||
"recipients" may be individuals or organizations.
 | 
			
		||||
 | 
			
		||||
  To "modify" a work means to copy from or adapt all or part of the work
 | 
			
		||||
in a fashion requiring copyright permission, other than the making of an
 | 
			
		||||
exact copy.  The resulting work is called a "modified version" of the
 | 
			
		||||
earlier work or a work "based on" the earlier work.
 | 
			
		||||
 | 
			
		||||
  A "covered work" means either the unmodified Program or a work based
 | 
			
		||||
on the Program.
 | 
			
		||||
 | 
			
		||||
  To "propagate" a work means to do anything with it that, without
 | 
			
		||||
permission, would make you directly or secondarily liable for
 | 
			
		||||
infringement under applicable copyright law, except executing it on a
 | 
			
		||||
computer or modifying a private copy.  Propagation includes copying,
 | 
			
		||||
distribution (with or without modification), making available to the
 | 
			
		||||
public, and in some countries other activities as well.
 | 
			
		||||
 | 
			
		||||
  To "convey" a work means any kind of propagation that enables other
 | 
			
		||||
parties to make or receive copies.  Mere interaction with a user through
 | 
			
		||||
a computer network, with no transfer of a copy, is not conveying.
 | 
			
		||||
 | 
			
		||||
  An interactive user interface displays "Appropriate Legal Notices"
 | 
			
		||||
to the extent that it includes a convenient and prominently visible
 | 
			
		||||
feature that (1) displays an appropriate copyright notice, and (2)
 | 
			
		||||
tells the user that there is no warranty for the work (except to the
 | 
			
		||||
extent that warranties are provided), that licensees may convey the
 | 
			
		||||
work under this License, and how to view a copy of this License.  If
 | 
			
		||||
the interface presents a list of user commands or options, such as a
 | 
			
		||||
menu, a prominent item in the list meets this criterion.
 | 
			
		||||
 | 
			
		||||
  1. Source Code.
 | 
			
		||||
 | 
			
		||||
  The "source code" for a work means the preferred form of the work
 | 
			
		||||
for making modifications to it.  "Object code" means any non-source
 | 
			
		||||
form of a work.
 | 
			
		||||
 | 
			
		||||
  A "Standard Interface" means an interface that either is an official
 | 
			
		||||
standard defined by a recognized standards body, or, in the case of
 | 
			
		||||
interfaces specified for a particular programming language, one that
 | 
			
		||||
is widely used among developers working in that language.
 | 
			
		||||
 | 
			
		||||
  The "System Libraries" of an executable work include anything, other
 | 
			
		||||
than the work as a whole, that (a) is included in the normal form of
 | 
			
		||||
packaging a Major Component, but which is not part of that Major
 | 
			
		||||
Component, and (b) serves only to enable use of the work with that
 | 
			
		||||
Major Component, or to implement a Standard Interface for which an
 | 
			
		||||
implementation is available to the public in source code form.  A
 | 
			
		||||
"Major Component", in this context, means a major essential component
 | 
			
		||||
(kernel, window system, and so on) of the specific operating system
 | 
			
		||||
(if any) on which the executable work runs, or a compiler used to
 | 
			
		||||
produce the work, or an object code interpreter used to run it.
 | 
			
		||||
 | 
			
		||||
  The "Corresponding Source" for a work in object code form means all
 | 
			
		||||
the source code needed to generate, install, and (for an executable
 | 
			
		||||
work) run the object code and to modify the work, including scripts to
 | 
			
		||||
control those activities.  However, it does not include the work's
 | 
			
		||||
System Libraries, or general-purpose tools or generally available free
 | 
			
		||||
programs which are used unmodified in performing those activities but
 | 
			
		||||
which are not part of the work.  For example, Corresponding Source
 | 
			
		||||
includes interface definition files associated with source files for
 | 
			
		||||
the work, and the source code for shared libraries and dynamically
 | 
			
		||||
linked subprograms that the work is specifically designed to require,
 | 
			
		||||
such as by intimate data communication or control flow between those
 | 
			
		||||
subprograms and other parts of the work.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source need not include anything that users
 | 
			
		||||
can regenerate automatically from other parts of the Corresponding
 | 
			
		||||
Source.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source for a work in source code form is that
 | 
			
		||||
same work.
 | 
			
		||||
 | 
			
		||||
  2. Basic Permissions.
 | 
			
		||||
 | 
			
		||||
  All rights granted under this License are granted for the term of
 | 
			
		||||
copyright on the Program, and are irrevocable provided the stated
 | 
			
		||||
conditions are met.  This License explicitly affirms your unlimited
 | 
			
		||||
permission to run the unmodified Program.  The output from running a
 | 
			
		||||
covered work is covered by this License only if the output, given its
 | 
			
		||||
content, constitutes a covered work.  This License acknowledges your
 | 
			
		||||
rights of fair use or other equivalent, as provided by copyright law.
 | 
			
		||||
 | 
			
		||||
  You may make, run and propagate covered works that you do not
 | 
			
		||||
convey, without conditions so long as your license otherwise remains
 | 
			
		||||
in force.  You may convey covered works to others for the sole purpose
 | 
			
		||||
of having them make modifications exclusively for you, or provide you
 | 
			
		||||
with facilities for running those works, provided that you comply with
 | 
			
		||||
the terms of this License in conveying all material for which you do
 | 
			
		||||
not control copyright.  Those thus making or running the covered works
 | 
			
		||||
for you must do so exclusively on your behalf, under your direction
 | 
			
		||||
and control, on terms that prohibit them from making any copies of
 | 
			
		||||
your copyrighted material outside their relationship with you.
 | 
			
		||||
 | 
			
		||||
  Conveying under any other circumstances is permitted solely under
 | 
			
		||||
the conditions stated below.  Sublicensing is not allowed; section 10
 | 
			
		||||
makes it unnecessary.
 | 
			
		||||
 | 
			
		||||
  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 | 
			
		||||
 | 
			
		||||
  No covered work shall be deemed part of an effective technological
 | 
			
		||||
measure under any applicable law fulfilling obligations under article
 | 
			
		||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
 | 
			
		||||
similar laws prohibiting or restricting circumvention of such
 | 
			
		||||
measures.
 | 
			
		||||
 | 
			
		||||
  When you convey a covered work, you waive any legal power to forbid
 | 
			
		||||
circumvention of technological measures to the extent such circumvention
 | 
			
		||||
is effected by exercising rights under this License with respect to
 | 
			
		||||
the covered work, and you disclaim any intention to limit operation or
 | 
			
		||||
modification of the work as a means of enforcing, against the work's
 | 
			
		||||
users, your or third parties' legal rights to forbid circumvention of
 | 
			
		||||
technological measures.
 | 
			
		||||
 | 
			
		||||
  4. Conveying Verbatim Copies.
 | 
			
		||||
 | 
			
		||||
  You may convey verbatim copies of the Program's source code as you
 | 
			
		||||
receive it, in any medium, provided that you conspicuously and
 | 
			
		||||
appropriately publish on each copy an appropriate copyright notice;
 | 
			
		||||
keep intact all notices stating that this License and any
 | 
			
		||||
non-permissive terms added in accord with section 7 apply to the code;
 | 
			
		||||
keep intact all notices of the absence of any warranty; and give all
 | 
			
		||||
recipients a copy of this License along with the Program.
 | 
			
		||||
 | 
			
		||||
  You may charge any price or no price for each copy that you convey,
 | 
			
		||||
and you may offer support or warranty protection for a fee.
 | 
			
		||||
 | 
			
		||||
  5. Conveying Modified Source Versions.
 | 
			
		||||
 | 
			
		||||
  You may convey a work based on the Program, or the modifications to
 | 
			
		||||
produce it from the Program, in the form of source code under the
 | 
			
		||||
terms of section 4, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) The work must carry prominent notices stating that you modified
 | 
			
		||||
    it, and giving a relevant date.
 | 
			
		||||
 | 
			
		||||
    b) The work must carry prominent notices stating that it is
 | 
			
		||||
    released under this License and any conditions added under section
 | 
			
		||||
    7.  This requirement modifies the requirement in section 4 to
 | 
			
		||||
    "keep intact all notices".
 | 
			
		||||
 | 
			
		||||
    c) You must license the entire work, as a whole, under this
 | 
			
		||||
    License to anyone who comes into possession of a copy.  This
 | 
			
		||||
    License will therefore apply, along with any applicable section 7
 | 
			
		||||
    additional terms, to the whole of the work, and all its parts,
 | 
			
		||||
    regardless of how they are packaged.  This License gives no
 | 
			
		||||
    permission to license the work in any other way, but it does not
 | 
			
		||||
    invalidate such permission if you have separately received it.
 | 
			
		||||
 | 
			
		||||
    d) If the work has interactive user interfaces, each must display
 | 
			
		||||
    Appropriate Legal Notices; however, if the Program has interactive
 | 
			
		||||
    interfaces that do not display Appropriate Legal Notices, your
 | 
			
		||||
    work need not make them do so.
 | 
			
		||||
 | 
			
		||||
  A compilation of a covered work with other separate and independent
 | 
			
		||||
works, which are not by their nature extensions of the covered work,
 | 
			
		||||
and which are not combined with it such as to form a larger program,
 | 
			
		||||
in or on a volume of a storage or distribution medium, is called an
 | 
			
		||||
"aggregate" if the compilation and its resulting copyright are not
 | 
			
		||||
used to limit the access or legal rights of the compilation's users
 | 
			
		||||
beyond what the individual works permit.  Inclusion of a covered work
 | 
			
		||||
in an aggregate does not cause this License to apply to the other
 | 
			
		||||
parts of the aggregate.
 | 
			
		||||
 | 
			
		||||
  6. Conveying Non-Source Forms.
 | 
			
		||||
 | 
			
		||||
  You may convey a covered work in object code form under the terms
 | 
			
		||||
of sections 4 and 5, provided that you also convey the
 | 
			
		||||
machine-readable Corresponding Source under the terms of this License,
 | 
			
		||||
in one of these ways:
 | 
			
		||||
 | 
			
		||||
    a) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by the
 | 
			
		||||
    Corresponding Source fixed on a durable physical medium
 | 
			
		||||
    customarily used for software interchange.
 | 
			
		||||
 | 
			
		||||
    b) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by a
 | 
			
		||||
    written offer, valid for at least three years and valid for as
 | 
			
		||||
    long as you offer spare parts or customer support for that product
 | 
			
		||||
    model, to give anyone who possesses the object code either (1) a
 | 
			
		||||
    copy of the Corresponding Source for all the software in the
 | 
			
		||||
    product that is covered by this License, on a durable physical
 | 
			
		||||
    medium customarily used for software interchange, for a price no
 | 
			
		||||
    more than your reasonable cost of physically performing this
 | 
			
		||||
    conveying of source, or (2) access to copy the
 | 
			
		||||
    Corresponding Source from a network server at no charge.
 | 
			
		||||
 | 
			
		||||
    c) Convey individual copies of the object code with a copy of the
 | 
			
		||||
    written offer to provide the Corresponding Source.  This
 | 
			
		||||
    alternative is allowed only occasionally and noncommercially, and
 | 
			
		||||
    only if you received the object code with such an offer, in accord
 | 
			
		||||
    with subsection 6b.
 | 
			
		||||
 | 
			
		||||
    d) Convey the object code by offering access from a designated
 | 
			
		||||
    place (gratis or for a charge), and offer equivalent access to the
 | 
			
		||||
    Corresponding Source in the same way through the same place at no
 | 
			
		||||
    further charge.  You need not require recipients to copy the
 | 
			
		||||
    Corresponding Source along with the object code.  If the place to
 | 
			
		||||
    copy the object code is a network server, the Corresponding Source
 | 
			
		||||
    may be on a different server (operated by you or a third party)
 | 
			
		||||
    that supports equivalent copying facilities, provided you maintain
 | 
			
		||||
    clear directions next to the object code saying where to find the
 | 
			
		||||
    Corresponding Source.  Regardless of what server hosts the
 | 
			
		||||
    Corresponding Source, you remain obligated to ensure that it is
 | 
			
		||||
    available for as long as needed to satisfy these requirements.
 | 
			
		||||
 | 
			
		||||
    e) Convey the object code using peer-to-peer transmission, provided
 | 
			
		||||
    you inform other peers where the object code and Corresponding
 | 
			
		||||
    Source of the work are being offered to the general public at no
 | 
			
		||||
    charge under subsection 6d.
 | 
			
		||||
 | 
			
		||||
  A separable portion of the object code, whose source code is excluded
 | 
			
		||||
from the Corresponding Source as a System Library, need not be
 | 
			
		||||
included in conveying the object code work.
 | 
			
		||||
 | 
			
		||||
  A "User Product" is either (1) a "consumer product", which means any
 | 
			
		||||
tangible personal property which is normally used for personal, family,
 | 
			
		||||
or household purposes, or (2) anything designed or sold for incorporation
 | 
			
		||||
into a dwelling.  In determining whether a product is a consumer product,
 | 
			
		||||
doubtful cases shall be resolved in favor of coverage.  For a particular
 | 
			
		||||
product received by a particular user, "normally used" refers to a
 | 
			
		||||
typical or common use of that class of product, regardless of the status
 | 
			
		||||
of the particular user or of the way in which the particular user
 | 
			
		||||
actually uses, or expects or is expected to use, the product.  A product
 | 
			
		||||
is a consumer product regardless of whether the product has substantial
 | 
			
		||||
commercial, industrial or non-consumer uses, unless such uses represent
 | 
			
		||||
the only significant mode of use of the product.
 | 
			
		||||
 | 
			
		||||
  "Installation Information" for a User Product means any methods,
 | 
			
		||||
procedures, authorization keys, or other information required to install
 | 
			
		||||
and execute modified versions of a covered work in that User Product from
 | 
			
		||||
a modified version of its Corresponding Source.  The information must
 | 
			
		||||
suffice to ensure that the continued functioning of the modified object
 | 
			
		||||
code is in no case prevented or interfered with solely because
 | 
			
		||||
modification has been made.
 | 
			
		||||
 | 
			
		||||
  If you convey an object code work under this section in, or with, or
 | 
			
		||||
specifically for use in, a User Product, and the conveying occurs as
 | 
			
		||||
part of a transaction in which the right of possession and use of the
 | 
			
		||||
User Product is transferred to the recipient in perpetuity or for a
 | 
			
		||||
fixed term (regardless of how the transaction is characterized), the
 | 
			
		||||
Corresponding Source conveyed under this section must be accompanied
 | 
			
		||||
by the Installation Information.  But this requirement does not apply
 | 
			
		||||
if neither you nor any third party retains the ability to install
 | 
			
		||||
modified object code on the User Product (for example, the work has
 | 
			
		||||
been installed in ROM).
 | 
			
		||||
 | 
			
		||||
  The requirement to provide Installation Information does not include a
 | 
			
		||||
requirement to continue to provide support service, warranty, or updates
 | 
			
		||||
for a work that has been modified or installed by the recipient, or for
 | 
			
		||||
the User Product in which it has been modified or installed.  Access to a
 | 
			
		||||
network may be denied when the modification itself materially and
 | 
			
		||||
adversely affects the operation of the network or violates the rules and
 | 
			
		||||
protocols for communication across the network.
 | 
			
		||||
 | 
			
		||||
  Corresponding Source conveyed, and Installation Information provided,
 | 
			
		||||
in accord with this section must be in a format that is publicly
 | 
			
		||||
documented (and with an implementation available to the public in
 | 
			
		||||
source code form), and must require no special password or key for
 | 
			
		||||
unpacking, reading or copying.
 | 
			
		||||
 | 
			
		||||
  7. Additional Terms.
 | 
			
		||||
 | 
			
		||||
  "Additional permissions" are terms that supplement the terms of this
 | 
			
		||||
License by making exceptions from one or more of its conditions.
 | 
			
		||||
Additional permissions that are applicable to the entire Program shall
 | 
			
		||||
be treated as though they were included in this License, to the extent
 | 
			
		||||
that they are valid under applicable law.  If additional permissions
 | 
			
		||||
apply only to part of the Program, that part may be used separately
 | 
			
		||||
under those permissions, but the entire Program remains governed by
 | 
			
		||||
this License without regard to the additional permissions.
 | 
			
		||||
 | 
			
		||||
  When you convey a copy of a covered work, you may at your option
 | 
			
		||||
remove any additional permissions from that copy, or from any part of
 | 
			
		||||
it.  (Additional permissions may be written to require their own
 | 
			
		||||
removal in certain cases when you modify the work.)  You may place
 | 
			
		||||
additional permissions on material, added by you to a covered work,
 | 
			
		||||
for which you have or can give appropriate copyright permission.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, for material you
 | 
			
		||||
add to a covered work, you may (if authorized by the copyright holders of
 | 
			
		||||
that material) supplement the terms of this License with terms:
 | 
			
		||||
 | 
			
		||||
    a) Disclaiming warranty or limiting liability differently from the
 | 
			
		||||
    terms of sections 15 and 16 of this License; or
 | 
			
		||||
 | 
			
		||||
    b) Requiring preservation of specified reasonable legal notices or
 | 
			
		||||
    author attributions in that material or in the Appropriate Legal
 | 
			
		||||
    Notices displayed by works containing it; or
 | 
			
		||||
 | 
			
		||||
    c) Prohibiting misrepresentation of the origin of that material, or
 | 
			
		||||
    requiring that modified versions of such material be marked in
 | 
			
		||||
    reasonable ways as different from the original version; or
 | 
			
		||||
 | 
			
		||||
    d) Limiting the use for publicity purposes of names of licensors or
 | 
			
		||||
    authors of the material; or
 | 
			
		||||
 | 
			
		||||
    e) Declining to grant rights under trademark law for use of some
 | 
			
		||||
    trade names, trademarks, or service marks; or
 | 
			
		||||
 | 
			
		||||
    f) Requiring indemnification of licensors and authors of that
 | 
			
		||||
    material by anyone who conveys the material (or modified versions of
 | 
			
		||||
    it) with contractual assumptions of liability to the recipient, for
 | 
			
		||||
    any liability that these contractual assumptions directly impose on
 | 
			
		||||
    those licensors and authors.
 | 
			
		||||
 | 
			
		||||
  All other non-permissive additional terms are considered "further
 | 
			
		||||
restrictions" within the meaning of section 10.  If the Program as you
 | 
			
		||||
received it, or any part of it, contains a notice stating that it is
 | 
			
		||||
governed by this License along with a term that is a further
 | 
			
		||||
restriction, you may remove that term.  If a license document contains
 | 
			
		||||
a further restriction but permits relicensing or conveying under this
 | 
			
		||||
License, you may add to a covered work material governed by the terms
 | 
			
		||||
of that license document, provided that the further restriction does
 | 
			
		||||
not survive such relicensing or conveying.
 | 
			
		||||
 | 
			
		||||
  If you add terms to a covered work in accord with this section, you
 | 
			
		||||
must place, in the relevant source files, a statement of the
 | 
			
		||||
additional terms that apply to those files, or a notice indicating
 | 
			
		||||
where to find the applicable terms.
 | 
			
		||||
 | 
			
		||||
  Additional terms, permissive or non-permissive, may be stated in the
 | 
			
		||||
form of a separately written license, or stated as exceptions;
 | 
			
		||||
the above requirements apply either way.
 | 
			
		||||
 | 
			
		||||
  8. Termination.
 | 
			
		||||
 | 
			
		||||
  You may not propagate or modify a covered work except as expressly
 | 
			
		||||
provided under this License.  Any attempt otherwise to propagate or
 | 
			
		||||
modify it is void, and will automatically terminate your rights under
 | 
			
		||||
this License (including any patent licenses granted under the third
 | 
			
		||||
paragraph of section 11).
 | 
			
		||||
 | 
			
		||||
  However, if you cease all violation of this License, then your
 | 
			
		||||
license from a particular copyright holder is reinstated (a)
 | 
			
		||||
provisionally, unless and until the copyright holder explicitly and
 | 
			
		||||
finally terminates your license, and (b) permanently, if the copyright
 | 
			
		||||
holder fails to notify you of the violation by some reasonable means
 | 
			
		||||
prior to 60 days after the cessation.
 | 
			
		||||
 | 
			
		||||
  Moreover, your license from a particular copyright holder is
 | 
			
		||||
reinstated permanently if the copyright holder notifies you of the
 | 
			
		||||
violation by some reasonable means, this is the first time you have
 | 
			
		||||
received notice of violation of this License (for any work) from that
 | 
			
		||||
copyright holder, and you cure the violation prior to 30 days after
 | 
			
		||||
your receipt of the notice.
 | 
			
		||||
 | 
			
		||||
  Termination of your rights under this section does not terminate the
 | 
			
		||||
licenses of parties who have received copies or rights from you under
 | 
			
		||||
this License.  If your rights have been terminated and not permanently
 | 
			
		||||
reinstated, you do not qualify to receive new licenses for the same
 | 
			
		||||
material under section 10.
 | 
			
		||||
 | 
			
		||||
  9. Acceptance Not Required for Having Copies.
 | 
			
		||||
 | 
			
		||||
  You are not required to accept this License in order to receive or
 | 
			
		||||
run a copy of the Program.  Ancillary propagation of a covered work
 | 
			
		||||
occurring solely as a consequence of using peer-to-peer transmission
 | 
			
		||||
to receive a copy likewise does not require acceptance.  However,
 | 
			
		||||
nothing other than this License grants you permission to propagate or
 | 
			
		||||
modify any covered work.  These actions infringe copyright if you do
 | 
			
		||||
not accept this License.  Therefore, by modifying or propagating a
 | 
			
		||||
covered work, you indicate your acceptance of this License to do so.
 | 
			
		||||
 | 
			
		||||
  10. Automatic Licensing of Downstream Recipients.
 | 
			
		||||
 | 
			
		||||
  Each time you convey a covered work, the recipient automatically
 | 
			
		||||
receives a license from the original licensors, to run, modify and
 | 
			
		||||
propagate that work, subject to this License.  You are not responsible
 | 
			
		||||
for enforcing compliance by third parties with this License.
 | 
			
		||||
 | 
			
		||||
  An "entity transaction" is a transaction transferring control of an
 | 
			
		||||
organization, or substantially all assets of one, or subdividing an
 | 
			
		||||
organization, or merging organizations.  If propagation of a covered
 | 
			
		||||
work results from an entity transaction, each party to that
 | 
			
		||||
transaction who receives a copy of the work also receives whatever
 | 
			
		||||
licenses to the work the party's predecessor in interest had or could
 | 
			
		||||
give under the previous paragraph, plus a right to possession of the
 | 
			
		||||
Corresponding Source of the work from the predecessor in interest, if
 | 
			
		||||
the predecessor has it or can get it with reasonable efforts.
 | 
			
		||||
 | 
			
		||||
  You may not impose any further restrictions on the exercise of the
 | 
			
		||||
rights granted or affirmed under this License.  For example, you may
 | 
			
		||||
not impose a license fee, royalty, or other charge for exercise of
 | 
			
		||||
rights granted under this License, and you may not initiate litigation
 | 
			
		||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
 | 
			
		||||
any patent claim is infringed by making, using, selling, offering for
 | 
			
		||||
sale, or importing the Program or any portion of it.
 | 
			
		||||
 | 
			
		||||
  11. Patents.
 | 
			
		||||
 | 
			
		||||
  A "contributor" is a copyright holder who authorizes use under this
 | 
			
		||||
License of the Program or a work on which the Program is based.  The
 | 
			
		||||
work thus licensed is called the contributor's "contributor version".
 | 
			
		||||
 | 
			
		||||
  A contributor's "essential patent claims" are all patent claims
 | 
			
		||||
owned or controlled by the contributor, whether already acquired or
 | 
			
		||||
hereafter acquired, that would be infringed by some manner, permitted
 | 
			
		||||
by this License, of making, using, or selling its contributor version,
 | 
			
		||||
but do not include claims that would be infringed only as a
 | 
			
		||||
consequence of further modification of the contributor version.  For
 | 
			
		||||
purposes of this definition, "control" includes the right to grant
 | 
			
		||||
patent sublicenses in a manner consistent with the requirements of
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  Each contributor grants you a non-exclusive, worldwide, royalty-free
 | 
			
		||||
patent license under the contributor's essential patent claims, to
 | 
			
		||||
make, use, sell, offer for sale, import and otherwise run, modify and
 | 
			
		||||
propagate the contents of its contributor version.
 | 
			
		||||
 | 
			
		||||
  In the following three paragraphs, a "patent license" is any express
 | 
			
		||||
agreement or commitment, however denominated, not to enforce a patent
 | 
			
		||||
(such as an express permission to practice a patent or covenant not to
 | 
			
		||||
sue for patent infringement).  To "grant" such a patent license to a
 | 
			
		||||
party means to make such an agreement or commitment not to enforce a
 | 
			
		||||
patent against the party.
 | 
			
		||||
 | 
			
		||||
  If you convey a covered work, knowingly relying on a patent license,
 | 
			
		||||
and the Corresponding Source of the work is not available for anyone
 | 
			
		||||
to copy, free of charge and under the terms of this License, through a
 | 
			
		||||
publicly available network server or other readily accessible means,
 | 
			
		||||
then you must either (1) cause the Corresponding Source to be so
 | 
			
		||||
available, or (2) arrange to deprive yourself of the benefit of the
 | 
			
		||||
patent license for this particular work, or (3) arrange, in a manner
 | 
			
		||||
consistent with the requirements of this License, to extend the patent
 | 
			
		||||
license to downstream recipients.  "Knowingly relying" means you have
 | 
			
		||||
actual knowledge that, but for the patent license, your conveying the
 | 
			
		||||
covered work in a country, or your recipient's use of the covered work
 | 
			
		||||
in a country, would infringe one or more identifiable patents in that
 | 
			
		||||
country that you have reason to believe are valid.
 | 
			
		||||
 | 
			
		||||
  If, pursuant to or in connection with a single transaction or
 | 
			
		||||
arrangement, you convey, or propagate by procuring conveyance of, a
 | 
			
		||||
covered work, and grant a patent license to some of the parties
 | 
			
		||||
receiving the covered work authorizing them to use, propagate, modify
 | 
			
		||||
or convey a specific copy of the covered work, then the patent license
 | 
			
		||||
you grant is automatically extended to all recipients of the covered
 | 
			
		||||
work and works based on it.
 | 
			
		||||
 | 
			
		||||
  A patent license is "discriminatory" if it does not include within
 | 
			
		||||
the scope of its coverage, prohibits the exercise of, or is
 | 
			
		||||
conditioned on the non-exercise of one or more of the rights that are
 | 
			
		||||
specifically granted under this License.  You may not convey a covered
 | 
			
		||||
work if you are a party to an arrangement with a third party that is
 | 
			
		||||
in the business of distributing software, under which you make payment
 | 
			
		||||
to the third party based on the extent of your activity of conveying
 | 
			
		||||
the work, and under which the third party grants, to any of the
 | 
			
		||||
parties who would receive the covered work from you, a discriminatory
 | 
			
		||||
patent license (a) in connection with copies of the covered work
 | 
			
		||||
conveyed by you (or copies made from those copies), or (b) primarily
 | 
			
		||||
for and in connection with specific products or compilations that
 | 
			
		||||
contain the covered work, unless you entered into that arrangement,
 | 
			
		||||
or that patent license was granted, prior to 28 March 2007.
 | 
			
		||||
 | 
			
		||||
  Nothing in this License shall be construed as excluding or limiting
 | 
			
		||||
any implied license or other defenses to infringement that may
 | 
			
		||||
otherwise be available to you under applicable patent law.
 | 
			
		||||
 | 
			
		||||
  12. No Surrender of Others' Freedom.
 | 
			
		||||
 | 
			
		||||
  If conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot convey a
 | 
			
		||||
covered work so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you may
 | 
			
		||||
not convey it at all.  For example, if you agree to terms that obligate you
 | 
			
		||||
to collect a royalty for further conveying from those to whom you convey
 | 
			
		||||
the Program, the only way you could satisfy both those terms and this
 | 
			
		||||
License would be to refrain entirely from conveying the Program.
 | 
			
		||||
 | 
			
		||||
  13. Remote Network Interaction; Use with the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, if you modify the
 | 
			
		||||
Program, your modified version must prominently offer all users
 | 
			
		||||
interacting with it remotely through a computer network (if your version
 | 
			
		||||
supports such interaction) an opportunity to receive the Corresponding
 | 
			
		||||
Source of your version by providing access to the Corresponding Source
 | 
			
		||||
from a network server at no charge, through some standard or customary
 | 
			
		||||
means of facilitating copying of software.  This Corresponding Source
 | 
			
		||||
shall include the Corresponding Source for any work covered by version 3
 | 
			
		||||
of the GNU General Public License that is incorporated pursuant to the
 | 
			
		||||
following paragraph.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, you have
 | 
			
		||||
permission to link or combine any covered work with a work licensed
 | 
			
		||||
under version 3 of the GNU General Public License into a single
 | 
			
		||||
combined work, and to convey the resulting work.  The terms of this
 | 
			
		||||
License will continue to apply to the part which is the covered work,
 | 
			
		||||
but the work with which it is combined will remain governed by version
 | 
			
		||||
3 of the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  14. Revised Versions of this License.
 | 
			
		||||
 | 
			
		||||
  The Free Software Foundation may publish revised and/or new versions of
 | 
			
		||||
the GNU Affero General Public License from time to time.  Such new versions
 | 
			
		||||
will be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
  Each version is given a distinguishing version number.  If the
 | 
			
		||||
Program specifies that a certain numbered version of the GNU Affero General
 | 
			
		||||
Public License "or any later version" applies to it, you have the
 | 
			
		||||
option of following the terms and conditions either of that numbered
 | 
			
		||||
version or of any later version published by the Free Software
 | 
			
		||||
Foundation.  If the Program does not specify a version number of the
 | 
			
		||||
GNU Affero General Public License, you may choose any version ever published
 | 
			
		||||
by the Free Software Foundation.
 | 
			
		||||
 | 
			
		||||
  If the Program specifies that a proxy can decide which future
 | 
			
		||||
versions of the GNU Affero General Public License can be used, that proxy's
 | 
			
		||||
public statement of acceptance of a version permanently authorizes you
 | 
			
		||||
to choose that version for the Program.
 | 
			
		||||
 | 
			
		||||
  Later license versions may give you additional or different
 | 
			
		||||
permissions.  However, no additional obligations are imposed on any
 | 
			
		||||
author or copyright holder as a result of your choosing to follow a
 | 
			
		||||
later version.
 | 
			
		||||
 | 
			
		||||
  15. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 | 
			
		||||
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 | 
			
		||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 | 
			
		||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 | 
			
		||||
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 | 
			
		||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  16. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 | 
			
		||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 | 
			
		||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 | 
			
		||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 | 
			
		||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 | 
			
		||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 | 
			
		||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
  17. Interpretation of Sections 15 and 16.
 | 
			
		||||
 | 
			
		||||
  If the disclaimer of warranty and limitation of liability provided
 | 
			
		||||
above cannot be given local legal effect according to their terms,
 | 
			
		||||
reviewing courts shall apply local law that most closely approximates
 | 
			
		||||
an absolute waiver of all civil liability in connection with the
 | 
			
		||||
Program, unless a warranty or assumption of liability accompanies a
 | 
			
		||||
copy of the Program in return for a fee.
 | 
			
		||||
 | 
			
		||||
                     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
            How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
state the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) <year>  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
  If your software can interact with users remotely through a computer
 | 
			
		||||
network, you should also make sure that it provides a way for users to
 | 
			
		||||
get its source.  For example, if your program is a web application, its
 | 
			
		||||
interface could display a "Source" link that leads users to an archive
 | 
			
		||||
of the code.  There are many ways you could offer source, and different
 | 
			
		||||
solutions will be better for different programs; see section 13 for the
 | 
			
		||||
specific requirements.
 | 
			
		||||
 | 
			
		||||
  You should also get your employer (if you work as a programmer) or school,
 | 
			
		||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
 | 
			
		||||
For more information on this, and how to apply and follow the GNU AGPL, see
 | 
			
		||||
<http://www.gnu.org/licenses/>.
 | 
			
		||||
							
								
								
									
										93
									
								
								vendor/github.com/mattermost/platform/model/access.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								vendor/github.com/mattermost/platform/model/access.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ACCESS_TOKEN_GRANT_TYPE  = "authorization_code"
 | 
			
		||||
	ACCESS_TOKEN_TYPE        = "bearer"
 | 
			
		||||
	REFRESH_TOKEN_GRANT_TYPE = "refresh_token"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AccessData struct {
 | 
			
		||||
	AuthCode     string `json:"auth_code"`
 | 
			
		||||
	Token        string `json:"token"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token"`
 | 
			
		||||
	RedirectUri  string `json:"redirect_uri"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AccessResponse struct {
 | 
			
		||||
	AccessToken  string `json:"access_token"`
 | 
			
		||||
	TokenType    string `json:"token_type"`
 | 
			
		||||
	ExpiresIn    int32  `json:"expires_in"`
 | 
			
		||||
	Scope        string `json:"scope"`
 | 
			
		||||
	RefreshToken string `json:"refresh_token"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsValid validates the AccessData and returns an error if it isn't configured
 | 
			
		||||
// correctly.
 | 
			
		||||
func (ad *AccessData) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(ad.AuthCode) == 0 || len(ad.AuthCode) > 128 {
 | 
			
		||||
		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.auth_code.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.Token) != 26 {
 | 
			
		||||
		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.access_token.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.RefreshToken) > 26 {
 | 
			
		||||
		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.RedirectUri) > 256 {
 | 
			
		||||
		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ad *AccessData) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(ad)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AccessDataFromJson(data io.Reader) *AccessData {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var ad AccessData
 | 
			
		||||
	err := decoder.Decode(&ad)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &ad
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ar *AccessResponse) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(ar)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AccessResponseFromJson(data io.Reader) *AccessResponse {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var ar AccessResponse
 | 
			
		||||
	err := decoder.Decode(&ar)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &ar
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								vendor/github.com/mattermost/platform/model/analytics_row.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/mattermost/platform/model/analytics_row.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AnalyticsRow struct {
 | 
			
		||||
	Name  string  `json:"name"`
 | 
			
		||||
	Value float64 `json:"value"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AnalyticsRows []*AnalyticsRow
 | 
			
		||||
 | 
			
		||||
func (me *AnalyticsRow) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(me)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AnalyticsRowFromJson(data io.Reader) *AnalyticsRow {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var me AnalyticsRow
 | 
			
		||||
	err := decoder.Decode(&me)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &me
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me AnalyticsRows) ToJson() string {
 | 
			
		||||
	if b, err := json.Marshal(me); err != nil {
 | 
			
		||||
		return "[]"
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AnalyticsRowsFromJson(data io.Reader) AnalyticsRows {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var me AnalyticsRows
 | 
			
		||||
	err := decoder.Decode(&me)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return me
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/mattermost/platform/model/audit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/mattermost/platform/model/audit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Audit struct {
 | 
			
		||||
	Id        string `json:"id"`
 | 
			
		||||
	CreateAt  int64  `json:"create_at"`
 | 
			
		||||
	UserId    string `json:"user_id"`
 | 
			
		||||
	Action    string `json:"action"`
 | 
			
		||||
	ExtraInfo string `json:"extra_info"`
 | 
			
		||||
	IpAddress string `json:"ip_address"`
 | 
			
		||||
	SessionId string `json:"session_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Audit) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuditFromJson(data io.Reader) *Audit {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Audit
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/mattermost/platform/model/audits.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/mattermost/platform/model/audits.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Audits []Audit
 | 
			
		||||
 | 
			
		||||
func (o Audits) Etag() string {
 | 
			
		||||
	if len(o) > 0 {
 | 
			
		||||
		// the first in the list is always the most current
 | 
			
		||||
		return Etag(o[0].CreateAt)
 | 
			
		||||
	} else {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o Audits) ToJson() string {
 | 
			
		||||
	if b, err := json.Marshal(o); err != nil {
 | 
			
		||||
		return "[]"
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuditsFromJson(data io.Reader) Audits {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Audits
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								vendor/github.com/mattermost/platform/model/authorize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/mattermost/platform/model/authorize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	AUTHCODE_EXPIRE_TIME   = 60 * 10 // 10 minutes
 | 
			
		||||
	AUTHCODE_RESPONSE_TYPE = "code"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthData struct {
 | 
			
		||||
	ClientId    string `json:"client_id"`
 | 
			
		||||
	UserId      string `json:"user_id"`
 | 
			
		||||
	Code        string `json:"code"`
 | 
			
		||||
	ExpiresIn   int32  `json:"expires_in"`
 | 
			
		||||
	CreateAt    int64  `json:"create_at"`
 | 
			
		||||
	RedirectUri string `json:"redirect_uri"`
 | 
			
		||||
	State       string `json:"state"`
 | 
			
		||||
	Scope       string `json:"scope"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsValid validates the AuthData and returns an error if it isn't configured
 | 
			
		||||
// correctly.
 | 
			
		||||
func (ad *AuthData) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(ad.ClientId) != 26 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.UserId) != 26 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.Code) == 0 || len(ad.Code) > 128 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ad.ExpiresIn == 0 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.expires.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ad.CreateAt <= 0 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.RedirectUri) > 256 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.State) > 128 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ad.ClientId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ad.Scope) > 128 {
 | 
			
		||||
		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ad.ClientId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ad *AuthData) PreSave() {
 | 
			
		||||
	if ad.ExpiresIn == 0 {
 | 
			
		||||
		ad.ExpiresIn = AUTHCODE_EXPIRE_TIME
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ad.CreateAt == 0 {
 | 
			
		||||
		ad.CreateAt = GetMillis()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ad *AuthData) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(ad)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuthDataFromJson(data io.Reader) *AuthData {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var ad AuthData
 | 
			
		||||
	err := decoder.Decode(&ad)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &ad
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ad *AuthData) IsExpired() bool {
 | 
			
		||||
 | 
			
		||||
	if GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								vendor/github.com/mattermost/platform/model/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								vendor/github.com/mattermost/platform/model/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CHANNEL_OPEN    = "O"
 | 
			
		||||
	CHANNEL_PRIVATE = "P"
 | 
			
		||||
	CHANNEL_DIRECT  = "D"
 | 
			
		||||
	DEFAULT_CHANNEL = "town-square"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Channel struct {
 | 
			
		||||
	Id            string `json:"id"`
 | 
			
		||||
	CreateAt      int64  `json:"create_at"`
 | 
			
		||||
	UpdateAt      int64  `json:"update_at"`
 | 
			
		||||
	DeleteAt      int64  `json:"delete_at"`
 | 
			
		||||
	TeamId        string `json:"team_id"`
 | 
			
		||||
	Type          string `json:"type"`
 | 
			
		||||
	DisplayName   string `json:"display_name"`
 | 
			
		||||
	Name          string `json:"name"`
 | 
			
		||||
	Header        string `json:"header"`
 | 
			
		||||
	Purpose       string `json:"purpose"`
 | 
			
		||||
	LastPostAt    int64  `json:"last_post_at"`
 | 
			
		||||
	TotalMsgCount int64  `json:"total_msg_count"`
 | 
			
		||||
	ExtraUpdateAt int64  `json:"extra_update_at"`
 | 
			
		||||
	CreatorId     string `json:"creator_id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelFromJson(data io.Reader) *Channel {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Channel
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) Etag() string {
 | 
			
		||||
	return Etag(o.Id, o.UpdateAt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) ExtraEtag(memberLimit int) string {
 | 
			
		||||
	return Etag(o.Id, o.ExtraUpdateAt, memberLimit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(o.Id) != 26 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.CreateAt == 0 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.UpdateAt == 0 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if utf8.RuneCountInString(o.DisplayName) > 64 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.Name) > 64 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsValidChannelIdentifier(o.Name) {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT) {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if utf8.RuneCountInString(o.Header) > 1024 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if utf8.RuneCountInString(o.Purpose) > 128 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.CreatorId) > 26 {
 | 
			
		||||
		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) PreSave() {
 | 
			
		||||
	if o.Id == "" {
 | 
			
		||||
		o.Id = NewId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.CreateAt = GetMillis()
 | 
			
		||||
	o.UpdateAt = o.CreateAt
 | 
			
		||||
	o.ExtraUpdateAt = o.CreateAt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) PreUpdate() {
 | 
			
		||||
	o.UpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) ExtraUpdated() {
 | 
			
		||||
	o.ExtraUpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Channel) PreExport() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDMNameFromIds(userId1, userId2 string) string {
 | 
			
		||||
	if userId1 > userId2 {
 | 
			
		||||
		return userId2 + "__" + userId1
 | 
			
		||||
	} else {
 | 
			
		||||
		return userId1 + "__" + userId2
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								vendor/github.com/mattermost/platform/model/channel_count.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/mattermost/platform/model/channel_count.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChannelCounts struct {
 | 
			
		||||
	Counts      map[string]int64 `json:"counts"`
 | 
			
		||||
	UpdateTimes map[string]int64 `json:"update_times"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelCounts) Etag() string {
 | 
			
		||||
 | 
			
		||||
	ids := []string{}
 | 
			
		||||
	for id := range o.Counts {
 | 
			
		||||
		ids = append(ids, id)
 | 
			
		||||
	}
 | 
			
		||||
	sort.Strings(ids)
 | 
			
		||||
 | 
			
		||||
	str := ""
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		str += id + strconv.FormatInt(o.Counts[id], 10)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	md5Counts := fmt.Sprintf("%x", md5.Sum([]byte(str)))
 | 
			
		||||
 | 
			
		||||
	var update int64 = 0
 | 
			
		||||
	for _, u := range o.UpdateTimes {
 | 
			
		||||
		if u > update {
 | 
			
		||||
			update = u
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Etag(md5Counts, update)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelCounts) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelCountsFromJson(data io.Reader) *ChannelCounts {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o ChannelCounts
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/mattermost/platform/model/channel_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/mattermost/platform/model/channel_data.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChannelData struct {
 | 
			
		||||
	Channel *Channel       `json:"channel"`
 | 
			
		||||
	Member  *ChannelMember `json:"member"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelData) Etag() string {
 | 
			
		||||
	var mt int64 = 0
 | 
			
		||||
	if o.Member != nil {
 | 
			
		||||
		mt = o.Member.LastUpdateAt
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Etag(o.Channel.Id, o.Channel.UpdateAt, o.Channel.LastPostAt, mt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelData) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelDataFromJson(data io.Reader) *ChannelData {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o ChannelData
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/mattermost/platform/model/channel_extra.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/mattermost/platform/model/channel_extra.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ExtraMember struct {
 | 
			
		||||
	Id       string `json:"id"`
 | 
			
		||||
	Nickname string `json:"nickname"`
 | 
			
		||||
	Email    string `json:"email"`
 | 
			
		||||
	Roles    string `json:"roles"`
 | 
			
		||||
	Username string `json:"username"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ExtraMember) Sanitize(options map[string]bool) {
 | 
			
		||||
	if len(options) == 0 || !options["email"] {
 | 
			
		||||
		o.Email = ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChannelExtra struct {
 | 
			
		||||
	Id          string        `json:"id"`
 | 
			
		||||
	Members     []ExtraMember `json:"members"`
 | 
			
		||||
	MemberCount int64         `json:"member_count"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelExtra) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelExtraFromJson(data io.Reader) *ChannelExtra {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o ChannelExtra
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								vendor/github.com/mattermost/platform/model/channel_list.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/mattermost/platform/model/channel_list.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChannelList struct {
 | 
			
		||||
	Channels []*Channel                `json:"channels"`
 | 
			
		||||
	Members  map[string]*ChannelMember `json:"members"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelList) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelList) Etag() string {
 | 
			
		||||
 | 
			
		||||
	id := "0"
 | 
			
		||||
	var t int64 = 0
 | 
			
		||||
	var delta int64 = 0
 | 
			
		||||
 | 
			
		||||
	for _, v := range o.Channels {
 | 
			
		||||
		if v.LastPostAt > t {
 | 
			
		||||
			t = v.LastPostAt
 | 
			
		||||
			id = v.Id
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if v.UpdateAt > t {
 | 
			
		||||
			t = v.UpdateAt
 | 
			
		||||
			id = v.Id
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		member := o.Members[v.Id]
 | 
			
		||||
 | 
			
		||||
		if member != nil {
 | 
			
		||||
			max := v.LastPostAt
 | 
			
		||||
			if v.UpdateAt > max {
 | 
			
		||||
				max = v.UpdateAt
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			delta += max - member.LastViewedAt
 | 
			
		||||
 | 
			
		||||
			if member.LastViewedAt > t {
 | 
			
		||||
				t = member.LastViewedAt
 | 
			
		||||
				id = v.Id
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if member.LastUpdateAt > t {
 | 
			
		||||
				t = member.LastUpdateAt
 | 
			
		||||
				id = v.Id
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Etag(id, t, delta, len(o.Channels))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelListFromJson(data io.Reader) *ChannelList {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o ChannelList
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								vendor/github.com/mattermost/platform/model/channel_member.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								vendor/github.com/mattermost/platform/model/channel_member.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CHANNEL_ROLE_ADMIN          = "admin"
 | 
			
		||||
	CHANNEL_NOTIFY_DEFAULT      = "default"
 | 
			
		||||
	CHANNEL_NOTIFY_ALL          = "all"
 | 
			
		||||
	CHANNEL_NOTIFY_MENTION      = "mention"
 | 
			
		||||
	CHANNEL_NOTIFY_NONE         = "none"
 | 
			
		||||
	CHANNEL_MARK_UNREAD_ALL     = "all"
 | 
			
		||||
	CHANNEL_MARK_UNREAD_MENTION = "mention"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ChannelMember struct {
 | 
			
		||||
	ChannelId    string    `json:"channel_id"`
 | 
			
		||||
	UserId       string    `json:"user_id"`
 | 
			
		||||
	Roles        string    `json:"roles"`
 | 
			
		||||
	LastViewedAt int64     `json:"last_viewed_at"`
 | 
			
		||||
	MsgCount     int64     `json:"msg_count"`
 | 
			
		||||
	MentionCount int64     `json:"mention_count"`
 | 
			
		||||
	NotifyProps  StringMap `json:"notify_props"`
 | 
			
		||||
	LastUpdateAt int64     `json:"last_update_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelMember) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ChannelMemberFromJson(data io.Reader) *ChannelMember {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o ChannelMember
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelMember) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(o.ChannelId) != 26 {
 | 
			
		||||
		return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.UserId) != 26 {
 | 
			
		||||
		return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, role := range strings.Split(o.Roles, " ") {
 | 
			
		||||
		if !(role == "" || role == CHANNEL_ROLE_ADMIN) {
 | 
			
		||||
			return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.role.app_error", nil, "role="+role)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	notifyLevel := o.NotifyProps["desktop"]
 | 
			
		||||
	if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
 | 
			
		||||
		return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
 | 
			
		||||
			nil, "notify_level="+notifyLevel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	markUnreadLevel := o.NotifyProps["mark_unread"]
 | 
			
		||||
	if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) {
 | 
			
		||||
		return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error",
 | 
			
		||||
			nil, "mark_unread_level="+markUnreadLevel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelMember) PreSave() {
 | 
			
		||||
	o.LastUpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *ChannelMember) PreUpdate() {
 | 
			
		||||
	o.LastUpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsChannelNotifyLevelValid(notifyLevel string) bool {
 | 
			
		||||
	return notifyLevel == CHANNEL_NOTIFY_DEFAULT ||
 | 
			
		||||
		notifyLevel == CHANNEL_NOTIFY_ALL ||
 | 
			
		||||
		notifyLevel == CHANNEL_NOTIFY_MENTION ||
 | 
			
		||||
		notifyLevel == CHANNEL_NOTIFY_NONE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsChannelMarkUnreadLevelValid(markUnreadLevel string) bool {
 | 
			
		||||
	return markUnreadLevel == CHANNEL_MARK_UNREAD_ALL || markUnreadLevel == CHANNEL_MARK_UNREAD_MENTION
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetDefaultChannelNotifyProps() StringMap {
 | 
			
		||||
	return StringMap{
 | 
			
		||||
		"desktop":     CHANNEL_NOTIFY_DEFAULT,
 | 
			
		||||
		"mark_unread": CHANNEL_MARK_UNREAD_ALL,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1511
									
								
								vendor/github.com/mattermost/platform/model/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1511
									
								
								vendor/github.com/mattermost/platform/model/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										156
									
								
								vendor/github.com/mattermost/platform/model/command.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								vendor/github.com/mattermost/platform/model/command.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	COMMAND_METHOD_POST = "P"
 | 
			
		||||
	COMMAND_METHOD_GET  = "G"
 | 
			
		||||
	MIN_TRIGGER_LENGTH  = 1
 | 
			
		||||
	MAX_TRIGGER_LENGTH  = 128
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Command struct {
 | 
			
		||||
	Id               string `json:"id"`
 | 
			
		||||
	Token            string `json:"token"`
 | 
			
		||||
	CreateAt         int64  `json:"create_at"`
 | 
			
		||||
	UpdateAt         int64  `json:"update_at"`
 | 
			
		||||
	DeleteAt         int64  `json:"delete_at"`
 | 
			
		||||
	CreatorId        string `json:"creator_id"`
 | 
			
		||||
	TeamId           string `json:"team_id"`
 | 
			
		||||
	Trigger          string `json:"trigger"`
 | 
			
		||||
	Method           string `json:"method"`
 | 
			
		||||
	Username         string `json:"username"`
 | 
			
		||||
	IconURL          string `json:"icon_url"`
 | 
			
		||||
	AutoComplete     bool   `json:"auto_complete"`
 | 
			
		||||
	AutoCompleteDesc string `json:"auto_complete_desc"`
 | 
			
		||||
	AutoCompleteHint string `json:"auto_complete_hint"`
 | 
			
		||||
	DisplayName      string `json:"display_name"`
 | 
			
		||||
	Description      string `json:"description"`
 | 
			
		||||
	URL              string `json:"url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Command) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CommandFromJson(data io.Reader) *Command {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Command
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CommandListToJson(l []*Command) string {
 | 
			
		||||
	b, err := json.Marshal(l)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CommandListFromJson(data io.Reader) []*Command {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o []*Command
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Command) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(o.Id) != 26 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.Token) != 26 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.CreateAt == 0 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.UpdateAt == 0 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.CreatorId) != 26 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.TeamId) != 26 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.Trigger) < MIN_TRIGGER_LENGTH || len(o.Trigger) > MAX_TRIGGER_LENGTH || strings.Index(o.Trigger, "/") == 0 || strings.Contains(o.Trigger, " ") {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.URL) == 0 || len(o.URL) > 1024 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsValidHttpUrl(o.URL) {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(o.Method == COMMAND_METHOD_GET || o.Method == COMMAND_METHOD_POST) {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.DisplayName) > 64 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.display_name.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.Description) > 128 {
 | 
			
		||||
		return NewLocAppError("Command.IsValid", "model.command.is_valid.description.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Command) PreSave() {
 | 
			
		||||
	if o.Id == "" {
 | 
			
		||||
		o.Id = NewId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.Token == "" {
 | 
			
		||||
		o.Token = NewId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.CreateAt = GetMillis()
 | 
			
		||||
	o.UpdateAt = o.CreateAt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Command) PreUpdate() {
 | 
			
		||||
	o.UpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Command) Sanitize() {
 | 
			
		||||
	o.Token = ""
 | 
			
		||||
	o.CreatorId = ""
 | 
			
		||||
	o.Method = ""
 | 
			
		||||
	o.URL = ""
 | 
			
		||||
	o.Username = ""
 | 
			
		||||
	o.IconURL = ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								vendor/github.com/mattermost/platform/model/command_response.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/mattermost/platform/model/command_response.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	COMMAND_RESPONSE_TYPE_IN_CHANNEL = "in_channel"
 | 
			
		||||
	COMMAND_RESPONSE_TYPE_EPHEMERAL  = "ephemeral"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CommandResponse struct {
 | 
			
		||||
	ResponseType string      `json:"response_type"`
 | 
			
		||||
	Text         string      `json:"text"`
 | 
			
		||||
	GotoLocation string      `json:"goto_location"`
 | 
			
		||||
	Attachments  interface{} `json:"attachments"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *CommandResponse) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CommandResponseFromJson(data io.Reader) *CommandResponse {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o CommandResponse
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								vendor/github.com/mattermost/platform/model/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/mattermost/platform/model/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	COMPLIANCE_STATUS_CREATED  = "created"
 | 
			
		||||
	COMPLIANCE_STATUS_RUNNING  = "running"
 | 
			
		||||
	COMPLIANCE_STATUS_FINISHED = "finished"
 | 
			
		||||
	COMPLIANCE_STATUS_FAILED   = "failed"
 | 
			
		||||
	COMPLIANCE_STATUS_REMOVED  = "removed"
 | 
			
		||||
 | 
			
		||||
	COMPLIANCE_TYPE_DAILY = "daily"
 | 
			
		||||
	COMPLIANCE_TYPE_ADHOC = "adhoc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Compliance struct {
 | 
			
		||||
	Id       string `json:"id"`
 | 
			
		||||
	CreateAt int64  `json:"create_at"`
 | 
			
		||||
	UserId   string `json:"user_id"`
 | 
			
		||||
	Status   string `json:"status"`
 | 
			
		||||
	Count    int    `json:"count"`
 | 
			
		||||
	Desc     string `json:"desc"`
 | 
			
		||||
	Type     string `json:"type"`
 | 
			
		||||
	StartAt  int64  `json:"start_at"`
 | 
			
		||||
	EndAt    int64  `json:"end_at"`
 | 
			
		||||
	Keywords string `json:"keywords"`
 | 
			
		||||
	Emails   string `json:"emails"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Compliances []Compliance
 | 
			
		||||
 | 
			
		||||
func (o *Compliance) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me *Compliance) PreSave() {
 | 
			
		||||
	if me.Id == "" {
 | 
			
		||||
		me.Id = NewId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if me.Status == "" {
 | 
			
		||||
		me.Status = COMPLIANCE_STATUS_CREATED
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	me.Count = 0
 | 
			
		||||
	me.Emails = strings.ToLower(me.Emails)
 | 
			
		||||
	me.Keywords = strings.ToLower(me.Keywords)
 | 
			
		||||
 | 
			
		||||
	me.CreateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me *Compliance) JobName() string {
 | 
			
		||||
	jobName := me.Type
 | 
			
		||||
	if me.Type == COMPLIANCE_TYPE_DAILY {
 | 
			
		||||
		jobName += "-" + me.Desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jobName += "-" + me.Id
 | 
			
		||||
 | 
			
		||||
	return jobName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me *Compliance) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(me.Id) != 26 {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if me.CreateAt == 0 {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(me.Desc) > 512 || len(me.Desc) == 0 {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if me.StartAt == 0 {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if me.EndAt == 0 {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if me.EndAt <= me.StartAt {
 | 
			
		||||
		return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ComplianceFromJson(data io.Reader) *Compliance {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Compliance
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o Compliances) ToJson() string {
 | 
			
		||||
	if b, err := json.Marshal(o); err != nil {
 | 
			
		||||
		return "[]"
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CompliancesFromJson(data io.Reader) Compliances {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Compliances
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								vendor/github.com/mattermost/platform/model/compliance_post.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/github.com/mattermost/platform/model/compliance_post.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CompliancePost struct {
 | 
			
		||||
 | 
			
		||||
	// From Team
 | 
			
		||||
	TeamName        string
 | 
			
		||||
	TeamDisplayName string
 | 
			
		||||
 | 
			
		||||
	// From Channel
 | 
			
		||||
	ChannelName        string
 | 
			
		||||
	ChannelDisplayName string
 | 
			
		||||
 | 
			
		||||
	// From User
 | 
			
		||||
	UserUsername string
 | 
			
		||||
	UserEmail    string
 | 
			
		||||
	UserNickname string
 | 
			
		||||
 | 
			
		||||
	// From Post
 | 
			
		||||
	PostId         string
 | 
			
		||||
	PostCreateAt   int64
 | 
			
		||||
	PostUpdateAt   int64
 | 
			
		||||
	PostDeleteAt   int64
 | 
			
		||||
	PostRootId     string
 | 
			
		||||
	PostParentId   string
 | 
			
		||||
	PostOriginalId string
 | 
			
		||||
	PostMessage    string
 | 
			
		||||
	PostType       string
 | 
			
		||||
	PostProps      string
 | 
			
		||||
	PostHashtags   string
 | 
			
		||||
	PostFilenames  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CompliancePostHeader() []string {
 | 
			
		||||
	return []string{
 | 
			
		||||
		"TeamName",
 | 
			
		||||
		"TeamDisplayName",
 | 
			
		||||
 | 
			
		||||
		"ChannelName",
 | 
			
		||||
		"ChannelDisplayName",
 | 
			
		||||
 | 
			
		||||
		"UserUsername",
 | 
			
		||||
		"UserEmail",
 | 
			
		||||
		"UserNickname",
 | 
			
		||||
 | 
			
		||||
		"PostId",
 | 
			
		||||
		"PostCreateAt",
 | 
			
		||||
		"PostUpdateAt",
 | 
			
		||||
		"PostDeleteAt",
 | 
			
		||||
		"PostRootId",
 | 
			
		||||
		"PostParentId",
 | 
			
		||||
		"PostOriginalId",
 | 
			
		||||
		"PostMessage",
 | 
			
		||||
		"PostType",
 | 
			
		||||
		"PostProps",
 | 
			
		||||
		"PostHashtags",
 | 
			
		||||
		"PostFilenames",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me *CompliancePost) Row() []string {
 | 
			
		||||
 | 
			
		||||
	postDeleteAt := ""
 | 
			
		||||
	if me.PostDeleteAt > 0 {
 | 
			
		||||
		postDeleteAt = time.Unix(0, me.PostDeleteAt*int64(1000*1000)).Format(time.RFC3339)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	postUpdateAt := ""
 | 
			
		||||
	if me.PostUpdateAt != me.PostCreateAt {
 | 
			
		||||
		postUpdateAt = time.Unix(0, me.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return []string{
 | 
			
		||||
		me.TeamName,
 | 
			
		||||
		me.TeamDisplayName,
 | 
			
		||||
 | 
			
		||||
		me.ChannelName,
 | 
			
		||||
		me.ChannelDisplayName,
 | 
			
		||||
 | 
			
		||||
		me.UserUsername,
 | 
			
		||||
		me.UserEmail,
 | 
			
		||||
		me.UserNickname,
 | 
			
		||||
 | 
			
		||||
		me.PostId,
 | 
			
		||||
		time.Unix(0, me.PostCreateAt*int64(1000*1000)).Format(time.RFC3339),
 | 
			
		||||
		postUpdateAt,
 | 
			
		||||
		postDeleteAt,
 | 
			
		||||
 | 
			
		||||
		me.PostRootId,
 | 
			
		||||
		me.PostParentId,
 | 
			
		||||
		me.PostOriginalId,
 | 
			
		||||
		me.PostMessage,
 | 
			
		||||
		me.PostType,
 | 
			
		||||
		me.PostProps,
 | 
			
		||||
		me.PostHashtags,
 | 
			
		||||
		me.PostFilenames,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										737
									
								
								vendor/github.com/mattermost/platform/model/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										737
									
								
								vendor/github.com/mattermost/platform/model/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,737 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CONN_SECURITY_NONE     = ""
 | 
			
		||||
	CONN_SECURITY_TLS      = "TLS"
 | 
			
		||||
	CONN_SECURITY_STARTTLS = "STARTTLS"
 | 
			
		||||
 | 
			
		||||
	IMAGE_DRIVER_LOCAL = "local"
 | 
			
		||||
	IMAGE_DRIVER_S3    = "amazons3"
 | 
			
		||||
 | 
			
		||||
	DATABASE_DRIVER_MYSQL    = "mysql"
 | 
			
		||||
	DATABASE_DRIVER_POSTGRES = "postgres"
 | 
			
		||||
 | 
			
		||||
	SERVICE_GITLAB = "gitlab"
 | 
			
		||||
	SERVICE_GOOGLE = "google"
 | 
			
		||||
 | 
			
		||||
	WEBSERVER_MODE_REGULAR  = "regular"
 | 
			
		||||
	WEBSERVER_MODE_GZIP     = "gzip"
 | 
			
		||||
	WEBSERVER_MODE_DISABLED = "disabled"
 | 
			
		||||
 | 
			
		||||
	GENERIC_NOTIFICATION = "generic"
 | 
			
		||||
	FULL_NOTIFICATION    = "full"
 | 
			
		||||
 | 
			
		||||
	DIRECT_MESSAGE_ANY  = "any"
 | 
			
		||||
	DIRECT_MESSAGE_TEAM = "team"
 | 
			
		||||
 | 
			
		||||
	FAKE_SETTING = "********************************"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// should match the values in webapp/i18n/i18n.jsx
 | 
			
		||||
var LOCALES = []string{
 | 
			
		||||
	"en",
 | 
			
		||||
	"es",
 | 
			
		||||
	"fr",
 | 
			
		||||
	"ja",
 | 
			
		||||
	"pt-BR",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServiceSettings struct {
 | 
			
		||||
	ListenAddress                     string
 | 
			
		||||
	MaximumLoginAttempts              int
 | 
			
		||||
	SegmentDeveloperKey               string
 | 
			
		||||
	GoogleDeveloperKey                string
 | 
			
		||||
	EnableOAuthServiceProvider        bool
 | 
			
		||||
	EnableIncomingWebhooks            bool
 | 
			
		||||
	EnableOutgoingWebhooks            bool
 | 
			
		||||
	EnableCommands                    *bool
 | 
			
		||||
	EnableOnlyAdminIntegrations       *bool
 | 
			
		||||
	EnablePostUsernameOverride        bool
 | 
			
		||||
	EnablePostIconOverride            bool
 | 
			
		||||
	EnableTesting                     bool
 | 
			
		||||
	EnableDeveloper                   *bool
 | 
			
		||||
	EnableSecurityFixAlert            *bool
 | 
			
		||||
	EnableInsecureOutgoingConnections *bool
 | 
			
		||||
	EnableMultifactorAuthentication   *bool
 | 
			
		||||
	AllowCorsFrom                     *string
 | 
			
		||||
	SessionLengthWebInDays            *int
 | 
			
		||||
	SessionLengthMobileInDays         *int
 | 
			
		||||
	SessionLengthSSOInDays            *int
 | 
			
		||||
	SessionCacheInMinutes             *int
 | 
			
		||||
	WebsocketSecurePort               *int
 | 
			
		||||
	WebsocketPort                     *int
 | 
			
		||||
	WebserverMode                     *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SSOSettings struct {
 | 
			
		||||
	Enable          bool
 | 
			
		||||
	Secret          string
 | 
			
		||||
	Id              string
 | 
			
		||||
	Scope           string
 | 
			
		||||
	AuthEndpoint    string
 | 
			
		||||
	TokenEndpoint   string
 | 
			
		||||
	UserApiEndpoint string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SqlSettings struct {
 | 
			
		||||
	DriverName         string
 | 
			
		||||
	DataSource         string
 | 
			
		||||
	DataSourceReplicas []string
 | 
			
		||||
	MaxIdleConns       int
 | 
			
		||||
	MaxOpenConns       int
 | 
			
		||||
	Trace              bool
 | 
			
		||||
	AtRestEncryptKey   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LogSettings struct {
 | 
			
		||||
	EnableConsole bool
 | 
			
		||||
	ConsoleLevel  string
 | 
			
		||||
	EnableFile    bool
 | 
			
		||||
	FileLevel     string
 | 
			
		||||
	FileFormat    string
 | 
			
		||||
	FileLocation  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FileSettings struct {
 | 
			
		||||
	MaxFileSize                *int64
 | 
			
		||||
	DriverName                 string
 | 
			
		||||
	Directory                  string
 | 
			
		||||
	EnablePublicLink           bool
 | 
			
		||||
	PublicLinkSalt             string
 | 
			
		||||
	ThumbnailWidth             int
 | 
			
		||||
	ThumbnailHeight            int
 | 
			
		||||
	PreviewWidth               int
 | 
			
		||||
	PreviewHeight              int
 | 
			
		||||
	ProfileWidth               int
 | 
			
		||||
	ProfileHeight              int
 | 
			
		||||
	InitialFont                string
 | 
			
		||||
	AmazonS3AccessKeyId        string
 | 
			
		||||
	AmazonS3SecretAccessKey    string
 | 
			
		||||
	AmazonS3Bucket             string
 | 
			
		||||
	AmazonS3Region             string
 | 
			
		||||
	AmazonS3Endpoint           string
 | 
			
		||||
	AmazonS3BucketEndpoint     string
 | 
			
		||||
	AmazonS3LocationConstraint *bool
 | 
			
		||||
	AmazonS3LowercaseBucket    *bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EmailSettings struct {
 | 
			
		||||
	EnableSignUpWithEmail    bool
 | 
			
		||||
	EnableSignInWithEmail    *bool
 | 
			
		||||
	EnableSignInWithUsername *bool
 | 
			
		||||
	SendEmailNotifications   bool
 | 
			
		||||
	RequireEmailVerification bool
 | 
			
		||||
	FeedbackName             string
 | 
			
		||||
	FeedbackEmail            string
 | 
			
		||||
	SMTPUsername             string
 | 
			
		||||
	SMTPPassword             string
 | 
			
		||||
	SMTPServer               string
 | 
			
		||||
	SMTPPort                 string
 | 
			
		||||
	ConnectionSecurity       string
 | 
			
		||||
	InviteSalt               string
 | 
			
		||||
	PasswordResetSalt        string
 | 
			
		||||
	SendPushNotifications    *bool
 | 
			
		||||
	PushNotificationServer   *string
 | 
			
		||||
	PushNotificationContents *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RateLimitSettings struct {
 | 
			
		||||
	EnableRateLimiter bool
 | 
			
		||||
	PerSec            int
 | 
			
		||||
	MemoryStoreSize   int
 | 
			
		||||
	VaryByRemoteAddr  bool
 | 
			
		||||
	VaryByHeader      string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PrivacySettings struct {
 | 
			
		||||
	ShowEmailAddress bool
 | 
			
		||||
	ShowFullName     bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SupportSettings struct {
 | 
			
		||||
	TermsOfServiceLink *string
 | 
			
		||||
	PrivacyPolicyLink  *string
 | 
			
		||||
	AboutLink          *string
 | 
			
		||||
	HelpLink           *string
 | 
			
		||||
	ReportAProblemLink *string
 | 
			
		||||
	SupportEmail       *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TeamSettings struct {
 | 
			
		||||
	SiteName                  string
 | 
			
		||||
	MaxUsersPerTeam           int
 | 
			
		||||
	EnableTeamCreation        bool
 | 
			
		||||
	EnableUserCreation        bool
 | 
			
		||||
	EnableOpenServer          *bool
 | 
			
		||||
	RestrictCreationToDomains string
 | 
			
		||||
	RestrictTeamNames         *bool
 | 
			
		||||
	EnableCustomBrand         *bool
 | 
			
		||||
	CustomBrandText           *string
 | 
			
		||||
	RestrictDirectMessage     *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LdapSettings struct {
 | 
			
		||||
	// Basic
 | 
			
		||||
	Enable             *bool
 | 
			
		||||
	LdapServer         *string
 | 
			
		||||
	LdapPort           *int
 | 
			
		||||
	ConnectionSecurity *string
 | 
			
		||||
	BaseDN             *string
 | 
			
		||||
	BindUsername       *string
 | 
			
		||||
	BindPassword       *string
 | 
			
		||||
 | 
			
		||||
	// Filtering
 | 
			
		||||
	UserFilter *string
 | 
			
		||||
 | 
			
		||||
	// User Mapping
 | 
			
		||||
	FirstNameAttribute *string
 | 
			
		||||
	LastNameAttribute  *string
 | 
			
		||||
	EmailAttribute     *string
 | 
			
		||||
	UsernameAttribute  *string
 | 
			
		||||
	NicknameAttribute  *string
 | 
			
		||||
	IdAttribute        *string
 | 
			
		||||
 | 
			
		||||
	// Syncronization
 | 
			
		||||
	SyncIntervalMinutes *int
 | 
			
		||||
 | 
			
		||||
	// Advanced
 | 
			
		||||
	SkipCertificateVerification *bool
 | 
			
		||||
	QueryTimeout                *int
 | 
			
		||||
 | 
			
		||||
	// Customization
 | 
			
		||||
	LoginFieldName *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ComplianceSettings struct {
 | 
			
		||||
	Enable      *bool
 | 
			
		||||
	Directory   *string
 | 
			
		||||
	EnableDaily *bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LocalizationSettings struct {
 | 
			
		||||
	DefaultServerLocale *string
 | 
			
		||||
	DefaultClientLocale *string
 | 
			
		||||
	AvailableLocales    *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	ServiceSettings      ServiceSettings
 | 
			
		||||
	TeamSettings         TeamSettings
 | 
			
		||||
	SqlSettings          SqlSettings
 | 
			
		||||
	LogSettings          LogSettings
 | 
			
		||||
	FileSettings         FileSettings
 | 
			
		||||
	EmailSettings        EmailSettings
 | 
			
		||||
	RateLimitSettings    RateLimitSettings
 | 
			
		||||
	PrivacySettings      PrivacySettings
 | 
			
		||||
	SupportSettings      SupportSettings
 | 
			
		||||
	GitLabSettings       SSOSettings
 | 
			
		||||
	GoogleSettings       SSOSettings
 | 
			
		||||
	LdapSettings         LdapSettings
 | 
			
		||||
	ComplianceSettings   ComplianceSettings
 | 
			
		||||
	LocalizationSettings LocalizationSettings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) GetSSOService(service string) *SSOSettings {
 | 
			
		||||
	switch service {
 | 
			
		||||
	case SERVICE_GITLAB:
 | 
			
		||||
		return &o.GitLabSettings
 | 
			
		||||
	case SERVICE_GOOGLE:
 | 
			
		||||
		return &o.GoogleSettings
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ConfigFromJson(data io.Reader) *Config {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o Config
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) SetDefaults() {
 | 
			
		||||
 | 
			
		||||
	if len(o.SqlSettings.AtRestEncryptKey) == 0 {
 | 
			
		||||
		o.SqlSettings.AtRestEncryptKey = NewRandomString(32)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.MaxFileSize == nil {
 | 
			
		||||
		o.FileSettings.MaxFileSize = new(int64)
 | 
			
		||||
		*o.FileSettings.MaxFileSize = 52428800 // 50 MB
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.FileSettings.PublicLinkSalt) == 0 {
 | 
			
		||||
		o.FileSettings.PublicLinkSalt = NewRandomString(32)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.AmazonS3LocationConstraint == nil {
 | 
			
		||||
		o.FileSettings.AmazonS3LocationConstraint = new(bool)
 | 
			
		||||
		*o.FileSettings.AmazonS3LocationConstraint = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.AmazonS3LowercaseBucket == nil {
 | 
			
		||||
		o.FileSettings.AmazonS3LowercaseBucket = new(bool)
 | 
			
		||||
		*o.FileSettings.AmazonS3LowercaseBucket = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.EmailSettings.InviteSalt) == 0 {
 | 
			
		||||
		o.EmailSettings.InviteSalt = NewRandomString(32)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.EmailSettings.PasswordResetSalt) == 0 {
 | 
			
		||||
		o.EmailSettings.PasswordResetSalt = NewRandomString(32)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableDeveloper == nil {
 | 
			
		||||
		o.ServiceSettings.EnableDeveloper = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableDeveloper = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableSecurityFixAlert == nil {
 | 
			
		||||
		o.ServiceSettings.EnableSecurityFixAlert = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableSecurityFixAlert = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableInsecureOutgoingConnections == nil {
 | 
			
		||||
		o.ServiceSettings.EnableInsecureOutgoingConnections = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableInsecureOutgoingConnections = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableMultifactorAuthentication == nil {
 | 
			
		||||
		o.ServiceSettings.EnableMultifactorAuthentication = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableMultifactorAuthentication = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.RestrictTeamNames == nil {
 | 
			
		||||
		o.TeamSettings.RestrictTeamNames = new(bool)
 | 
			
		||||
		*o.TeamSettings.RestrictTeamNames = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.EnableCustomBrand == nil {
 | 
			
		||||
		o.TeamSettings.EnableCustomBrand = new(bool)
 | 
			
		||||
		*o.TeamSettings.EnableCustomBrand = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.CustomBrandText == nil {
 | 
			
		||||
		o.TeamSettings.CustomBrandText = new(string)
 | 
			
		||||
		*o.TeamSettings.CustomBrandText = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.EnableOpenServer == nil {
 | 
			
		||||
		o.TeamSettings.EnableOpenServer = new(bool)
 | 
			
		||||
		*o.TeamSettings.EnableOpenServer = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.RestrictDirectMessage == nil {
 | 
			
		||||
		o.TeamSettings.RestrictDirectMessage = new(string)
 | 
			
		||||
		*o.TeamSettings.RestrictDirectMessage = DIRECT_MESSAGE_ANY
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.EmailSettings.EnableSignInWithEmail == nil {
 | 
			
		||||
		o.EmailSettings.EnableSignInWithEmail = new(bool)
 | 
			
		||||
 | 
			
		||||
		if o.EmailSettings.EnableSignUpWithEmail == true {
 | 
			
		||||
			*o.EmailSettings.EnableSignInWithEmail = true
 | 
			
		||||
		} else {
 | 
			
		||||
			*o.EmailSettings.EnableSignInWithEmail = false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.EmailSettings.EnableSignInWithUsername == nil {
 | 
			
		||||
		o.EmailSettings.EnableSignInWithUsername = new(bool)
 | 
			
		||||
		*o.EmailSettings.EnableSignInWithUsername = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.EmailSettings.SendPushNotifications == nil {
 | 
			
		||||
		o.EmailSettings.SendPushNotifications = new(bool)
 | 
			
		||||
		*o.EmailSettings.SendPushNotifications = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.EmailSettings.PushNotificationServer == nil {
 | 
			
		||||
		o.EmailSettings.PushNotificationServer = new(string)
 | 
			
		||||
		*o.EmailSettings.PushNotificationServer = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.EmailSettings.PushNotificationContents == nil {
 | 
			
		||||
		o.EmailSettings.PushNotificationContents = new(string)
 | 
			
		||||
		*o.EmailSettings.PushNotificationContents = GENERIC_NOTIFICATION
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsSafeLink(o.SupportSettings.TermsOfServiceLink) {
 | 
			
		||||
		o.SupportSettings.TermsOfServiceLink = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.TermsOfServiceLink == nil {
 | 
			
		||||
		o.SupportSettings.TermsOfServiceLink = new(string)
 | 
			
		||||
		*o.SupportSettings.TermsOfServiceLink = "/static/help/terms.html"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsSafeLink(o.SupportSettings.PrivacyPolicyLink) {
 | 
			
		||||
		o.SupportSettings.PrivacyPolicyLink = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.PrivacyPolicyLink == nil {
 | 
			
		||||
		o.SupportSettings.PrivacyPolicyLink = new(string)
 | 
			
		||||
		*o.SupportSettings.PrivacyPolicyLink = "/static/help/privacy.html"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsSafeLink(o.SupportSettings.AboutLink) {
 | 
			
		||||
		o.SupportSettings.AboutLink = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.AboutLink == nil {
 | 
			
		||||
		o.SupportSettings.AboutLink = new(string)
 | 
			
		||||
		*o.SupportSettings.AboutLink = "/static/help/about.html"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsSafeLink(o.SupportSettings.HelpLink) {
 | 
			
		||||
		o.SupportSettings.HelpLink = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.HelpLink == nil {
 | 
			
		||||
		o.SupportSettings.HelpLink = new(string)
 | 
			
		||||
		*o.SupportSettings.HelpLink = "/static/help/help.html"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !IsSafeLink(o.SupportSettings.ReportAProblemLink) {
 | 
			
		||||
		o.SupportSettings.ReportAProblemLink = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.ReportAProblemLink == nil {
 | 
			
		||||
		o.SupportSettings.ReportAProblemLink = new(string)
 | 
			
		||||
		*o.SupportSettings.ReportAProblemLink = "/static/help/report_problem.html"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SupportSettings.SupportEmail == nil {
 | 
			
		||||
		o.SupportSettings.SupportEmail = new(string)
 | 
			
		||||
		*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.Enable == nil {
 | 
			
		||||
		o.LdapSettings.Enable = new(bool)
 | 
			
		||||
		*o.LdapSettings.Enable = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.LdapServer == nil {
 | 
			
		||||
		o.LdapSettings.LdapServer = new(string)
 | 
			
		||||
		*o.LdapSettings.LdapServer = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.LdapPort == nil {
 | 
			
		||||
		o.LdapSettings.LdapPort = new(int)
 | 
			
		||||
		*o.LdapSettings.LdapPort = 389
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.ConnectionSecurity == nil {
 | 
			
		||||
		o.LdapSettings.ConnectionSecurity = new(string)
 | 
			
		||||
		*o.LdapSettings.ConnectionSecurity = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.BaseDN == nil {
 | 
			
		||||
		o.LdapSettings.BaseDN = new(string)
 | 
			
		||||
		*o.LdapSettings.BaseDN = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.BindUsername == nil {
 | 
			
		||||
		o.LdapSettings.BindUsername = new(string)
 | 
			
		||||
		*o.LdapSettings.BindUsername = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.BindPassword == nil {
 | 
			
		||||
		o.LdapSettings.BindPassword = new(string)
 | 
			
		||||
		*o.LdapSettings.BindPassword = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.UserFilter == nil {
 | 
			
		||||
		o.LdapSettings.UserFilter = new(string)
 | 
			
		||||
		*o.LdapSettings.UserFilter = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.FirstNameAttribute == nil {
 | 
			
		||||
		o.LdapSettings.FirstNameAttribute = new(string)
 | 
			
		||||
		*o.LdapSettings.FirstNameAttribute = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.LastNameAttribute == nil {
 | 
			
		||||
		o.LdapSettings.LastNameAttribute = new(string)
 | 
			
		||||
		*o.LdapSettings.LastNameAttribute = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.EmailAttribute == nil {
 | 
			
		||||
		o.LdapSettings.EmailAttribute = new(string)
 | 
			
		||||
		*o.LdapSettings.EmailAttribute = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.NicknameAttribute == nil {
 | 
			
		||||
		o.LdapSettings.NicknameAttribute = new(string)
 | 
			
		||||
		*o.LdapSettings.NicknameAttribute = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.IdAttribute == nil {
 | 
			
		||||
		o.LdapSettings.IdAttribute = new(string)
 | 
			
		||||
		*o.LdapSettings.IdAttribute = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.SyncIntervalMinutes == nil {
 | 
			
		||||
		o.LdapSettings.SyncIntervalMinutes = new(int)
 | 
			
		||||
		*o.LdapSettings.SyncIntervalMinutes = 60
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.SkipCertificateVerification == nil {
 | 
			
		||||
		o.LdapSettings.SkipCertificateVerification = new(bool)
 | 
			
		||||
		*o.LdapSettings.SkipCertificateVerification = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.QueryTimeout == nil {
 | 
			
		||||
		o.LdapSettings.QueryTimeout = new(int)
 | 
			
		||||
		*o.LdapSettings.QueryTimeout = 60
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LdapSettings.LoginFieldName == nil {
 | 
			
		||||
		o.LdapSettings.LoginFieldName = new(string)
 | 
			
		||||
		*o.LdapSettings.LoginFieldName = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.SessionLengthWebInDays == nil {
 | 
			
		||||
		o.ServiceSettings.SessionLengthWebInDays = new(int)
 | 
			
		||||
		*o.ServiceSettings.SessionLengthWebInDays = 30
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.SessionLengthMobileInDays == nil {
 | 
			
		||||
		o.ServiceSettings.SessionLengthMobileInDays = new(int)
 | 
			
		||||
		*o.ServiceSettings.SessionLengthMobileInDays = 30
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.SessionLengthSSOInDays == nil {
 | 
			
		||||
		o.ServiceSettings.SessionLengthSSOInDays = new(int)
 | 
			
		||||
		*o.ServiceSettings.SessionLengthSSOInDays = 30
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.SessionCacheInMinutes == nil {
 | 
			
		||||
		o.ServiceSettings.SessionCacheInMinutes = new(int)
 | 
			
		||||
		*o.ServiceSettings.SessionCacheInMinutes = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableCommands == nil {
 | 
			
		||||
		o.ServiceSettings.EnableCommands = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableCommands = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.EnableOnlyAdminIntegrations == nil {
 | 
			
		||||
		o.ServiceSettings.EnableOnlyAdminIntegrations = new(bool)
 | 
			
		||||
		*o.ServiceSettings.EnableOnlyAdminIntegrations = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.WebsocketPort == nil {
 | 
			
		||||
		o.ServiceSettings.WebsocketPort = new(int)
 | 
			
		||||
		*o.ServiceSettings.WebsocketPort = 80
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.WebsocketSecurePort == nil {
 | 
			
		||||
		o.ServiceSettings.WebsocketSecurePort = new(int)
 | 
			
		||||
		*o.ServiceSettings.WebsocketSecurePort = 443
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.AllowCorsFrom == nil {
 | 
			
		||||
		o.ServiceSettings.AllowCorsFrom = new(string)
 | 
			
		||||
		*o.ServiceSettings.AllowCorsFrom = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.WebserverMode == nil {
 | 
			
		||||
		o.ServiceSettings.WebserverMode = new(string)
 | 
			
		||||
		*o.ServiceSettings.WebserverMode = "regular"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ComplianceSettings.Enable == nil {
 | 
			
		||||
		o.ComplianceSettings.Enable = new(bool)
 | 
			
		||||
		*o.ComplianceSettings.Enable = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ComplianceSettings.Directory == nil {
 | 
			
		||||
		o.ComplianceSettings.Directory = new(string)
 | 
			
		||||
		*o.ComplianceSettings.Directory = "./data/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.ComplianceSettings.EnableDaily == nil {
 | 
			
		||||
		o.ComplianceSettings.EnableDaily = new(bool)
 | 
			
		||||
		*o.ComplianceSettings.EnableDaily = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LocalizationSettings.DefaultServerLocale == nil {
 | 
			
		||||
		o.LocalizationSettings.DefaultServerLocale = new(string)
 | 
			
		||||
		*o.LocalizationSettings.DefaultServerLocale = DEFAULT_LOCALE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LocalizationSettings.DefaultClientLocale == nil {
 | 
			
		||||
		o.LocalizationSettings.DefaultClientLocale = new(string)
 | 
			
		||||
		*o.LocalizationSettings.DefaultClientLocale = DEFAULT_LOCALE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.LocalizationSettings.AvailableLocales == nil {
 | 
			
		||||
		o.LocalizationSettings.AvailableLocales = new(string)
 | 
			
		||||
		*o.LocalizationSettings.AvailableLocales = strings.Join(LOCALES, ",")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if o.ServiceSettings.MaximumLoginAttempts <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.ServiceSettings.ListenAddress) == 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.TeamSettings.MaxUsersPerTeam <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(*o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.SqlSettings.AtRestEncryptKey) < 32 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(o.SqlSettings.DriverName == DATABASE_DRIVER_MYSQL || o.SqlSettings.DriverName == DATABASE_DRIVER_POSTGRES) {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_driver.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SqlSettings.MaxIdleConns <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_idle.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.SqlSettings.DataSource) == 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.SqlSettings.MaxOpenConns <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if *o.FileSettings.MaxFileSize <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.max_file_size.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(o.FileSettings.DriverName == IMAGE_DRIVER_LOCAL || o.FileSettings.DriverName == IMAGE_DRIVER_S3) {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.PreviewHeight < 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_preview_height.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.PreviewWidth <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_preview_width.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.ProfileHeight <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_profile_height.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.ProfileWidth <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_profile_width.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.ThumbnailHeight <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_thumb_height.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.FileSettings.ThumbnailWidth <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_thumb_width.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.FileSettings.PublicLinkSalt) < 32 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(o.EmailSettings.ConnectionSecurity == CONN_SECURITY_NONE || o.EmailSettings.ConnectionSecurity == CONN_SECURITY_TLS || o.EmailSettings.ConnectionSecurity == CONN_SECURITY_STARTTLS) {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_security.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.EmailSettings.InviteSalt) < 32 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_salt.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.EmailSettings.PasswordResetSalt) < 32 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_reset_salt.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.RateLimitSettings.MemoryStoreSize <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.rate_mem.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.RateLimitSettings.PerSec <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.rate_sec.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !(*o.LdapSettings.ConnectionSecurity == CONN_SECURITY_NONE || *o.LdapSettings.ConnectionSecurity == CONN_SECURITY_TLS || *o.LdapSettings.ConnectionSecurity == CONN_SECURITY_STARTTLS) {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if *o.LdapSettings.SyncIntervalMinutes <= 0 {
 | 
			
		||||
		return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) GetSanitizeOptions() map[string]bool {
 | 
			
		||||
	options := map[string]bool{}
 | 
			
		||||
	options["fullname"] = o.PrivacySettings.ShowFullName
 | 
			
		||||
	options["email"] = o.PrivacySettings.ShowEmailAddress
 | 
			
		||||
 | 
			
		||||
	return options
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *Config) Sanitize() {
 | 
			
		||||
	if o.LdapSettings.BindPassword != nil && len(*o.LdapSettings.BindPassword) > 0 {
 | 
			
		||||
		*o.LdapSettings.BindPassword = FAKE_SETTING
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.FileSettings.PublicLinkSalt = FAKE_SETTING
 | 
			
		||||
	if len(o.FileSettings.AmazonS3SecretAccessKey) > 0 {
 | 
			
		||||
		o.FileSettings.AmazonS3SecretAccessKey = FAKE_SETTING
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.EmailSettings.InviteSalt = FAKE_SETTING
 | 
			
		||||
	o.EmailSettings.PasswordResetSalt = FAKE_SETTING
 | 
			
		||||
	if len(o.EmailSettings.SMTPPassword) > 0 {
 | 
			
		||||
		o.EmailSettings.SMTPPassword = FAKE_SETTING
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.GitLabSettings.Secret) > 0 {
 | 
			
		||||
		o.GitLabSettings.Secret = FAKE_SETTING
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.SqlSettings.DataSource = FAKE_SETTING
 | 
			
		||||
	o.SqlSettings.AtRestEncryptKey = FAKE_SETTING
 | 
			
		||||
 | 
			
		||||
	for i := range o.SqlSettings.DataSourceReplicas {
 | 
			
		||||
		o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/mattermost/platform/model/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/mattermost/platform/model/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	IMAGE_EXTENSIONS = [5]string{".jpg", ".jpeg", ".gif", ".bmp", ".png"}
 | 
			
		||||
	IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type FileUploadResponse struct {
 | 
			
		||||
	Filenames []string `json:"filenames"`
 | 
			
		||||
	ClientIds []string `json:"client_ids"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FileUploadResponseFromJson(data io.Reader) *FileUploadResponse {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o FileUploadResponse
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *FileUploadResponse) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								vendor/github.com/mattermost/platform/model/file_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/mattermost/platform/model/file_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"image/gif"
 | 
			
		||||
	"io"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type FileInfo struct {
 | 
			
		||||
	Filename        string `json:"filename"`
 | 
			
		||||
	Size            int    `json:"size"`
 | 
			
		||||
	Extension       string `json:"extension"`
 | 
			
		||||
	MimeType        string `json:"mime_type"`
 | 
			
		||||
	HasPreviewImage bool   `json:"has_preview_image"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetInfoForBytes(filename string, data []byte) (*FileInfo, *AppError) {
 | 
			
		||||
	size := len(data)
 | 
			
		||||
 | 
			
		||||
	var mimeType string
 | 
			
		||||
	extension := filepath.Ext(filename)
 | 
			
		||||
	isImage := IsFileExtImage(extension)
 | 
			
		||||
	if isImage {
 | 
			
		||||
		mimeType = GetImageMimeType(extension)
 | 
			
		||||
	} else {
 | 
			
		||||
		mimeType = mime.TypeByExtension(extension)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if extension != "" && extension[0] == '.' {
 | 
			
		||||
		// the client expects a file extension without the leading period
 | 
			
		||||
		extension = extension[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hasPreviewImage := isImage
 | 
			
		||||
	if mimeType == "image/gif" {
 | 
			
		||||
		// just show the gif itself instead of a preview image for animated gifs
 | 
			
		||||
		if gifImage, err := gif.DecodeAll(bytes.NewReader(data)); err != nil {
 | 
			
		||||
			return nil, NewLocAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "filename="+filename)
 | 
			
		||||
		} else {
 | 
			
		||||
			hasPreviewImage = len(gifImage.Image) == 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &FileInfo{
 | 
			
		||||
		Filename:        filename,
 | 
			
		||||
		Size:            size,
 | 
			
		||||
		Extension:       extension,
 | 
			
		||||
		MimeType:        mimeType,
 | 
			
		||||
		HasPreviewImage: hasPreviewImage,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (info *FileInfo) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FileInfoFromJson(data io.Reader) *FileInfo {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
 | 
			
		||||
	var info FileInfo
 | 
			
		||||
	if err := decoder.Decode(&info); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return &info
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/mattermost/platform/model/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/mattermost/platform/model/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	USER_AUTH_SERVICE_GITLAB = "gitlab"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										105
									
								
								vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package oauthgitlab
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/mattermost/platform/einterfaces"
 | 
			
		||||
	"github.com/mattermost/platform/model"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GitLabProvider struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GitLabUser struct {
 | 
			
		||||
	Id       int64  `json:"id"`
 | 
			
		||||
	Username string `json:"username"`
 | 
			
		||||
	Login    string `json:"login"`
 | 
			
		||||
	Email    string `json:"email"`
 | 
			
		||||
	Name     string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	provider := &GitLabProvider{}
 | 
			
		||||
	einterfaces.RegisterOauthProvider(model.USER_AUTH_SERVICE_GITLAB, provider)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func userFromGitLabUser(glu *GitLabUser) *model.User {
 | 
			
		||||
	user := &model.User{}
 | 
			
		||||
	username := glu.Username
 | 
			
		||||
	if username == "" {
 | 
			
		||||
		username = glu.Login
 | 
			
		||||
	}
 | 
			
		||||
	user.Username = model.CleanUsername(username)
 | 
			
		||||
	splitName := strings.Split(glu.Name, " ")
 | 
			
		||||
	if len(splitName) == 2 {
 | 
			
		||||
		user.FirstName = splitName[0]
 | 
			
		||||
		user.LastName = splitName[1]
 | 
			
		||||
	} else if len(splitName) >= 2 {
 | 
			
		||||
		user.FirstName = splitName[0]
 | 
			
		||||
		user.LastName = strings.Join(splitName[1:], " ")
 | 
			
		||||
	} else {
 | 
			
		||||
		user.FirstName = glu.Name
 | 
			
		||||
	}
 | 
			
		||||
	strings.TrimSpace(user.Email)
 | 
			
		||||
	user.Email = glu.Email
 | 
			
		||||
	userId := strconv.FormatInt(glu.Id, 10)
 | 
			
		||||
	user.AuthData = &userId
 | 
			
		||||
	user.AuthService = model.USER_AUTH_SERVICE_GITLAB
 | 
			
		||||
 | 
			
		||||
	return user
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func gitLabUserFromJson(data io.Reader) *GitLabUser {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var glu GitLabUser
 | 
			
		||||
	err := decoder.Decode(&glu)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &glu
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (glu *GitLabUser) IsValid() bool {
 | 
			
		||||
	if glu.Id == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(glu.Email) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (glu *GitLabUser) getAuthData() string {
 | 
			
		||||
	return strconv.FormatInt(glu.Id, 10)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GitLabProvider) GetIdentifier() string {
 | 
			
		||||
	return model.USER_AUTH_SERVICE_GITLAB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GitLabProvider) GetUserFromJson(data io.Reader) *model.User {
 | 
			
		||||
	glu := gitLabUserFromJson(data)
 | 
			
		||||
	if glu.IsValid() {
 | 
			
		||||
		return userFromGitLabUser(glu)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &model.User{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GitLabProvider) GetAuthDataFromJson(data io.Reader) string {
 | 
			
		||||
	glu := gitLabUserFromJson(data)
 | 
			
		||||
 | 
			
		||||
	if glu.IsValid() {
 | 
			
		||||
		return glu.getAuthData()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										262
									
								
								vendor/github.com/mattermost/platform/model/incoming_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								vendor/github.com/mattermost/platform/model/incoming_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
			
		||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	DEFAULT_WEBHOOK_USERNAME = "webhook"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IncomingWebhook struct {
 | 
			
		||||
	Id          string `json:"id"`
 | 
			
		||||
	CreateAt    int64  `json:"create_at"`
 | 
			
		||||
	UpdateAt    int64  `json:"update_at"`
 | 
			
		||||
	DeleteAt    int64  `json:"delete_at"`
 | 
			
		||||
	UserId      string `json:"user_id"`
 | 
			
		||||
	ChannelId   string `json:"channel_id"`
 | 
			
		||||
	TeamId      string `json:"team_id"`
 | 
			
		||||
	DisplayName string `json:"display_name"`
 | 
			
		||||
	Description string `json:"description"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IncomingWebhookRequest struct {
 | 
			
		||||
	Text        string          `json:"text"`
 | 
			
		||||
	Username    string          `json:"username"`
 | 
			
		||||
	IconURL     string          `json:"icon_url"`
 | 
			
		||||
	ChannelName string          `json:"channel"`
 | 
			
		||||
	Props       StringInterface `json:"props"`
 | 
			
		||||
	Attachments interface{}     `json:"attachments"`
 | 
			
		||||
	Type        string          `json:"type"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *IncomingWebhook) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(o)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IncomingWebhookFromJson(data io.Reader) *IncomingWebhook {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o IncomingWebhook
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IncomingWebhookListToJson(l []*IncomingWebhook) string {
 | 
			
		||||
	b, err := json.Marshal(l)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IncomingWebhookListFromJson(data io.Reader) []*IncomingWebhook {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o []*IncomingWebhook
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *IncomingWebhook) IsValid() *AppError {
 | 
			
		||||
 | 
			
		||||
	if len(o.Id) != 26 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.CreateAt == 0 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.create_at.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if o.UpdateAt == 0 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.UserId) != 26 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.ChannelId) != 26 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.TeamId) != 26 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.DisplayName) > 64 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(o.Description) > 128 {
 | 
			
		||||
		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *IncomingWebhook) PreSave() {
 | 
			
		||||
	if o.Id == "" {
 | 
			
		||||
		o.Id = NewId()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	o.CreateAt = GetMillis()
 | 
			
		||||
	o.UpdateAt = o.CreateAt
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *IncomingWebhook) PreUpdate() {
 | 
			
		||||
	o.UpdateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// escapeControlCharsFromPayload escapes control chars (\n, \t) from a byte slice.
 | 
			
		||||
// Context:
 | 
			
		||||
// JSON strings are not supposed to contain control characters such as \n, \t,
 | 
			
		||||
// ... but some incoming webhooks might still send invalid JSON and we want to
 | 
			
		||||
// try to handle that. An example invalid JSON string from an incoming webhook
 | 
			
		||||
// might look like this (strings for both "text" and "fallback" attributes are
 | 
			
		||||
// invalid JSON strings because they contain unescaped newlines and tabs):
 | 
			
		||||
//  `{
 | 
			
		||||
//    "text": "this is a test
 | 
			
		||||
//						 that contains a newline and tabs",
 | 
			
		||||
//    "attachments": [
 | 
			
		||||
//      {
 | 
			
		||||
//        "fallback": "Required plain-text summary of the attachment
 | 
			
		||||
//										that contains a newline and tabs",
 | 
			
		||||
//        "color": "#36a64f",
 | 
			
		||||
//  			...
 | 
			
		||||
//        "text": "Optional text that appears within the attachment
 | 
			
		||||
//								 that contains a newline and tabs",
 | 
			
		||||
//  			...
 | 
			
		||||
//        "thumb_url": "http://example.com/path/to/thumb.png"
 | 
			
		||||
//      }
 | 
			
		||||
//    ]
 | 
			
		||||
//  }`
 | 
			
		||||
// This function will search for `"key": "value"` pairs, and escape \n, \t
 | 
			
		||||
// from the value.
 | 
			
		||||
func escapeControlCharsFromPayload(by []byte) []byte {
 | 
			
		||||
	// we'll search for `"text": "..."` or `"fallback": "..."`, ...
 | 
			
		||||
	keys := "text|fallback|pretext|author_name|title|value"
 | 
			
		||||
 | 
			
		||||
	// the regexp reads like this:
 | 
			
		||||
	// (?s): this flag let . match \n (default is false)
 | 
			
		||||
	// "(keys)": we search for the keys defined above
 | 
			
		||||
	// \s*:\s*: followed by 0..n spaces/tabs, a colon then 0..n spaces/tabs
 | 
			
		||||
	// ": a double-quote
 | 
			
		||||
	// (\\"|[^"])*: any number of times the `\"` string or any char but a double-quote
 | 
			
		||||
	// ": a double-quote
 | 
			
		||||
	r := `(?s)"(` + keys + `)"\s*:\s*"(\\"|[^"])*"`
 | 
			
		||||
	re := regexp.MustCompile(r)
 | 
			
		||||
 | 
			
		||||
	// the function that will escape \n and \t on the regexp matches
 | 
			
		||||
	repl := func(b []byte) []byte {
 | 
			
		||||
		if bytes.Contains(b, []byte("\n")) {
 | 
			
		||||
			b = bytes.Replace(b, []byte("\n"), []byte("\\n"), -1)
 | 
			
		||||
		}
 | 
			
		||||
		if bytes.Contains(b, []byte("\t")) {
 | 
			
		||||
			b = bytes.Replace(b, []byte("\t"), []byte("\\t"), -1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return b
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return re.ReplaceAllFunc(by, repl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) {
 | 
			
		||||
	decoder := json.NewDecoder(bytes.NewReader(by))
 | 
			
		||||
	var o IncomingWebhookRequest
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// To mention @channel via a webhook in Slack, the message should contain
 | 
			
		||||
// <!channel>, as explained at the bottom of this article:
 | 
			
		||||
// https://get.slack.help/hc/en-us/articles/202009646-Making-announcements
 | 
			
		||||
func expandAnnouncement(text string) string {
 | 
			
		||||
	c1 := "<!channel>"
 | 
			
		||||
	c2 := "@channel"
 | 
			
		||||
	if strings.Contains(text, c1) {
 | 
			
		||||
		return strings.Replace(text, c1, c2, -1)
 | 
			
		||||
	}
 | 
			
		||||
	return text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Expand announcements in incoming webhooks from Slack. Those announcements
 | 
			
		||||
// can be found in the text attribute, or in the pretext, text, title and value
 | 
			
		||||
// attributes of the attachment structure. The Slack attachment structure is
 | 
			
		||||
// documented here: https://api.slack.com/docs/attachments
 | 
			
		||||
func expandAnnouncements(i *IncomingWebhookRequest) {
 | 
			
		||||
	i.Text = expandAnnouncement(i.Text)
 | 
			
		||||
 | 
			
		||||
	if i.Attachments != nil {
 | 
			
		||||
		attachments := i.Attachments.([]interface{})
 | 
			
		||||
		for _, attachment := range attachments {
 | 
			
		||||
			a := attachment.(map[string]interface{})
 | 
			
		||||
 | 
			
		||||
			if a["pretext"] != nil {
 | 
			
		||||
				a["pretext"] = expandAnnouncement(a["pretext"].(string))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if a["text"] != nil {
 | 
			
		||||
				a["text"] = expandAnnouncement(a["text"].(string))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if a["title"] != nil {
 | 
			
		||||
				a["title"] = expandAnnouncement(a["title"].(string))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if a["fields"] != nil {
 | 
			
		||||
				fields := a["fields"].([]interface{})
 | 
			
		||||
				for _, field := range fields {
 | 
			
		||||
					f := field.(map[string]interface{})
 | 
			
		||||
					if f["value"] != nil {
 | 
			
		||||
						f["value"] = expandAnnouncement(f["value"].(string))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest {
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	buf.ReadFrom(data)
 | 
			
		||||
	by := buf.Bytes()
 | 
			
		||||
 | 
			
		||||
	// Try to decode the JSON data. Only if it fails, try to escape control
 | 
			
		||||
	// characters from the strings contained in the JSON data.
 | 
			
		||||
	o, err := decodeIncomingWebhookRequest(by)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		o, err = decodeIncomingWebhookRequest(escapeControlCharsFromPayload(by))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expandAnnouncements(o)
 | 
			
		||||
 | 
			
		||||
	return o
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								vendor/github.com/mattermost/platform/model/initial_load.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/mattermost/platform/model/initial_load.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type InitialLoad struct {
 | 
			
		||||
	User           *User             `json:"user"`
 | 
			
		||||
	TeamMembers    []*TeamMember     `json:"team_members"`
 | 
			
		||||
	Teams          []*Team           `json:"teams"`
 | 
			
		||||
	DirectProfiles map[string]*User  `json:"direct_profiles"`
 | 
			
		||||
	Preferences    Preferences       `json:"preferences"`
 | 
			
		||||
	ClientCfg      map[string]string `json:"client_cfg"`
 | 
			
		||||
	LicenseCfg     map[string]string `json:"license_cfg"`
 | 
			
		||||
	NoAccounts     bool              `json:"no_accounts"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (me *InitialLoad) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(me)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitialLoadFromJson(data io.Reader) *InitialLoad {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o InitialLoad
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										91
									
								
								vendor/github.com/mattermost/platform/model/job.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/mattermost/platform/model/job.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TaskFunc func()
 | 
			
		||||
 | 
			
		||||
type ScheduledTask struct {
 | 
			
		||||
	Name      string        `json:"name"`
 | 
			
		||||
	Interval  time.Duration `json:"interval"`
 | 
			
		||||
	Recurring bool          `json:"recurring"`
 | 
			
		||||
	function  TaskFunc      `json:",omitempty"`
 | 
			
		||||
	timer     *time.Timer   `json:",omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var tasks = make(map[string]*ScheduledTask)
 | 
			
		||||
 | 
			
		||||
func addTask(task *ScheduledTask) {
 | 
			
		||||
	tasks[task.Name] = task
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeTaskByName(name string) {
 | 
			
		||||
	delete(tasks, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTaskByName(name string) *ScheduledTask {
 | 
			
		||||
	return tasks[name]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetAllTasks() *map[string]*ScheduledTask {
 | 
			
		||||
	return &tasks
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateTask(name string, function TaskFunc, timeToExecution time.Duration) *ScheduledTask {
 | 
			
		||||
	task := &ScheduledTask{
 | 
			
		||||
		Name:      name,
 | 
			
		||||
		Interval:  timeToExecution,
 | 
			
		||||
		Recurring: false,
 | 
			
		||||
		function:  function,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	taskRunner := func() {
 | 
			
		||||
		go task.function()
 | 
			
		||||
		removeTaskByName(task.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	task.timer = time.AfterFunc(timeToExecution, taskRunner)
 | 
			
		||||
 | 
			
		||||
	addTask(task)
 | 
			
		||||
 | 
			
		||||
	return task
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateRecurringTask(name string, function TaskFunc, interval time.Duration) *ScheduledTask {
 | 
			
		||||
	task := &ScheduledTask{
 | 
			
		||||
		Name:      name,
 | 
			
		||||
		Interval:  interval,
 | 
			
		||||
		Recurring: true,
 | 
			
		||||
		function:  function,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	taskRecurer := func() {
 | 
			
		||||
		go task.function()
 | 
			
		||||
		task.timer.Reset(task.Interval)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	task.timer = time.AfterFunc(interval, taskRecurer)
 | 
			
		||||
 | 
			
		||||
	addTask(task)
 | 
			
		||||
 | 
			
		||||
	return task
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (task *ScheduledTask) Cancel() {
 | 
			
		||||
	task.timer.Stop()
 | 
			
		||||
	removeTaskByName(task.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (task *ScheduledTask) String() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"%s\nInterval: %s\nRecurring: %t\n",
 | 
			
		||||
		task.Name,
 | 
			
		||||
		task.Interval.String(),
 | 
			
		||||
		task.Recurring,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/mattermost/platform/model/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/mattermost/platform/model/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	USER_AUTH_SERVICE_LDAP = "ldap"
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										141
									
								
								vendor/github.com/mattermost/platform/model/license.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								vendor/github.com/mattermost/platform/model/license.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
 | 
			
		||||
// See License.txt for license information.
 | 
			
		||||
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LicenseRecord struct {
 | 
			
		||||
	Id       string `json:"id"`
 | 
			
		||||
	CreateAt int64  `json:"create_at"`
 | 
			
		||||
	Bytes    string `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type License struct {
 | 
			
		||||
	Id        string    `json:"id"`
 | 
			
		||||
	IssuedAt  int64     `json:"issued_at"`
 | 
			
		||||
	StartsAt  int64     `json:"starts_at"`
 | 
			
		||||
	ExpiresAt int64     `json:"expires_at"`
 | 
			
		||||
	Customer  *Customer `json:"customer"`
 | 
			
		||||
	Features  *Features `json:"features"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Customer struct {
 | 
			
		||||
	Id          string `json:"id"`
 | 
			
		||||
	Name        string `json:"name"`
 | 
			
		||||
	Email       string `json:"email"`
 | 
			
		||||
	Company     string `json:"company"`
 | 
			
		||||
	PhoneNumber string `json:"phone_number"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Features struct {
 | 
			
		||||
	Users          *int  `json:"users"`
 | 
			
		||||
	LDAP           *bool `json:"ldap"`
 | 
			
		||||
	MFA            *bool `json:"mfa"`
 | 
			
		||||
	GoogleSSO      *bool `json:"google_sso"`
 | 
			
		||||
	Compliance     *bool `json:"compliance"`
 | 
			
		||||
	CustomBrand    *bool `json:"custom_brand"`
 | 
			
		||||
	MHPNS          *bool `json:"mhpns"`
 | 
			
		||||
	FutureFeatures *bool `json:"future_features"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *Features) SetDefaults() {
 | 
			
		||||
	if f.FutureFeatures == nil {
 | 
			
		||||
		f.FutureFeatures = new(bool)
 | 
			
		||||
		*f.FutureFeatures = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.Users == nil {
 | 
			
		||||
		f.Users = new(int)
 | 
			
		||||
		*f.Users = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.LDAP == nil {
 | 
			
		||||
		f.LDAP = new(bool)
 | 
			
		||||
		*f.LDAP = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.MFA == nil {
 | 
			
		||||
		f.MFA = new(bool)
 | 
			
		||||
		*f.MFA = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.GoogleSSO == nil {
 | 
			
		||||
		f.GoogleSSO = new(bool)
 | 
			
		||||
		*f.GoogleSSO = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.Compliance == nil {
 | 
			
		||||
		f.Compliance = new(bool)
 | 
			
		||||
		*f.Compliance = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.CustomBrand == nil {
 | 
			
		||||
		f.CustomBrand = new(bool)
 | 
			
		||||
		*f.CustomBrand = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.MHPNS == nil {
 | 
			
		||||
		f.MHPNS = new(bool)
 | 
			
		||||
		*f.MHPNS = *f.FutureFeatures
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *License) IsExpired() bool {
 | 
			
		||||
	now := GetMillis()
 | 
			
		||||
	if l.ExpiresAt < now {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *License) IsStarted() bool {
 | 
			
		||||
	now := GetMillis()
 | 
			
		||||
	if l.StartsAt < now {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *License) ToJson() string {
 | 
			
		||||
	b, err := json.Marshal(l)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	} else {
 | 
			
		||||
		return string(b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LicenseFromJson(data io.Reader) *License {
 | 
			
		||||
	decoder := json.NewDecoder(data)
 | 
			
		||||
	var o License
 | 
			
		||||
	err := decoder.Decode(&o)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return &o
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lr *LicenseRecord) IsValid() *AppError {
 | 
			
		||||
	if len(lr.Id) != 26 {
 | 
			
		||||
		return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if lr.CreateAt == 0 {
 | 
			
		||||
		return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(lr.Bytes) == 0 || len(lr.Bytes) > 10000 {
 | 
			
		||||
		return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lr *LicenseRecord) PreSave() {
 | 
			
		||||
	lr.CreateAt = GetMillis()
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user