forked from lug/matterbridge
		
	Compare commits
	
		
			75 Commits
		
	
	
		
			v0.11.0-be
			...
			v0.15.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					822605c157 | ||
| 
						 | 
					e49266ae43 | ||
| 
						 | 
					62e9de1a3b | ||
| 
						 | 
					2ddc4f7ae9 | ||
| 
						 | 
					2dd402675d | ||
| 
						 | 
					25b1af1e11 | ||
| 
						 | 
					75fb2b8156 | ||
| 
						 | 
					2a403f8b85 | ||
| 
						 | 
					c3d45a9f06 | ||
| 
						 | 
					c07b85b625 | ||
| 
						 | 
					511f653e6e | ||
| 
						 | 
					5636eaca6d | ||
| 
						 | 
					4b839b9958 | ||
| 
						 | 
					3f79da84d5 | ||
| 
						 | 
					d540638223 | ||
| 
						 | 
					4ec9b6dd4e | ||
| 
						 | 
					3bc219167a | ||
| 
						 | 
					8a55c97b4e | ||
| 
						 | 
					9e34162a09 | ||
| 
						 | 
					860a371eeb | ||
| 
						 | 
					41a46526a1 | ||
| 
						 | 
					46b798ac1b | ||
| 
						 | 
					359d0f2910 | ||
| 
						 | 
					ad3cb0386b | ||
| 
						 | 
					3a183cb218 | ||
| 
						 | 
					2eecaccd1c | ||
| 
						 | 
					5f30a98bc1 | ||
| 
						 | 
					b8a2fcbaff | ||
| 
						 | 
					01496cd080 | ||
| 
						 | 
					6a968ab82a | ||
| 
						 | 
					c0c4890887 | ||
| 
						 | 
					171a53592d | ||
| 
						 | 
					7811c330db | ||
| 
						 | 
					9bcd131e66 | ||
| 
						 | 
					c791423dd5 | ||
| 
						 | 
					80bdf38388 | ||
| 
						 | 
					9d9cb32f4e | ||
| 
						 | 
					87229bab13 | ||
| 
						 | 
					f065e9e4d5 | ||
| 
						 | 
					3812693111 | ||
| 
						 | 
					dd3c572256 | ||
| 
						 | 
					c5dfe40326 | ||
| 
						 | 
					ef278301e3 | ||
| 
						 | 
					2888fd64b0 | ||
| 
						 | 
					27c0f37e49 | ||
| 
						 | 
					0774f6a5e7 | ||
| 
						 | 
					4036d4459b | ||
| 
						 | 
					ee643de5b6 | ||
| 
						 | 
					8c7549a09e | ||
| 
						 | 
					7a16146304 | ||
| 
						 | 
					3d3809a21b | ||
| 
						 | 
					29465397dd | ||
| 
						 | 
					d300bb1735 | ||
| 
						 | 
					2e703472f1 | ||
| 
						 | 
					8fede90b9e | ||
| 
						 | 
					d128f157c4 | ||
| 
						 | 
					4fcedabfd0 | ||
| 
						 | 
					246c8e4f74 | ||
| 
						 | 
					4d2207aba7 | ||
| 
						 | 
					17b8b86d68 | ||
| 
						 | 
					fdb57230a3 | ||
| 
						 | 
					7469732bbc | ||
| 
						 | 
					d1dd6c3440 | ||
| 
						 | 
					02612c0061 | ||
| 
						 | 
					a4db63a773 | ||
| 
						 | 
					035c2b906a | ||
| 
						 | 
					6ea8be5749 | ||
| 
						 | 
					36024d5439 | ||
| 
						 | 
					8d52c98373 | ||
| 
						 | 
					b4a4eb0057 | ||
| 
						 | 
					b469c8ddbd | ||
| 
						 | 
					eee0036c7f | ||
| 
						 | 
					89c66b9430 | ||
| 
						 | 
					bd38319d83 | ||
| 
						 | 
					33dffd5ea8 | 
@@ -28,7 +28,7 @@ Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, R
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Requirements
 | 
					# Requirements
 | 
				
			||||||
Accounts to one of the supported bridges
 | 
					Accounts to one of the supported bridges
 | 
				
			||||||
* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.7.x
 | 
					* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.10.x
 | 
				
			||||||
* [IRC](http://www.mirc.com/servers.html)
 | 
					* [IRC](http://www.mirc.com/servers.html)
 | 
				
			||||||
* [XMPP](https://jabber.org)
 | 
					* [XMPP](https://jabber.org)
 | 
				
			||||||
* [Gitter](https://gitter.im)
 | 
					* [Gitter](https://gitter.im)
 | 
				
			||||||
@@ -42,7 +42,7 @@ Accounts to one of the supported bridges
 | 
				
			|||||||
# Installing
 | 
					# Installing
 | 
				
			||||||
## Binaries
 | 
					## Binaries
 | 
				
			||||||
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
 | 
					Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
 | 
				
			||||||
* Latest release [v0.10.3](https://github.com/42wim/matterbridge/releases/latest)
 | 
					* Latest stable release [v0.15.0](https://github.com/42wim/matterbridge/releases/latest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Building
 | 
					## Building
 | 
				
			||||||
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)
 | 
					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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
						"github.com/42wim/matterbridge/bridge/config"
 | 
				
			||||||
	log "github.com/Sirupsen/logrus"
 | 
						log "github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/labstack/echo"
 | 
						"github.com/labstack/echo"
 | 
				
			||||||
 | 
						"github.com/labstack/echo/middleware"
 | 
				
			||||||
	"github.com/zfjagann/golang-ring"
 | 
						"github.com/zfjagann/golang-ring"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -20,7 +21,9 @@ type Api struct {
 | 
				
			|||||||
type ApiMessage struct {
 | 
					type ApiMessage struct {
 | 
				
			||||||
	Text     string `json:"text"`
 | 
						Text     string `json:"text"`
 | 
				
			||||||
	Username string `json:"username"`
 | 
						Username string `json:"username"`
 | 
				
			||||||
 | 
						UserID   string `json:"userid"`
 | 
				
			||||||
	Avatar   string `json:"avatar"`
 | 
						Avatar   string `json:"avatar"`
 | 
				
			||||||
 | 
						Gateway  string `json:"gateway"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var flog *log.Entry
 | 
					var flog *log.Entry
 | 
				
			||||||
@@ -38,6 +41,11 @@ func New(cfg config.Protocol, account string, c chan config.Message) *Api {
 | 
				
			|||||||
	b.Config = &cfg
 | 
						b.Config = &cfg
 | 
				
			||||||
	b.Account = account
 | 
						b.Account = account
 | 
				
			||||||
	b.Remote = c
 | 
						b.Remote = c
 | 
				
			||||||
 | 
						if b.Config.Token != "" {
 | 
				
			||||||
 | 
							e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
 | 
				
			||||||
 | 
								return key == b.Config.Token, nil
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	e.GET("/api/messages", b.handleMessages)
 | 
						e.GET("/api/messages", b.handleMessages)
 | 
				
			||||||
	e.POST("/api/message", b.handlePostMessage)
 | 
						e.POST("/api/message", b.handlePostMessage)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
@@ -70,12 +78,16 @@ func (b *Api) handlePostMessage(c echo.Context) error {
 | 
				
			|||||||
	if err := c.Bind(message); err != nil {
 | 
						if err := c.Bind(message); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						flog.Debugf("Sending message from %s on %s to gateway", message.Username, "api")
 | 
				
			||||||
	b.Remote <- config.Message{
 | 
						b.Remote <- config.Message{
 | 
				
			||||||
		Text:     message.Text,
 | 
							Text:     message.Text,
 | 
				
			||||||
		Username: message.Username,
 | 
							Username: message.Username,
 | 
				
			||||||
 | 
							UserID:   message.UserID,
 | 
				
			||||||
		Channel:  "api",
 | 
							Channel:  "api",
 | 
				
			||||||
		Avatar:   message.Avatar,
 | 
							Avatar:   message.Avatar,
 | 
				
			||||||
		Account:  b.Account,
 | 
							Account:  b.Account,
 | 
				
			||||||
 | 
							Gateway:  message.Gateway,
 | 
				
			||||||
 | 
							Protocol: "api",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return c.JSON(http.StatusOK, message)
 | 
						return c.JSON(http.StatusOK, message)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -83,9 +95,7 @@ func (b *Api) handlePostMessage(c echo.Context) error {
 | 
				
			|||||||
func (b *Api) handleMessages(c echo.Context) error {
 | 
					func (b *Api) handleMessages(c echo.Context) error {
 | 
				
			||||||
	b.Lock()
 | 
						b.Lock()
 | 
				
			||||||
	defer b.Unlock()
 | 
						defer b.Unlock()
 | 
				
			||||||
	for _, msg := range b.Messages.Values() {
 | 
						c.JSONPretty(http.StatusOK, b.Messages.Values(), " ")
 | 
				
			||||||
		c.JSONPretty(http.StatusOK, msg, " ")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	b.Messages = ring.Ring{}
 | 
						b.Messages = ring.Ring{}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,7 +100,7 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
 | 
				
			|||||||
				log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
 | 
									log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
 | 
				
			||||||
				mychannel = mychannel + " " + channel.Options.Key
 | 
									mychannel = mychannel + " " + channel.Options.Key
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			err := b.JoinChannel(channel.Name)
 | 
								err := b.JoinChannel(mychannel)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,19 +10,22 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	EVENT_JOIN_LEAVE = "join_leave"
 | 
						EVENT_JOIN_LEAVE      = "join_leave"
 | 
				
			||||||
	EVENT_FAILURE    = "failure"
 | 
						EVENT_FAILURE         = "failure"
 | 
				
			||||||
 | 
						EVENT_REJOIN_CHANNELS = "rejoin_channels"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Message struct {
 | 
					type Message struct {
 | 
				
			||||||
	Text      string
 | 
						Text      string    `json:"text"`
 | 
				
			||||||
	Channel   string
 | 
						Channel   string    `json:"channel"`
 | 
				
			||||||
	Username  string
 | 
						Username  string    `json:"username"`
 | 
				
			||||||
	Avatar    string
 | 
						UserID    string    `json:"userid"` // userid on the bridge
 | 
				
			||||||
	Account   string
 | 
						Avatar    string    `json:"avatar"`
 | 
				
			||||||
	Event     string
 | 
						Account   string    `json:"account"`
 | 
				
			||||||
	Protocol  string
 | 
						Event     string    `json:"event"`
 | 
				
			||||||
	Timestamp time.Time
 | 
						Protocol  string    `json:"protocol"`
 | 
				
			||||||
 | 
						Gateway   string    `json:"gateway"`
 | 
				
			||||||
 | 
						Timestamp time.Time `json:"timestamp"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ChannelInfo struct {
 | 
					type ChannelInfo struct {
 | 
				
			||||||
@@ -38,8 +41,11 @@ type ChannelInfo struct {
 | 
				
			|||||||
type Protocol struct {
 | 
					type Protocol struct {
 | 
				
			||||||
	BindAddress            string // mattermost, slack
 | 
						BindAddress            string // mattermost, slack
 | 
				
			||||||
	Buffer                 int    // api
 | 
						Buffer                 int    // api
 | 
				
			||||||
 | 
						EditSuffix             string // mattermost, slack, discord, telegram, gitter
 | 
				
			||||||
 | 
						EditDisable            bool   // mattermost, slack, discord, telegram, gitter
 | 
				
			||||||
	IconURL                string // mattermost, slack
 | 
						IconURL                string // mattermost, slack
 | 
				
			||||||
	IgnoreNicks            string // all protocols
 | 
						IgnoreNicks            string // all protocols
 | 
				
			||||||
 | 
						IgnoreMessages         string // all protocols
 | 
				
			||||||
	Jid                    string // xmpp
 | 
						Jid                    string // xmpp
 | 
				
			||||||
	Login                  string // mattermost, matrix
 | 
						Login                  string // mattermost, matrix
 | 
				
			||||||
	Muc                    string // xmpp
 | 
						Muc                    string // xmpp
 | 
				
			||||||
@@ -49,23 +55,26 @@ type Protocol struct {
 | 
				
			|||||||
	NickServNick           string // IRC
 | 
						NickServNick           string // IRC
 | 
				
			||||||
	NickServPassword       string // IRC
 | 
						NickServPassword       string // IRC
 | 
				
			||||||
	NicksPerRow            int    // mattermost, slack
 | 
						NicksPerRow            int    // mattermost, slack
 | 
				
			||||||
 | 
						NoHomeServerSuffix     bool   // matrix
 | 
				
			||||||
	NoTLS                  bool   // mattermost
 | 
						NoTLS                  bool   // mattermost
 | 
				
			||||||
	Password               string // IRC,mattermost,XMPP,matrix
 | 
						Password               string // IRC,mattermost,XMPP,matrix
 | 
				
			||||||
	PrefixMessagesWithNick bool   // mattemost, slack
 | 
						PrefixMessagesWithNick bool   // mattemost, slack
 | 
				
			||||||
	Protocol               string //all protocols
 | 
						Protocol               string //all protocols
 | 
				
			||||||
	MessageQueue           int    // IRC, size of message queue for flood control
 | 
						MessageQueue           int    // IRC, size of message queue for flood control
 | 
				
			||||||
	MessageDelay           int    // IRC, time in millisecond to wait between messages
 | 
						MessageDelay           int    // IRC, time in millisecond to wait between messages
 | 
				
			||||||
 | 
						MessageLength          int    // IRC, max length of a message allowed
 | 
				
			||||||
	MessageFormat          string // telegram
 | 
						MessageFormat          string // telegram
 | 
				
			||||||
	RemoteNickFormat       string // all protocols
 | 
						RemoteNickFormat       string // all protocols
 | 
				
			||||||
	Server                 string // IRC,mattermost,XMPP,discord
 | 
						Server                 string // IRC,mattermost,XMPP,discord
 | 
				
			||||||
	ShowJoinPart           bool   // all protocols
 | 
						ShowJoinPart           bool   // all protocols
 | 
				
			||||||
	SkipTLSVerify          bool   // IRC, mattermost
 | 
						SkipTLSVerify          bool   // IRC, mattermost
 | 
				
			||||||
	Team                   string // mattermost
 | 
						Team                   string // mattermost
 | 
				
			||||||
	Token                  string // gitter, slack, discord
 | 
						Token                  string // gitter, slack, discord, api
 | 
				
			||||||
	URL                    string // mattermost, slack, matrix
 | 
						URL                    string // mattermost, slack, matrix
 | 
				
			||||||
	UseAPI                 bool   // mattermost, slack
 | 
						UseAPI                 bool   // mattermost, slack
 | 
				
			||||||
	UseSASL                bool   // IRC
 | 
						UseSASL                bool   // IRC
 | 
				
			||||||
	UseTLS                 bool   // IRC
 | 
						UseTLS                 bool   // IRC
 | 
				
			||||||
 | 
						UseFirstName           bool   // telegram
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ChannelOptions struct {
 | 
					type ChannelOptions struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import (
 | 
				
			|||||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
						"github.com/42wim/matterbridge/bridge/config"
 | 
				
			||||||
	log "github.com/Sirupsen/logrus"
 | 
						log "github.com/Sirupsen/logrus"
 | 
				
			||||||
	"github.com/bwmarrin/discordgo"
 | 
						"github.com/bwmarrin/discordgo"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -51,6 +52,7 @@ func (b *bdiscord) Connect() error {
 | 
				
			|||||||
	flog.Info("Connection succeeded")
 | 
						flog.Info("Connection succeeded")
 | 
				
			||||||
	b.c.AddHandler(b.messageCreate)
 | 
						b.c.AddHandler(b.messageCreate)
 | 
				
			||||||
	b.c.AddHandler(b.memberUpdate)
 | 
						b.c.AddHandler(b.memberUpdate)
 | 
				
			||||||
 | 
						b.c.AddHandler(b.messageUpdate)
 | 
				
			||||||
	err = b.c.Open()
 | 
						err = b.c.Open()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		flog.Debugf("%#v", err)
 | 
							flog.Debugf("%#v", err)
 | 
				
			||||||
@@ -103,6 +105,18 @@ func (b *bdiscord) Send(msg config.Message) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
 | 
				
			||||||
 | 
						if b.Config.EditDisable {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// only when message is actually edited
 | 
				
			||||||
 | 
						if m.Message.EditedTimestamp != "" {
 | 
				
			||||||
 | 
							flog.Debugf("Sending edit message")
 | 
				
			||||||
 | 
							m.Content = m.Content + b.Config.EditSuffix
 | 
				
			||||||
 | 
							b.messageCreate(s, (*discordgo.MessageCreate)(m))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
 | 
					func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
 | 
				
			||||||
	// not relay our own messages
 | 
						// not relay our own messages
 | 
				
			||||||
	if m.Author.Username == b.Nick {
 | 
						if m.Author.Username == b.Nick {
 | 
				
			||||||
@@ -125,8 +139,11 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
 | 
				
			|||||||
	if len(m.MentionRoles) > 0 {
 | 
						if len(m.MentionRoles) > 0 {
 | 
				
			||||||
		m.Message.Content = b.replaceRoleMentions(m.Message.Content)
 | 
							m.Message.Content = b.replaceRoleMentions(m.Message.Content)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						m.Message.Content = b.stripCustomoji(m.Message.Content)
 | 
				
			||||||
 | 
						m.Message.Content = b.replaceChannelMentions(m.Message.Content)
 | 
				
			||||||
	b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
 | 
						b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
 | 
				
			||||||
		Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
 | 
							Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg",
 | 
				
			||||||
 | 
							UserID: m.Author.ID}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
 | 
					func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
 | 
				
			||||||
@@ -143,18 +160,21 @@ func (b *bdiscord) getNick(user *discordgo.User) string {
 | 
				
			|||||||
	b.Lock()
 | 
						b.Lock()
 | 
				
			||||||
	defer b.Unlock()
 | 
						defer b.Unlock()
 | 
				
			||||||
	if _, ok := b.userMemberMap[user.ID]; ok {
 | 
						if _, ok := b.userMemberMap[user.ID]; ok {
 | 
				
			||||||
		if b.userMemberMap[user.ID].Nick != "" {
 | 
							if b.userMemberMap[user.ID] != nil {
 | 
				
			||||||
			// only return if nick is set
 | 
								if b.userMemberMap[user.ID].Nick != "" {
 | 
				
			||||||
			return b.userMemberMap[user.ID].Nick
 | 
									// only return if nick is set
 | 
				
			||||||
 | 
									return b.userMemberMap[user.ID].Nick
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// otherwise return username
 | 
				
			||||||
 | 
								return user.Username
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// otherwise return username
 | 
					 | 
				
			||||||
		return user.Username
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// if we didn't find nick, search for it
 | 
						// if we didn't find nick, search for it
 | 
				
			||||||
	b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
 | 
						member, err := b.c.GuildMember(b.guildID, user.ID)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return user.Username
 | 
							return user.Username
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						b.userMemberMap[user.ID] = member
 | 
				
			||||||
	// only return if nick is set
 | 
						// only return if nick is set
 | 
				
			||||||
	if b.userMemberMap[user.ID].Nick != "" {
 | 
						if b.userMemberMap[user.ID].Nick != "" {
 | 
				
			||||||
		return b.userMemberMap[user.ID].Nick
 | 
							return b.userMemberMap[user.ID].Nick
 | 
				
			||||||
@@ -195,3 +215,28 @@ func (b *bdiscord) replaceRoleMentions(text string) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return text
 | 
						return text
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *bdiscord) replaceChannelMentions(text string) string {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						re := regexp.MustCompile("<#[0-9]+>")
 | 
				
			||||||
 | 
						text = re.ReplaceAllStringFunc(text, func(m string) string {
 | 
				
			||||||
 | 
							channel := b.getChannelName(m[2 : len(m)-1])
 | 
				
			||||||
 | 
							// if at first don't succeed, try again
 | 
				
			||||||
 | 
							if channel == "" {
 | 
				
			||||||
 | 
								b.Channels, err = b.c.GuildChannels(b.guildID)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return "#unknownchannel"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								channel = b.getChannelName(m[2 : len(m)-1])
 | 
				
			||||||
 | 
								return "#" + channel
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return "#" + channel
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return text
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *bdiscord) stripCustomoji(text string) string {
 | 
				
			||||||
 | 
						// <:doge:302803592035958784>
 | 
				
			||||||
 | 
						re := regexp.MustCompile("<(:.*?:)[0-9]+>")
 | 
				
			||||||
 | 
						return re.ReplaceAllString(text, `$1`)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,7 @@ func (b *Bgitter) JoinChannel(channel string) error {
 | 
				
			|||||||
				if !strings.HasSuffix(ev.Message.Text, "") {
 | 
									if !strings.HasSuffix(ev.Message.Text, "") {
 | 
				
			||||||
					flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account)
 | 
										flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account)
 | 
				
			||||||
					b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room,
 | 
										b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room,
 | 
				
			||||||
						Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username)}
 | 
											Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case *gitter.GitterConnectionClosed:
 | 
								case *gitter.GitterConnectionClosed:
 | 
				
			||||||
				flog.Errorf("connection with gitter closed for room %s", room)
 | 
									flog.Errorf("connection with gitter closed for room %s", room)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,14 +15,15 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Birc struct {
 | 
					type Birc struct {
 | 
				
			||||||
	i         *irc.Connection
 | 
						i               *irc.Connection
 | 
				
			||||||
	Nick      string
 | 
						Nick            string
 | 
				
			||||||
	names     map[string][]string
 | 
						names           map[string][]string
 | 
				
			||||||
	Config    *config.Protocol
 | 
						Config          *config.Protocol
 | 
				
			||||||
	Remote    chan config.Message
 | 
						Remote          chan config.Message
 | 
				
			||||||
	connected chan struct{}
 | 
						connected       chan struct{}
 | 
				
			||||||
	Local     chan config.Message // local queue for flood control
 | 
						Local           chan config.Message // local queue for flood control
 | 
				
			||||||
	Account   string
 | 
						Account         string
 | 
				
			||||||
 | 
						FirstConnection bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var flog *log.Entry
 | 
					var flog *log.Entry
 | 
				
			||||||
@@ -46,6 +47,10 @@ func New(cfg config.Protocol, account string, c chan config.Message) *Birc {
 | 
				
			|||||||
	if b.Config.MessageQueue == 0 {
 | 
						if b.Config.MessageQueue == 0 {
 | 
				
			||||||
		b.Config.MessageQueue = 30
 | 
							b.Config.MessageQueue = 30
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if b.Config.MessageLength == 0 {
 | 
				
			||||||
 | 
							b.Config.MessageLength = 400
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b.FirstConnection = true
 | 
				
			||||||
	return b
 | 
						return b
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -71,6 +76,8 @@ func (b *Birc) Connect() error {
 | 
				
			|||||||
	i.SASLLogin = b.Config.NickServNick
 | 
						i.SASLLogin = b.Config.NickServNick
 | 
				
			||||||
	i.SASLPassword = b.Config.NickServPassword
 | 
						i.SASLPassword = b.Config.NickServPassword
 | 
				
			||||||
	i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.SkipTLSVerify}
 | 
						i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.SkipTLSVerify}
 | 
				
			||||||
 | 
						i.KeepAlive = time.Minute
 | 
				
			||||||
 | 
						i.PingFreq = time.Minute
 | 
				
			||||||
	if b.Config.Password != "" {
 | 
						if b.Config.Password != "" {
 | 
				
			||||||
		i.Password = b.Config.Password
 | 
							i.Password = b.Config.Password
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -87,6 +94,14 @@ func (b *Birc) Connect() error {
 | 
				
			|||||||
		return fmt.Errorf("connection timed out")
 | 
							return fmt.Errorf("connection timed out")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i.Debug = false
 | 
						i.Debug = false
 | 
				
			||||||
 | 
						// clear on reconnects
 | 
				
			||||||
 | 
						i.ClearCallback(ircm.RPL_WELCOME)
 | 
				
			||||||
 | 
						i.AddCallback(ircm.RPL_WELCOME, func(event *irc.Event) {
 | 
				
			||||||
 | 
							b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: "", Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
 | 
				
			||||||
 | 
							// set our correct nick on reconnect if necessary
 | 
				
			||||||
 | 
							b.Nick = event.Nick
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						go i.Loop()
 | 
				
			||||||
	go b.doSend()
 | 
						go b.doSend()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -109,9 +124,11 @@ func (b *Birc) Send(msg config.Message) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if strings.HasPrefix(msg.Text, "!") {
 | 
						if strings.HasPrefix(msg.Text, "!") {
 | 
				
			||||||
		b.Command(&msg)
 | 
							b.Command(&msg)
 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, text := range strings.Split(msg.Text, "\n") {
 | 
						for _, text := range strings.Split(msg.Text, "\n") {
 | 
				
			||||||
 | 
							if len(text) > b.Config.MessageLength {
 | 
				
			||||||
 | 
								text = text[:b.Config.MessageLength] + " <message clipped>"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if len(b.Local) < b.Config.MessageQueue {
 | 
							if len(b.Local) < b.Config.MessageQueue {
 | 
				
			||||||
			if len(b.Local) == b.Config.MessageQueue-1 {
 | 
								if len(b.Local) == b.Config.MessageQueue-1 {
 | 
				
			||||||
				text = text + " <message clipped>"
 | 
									text = text + " <message clipped>"
 | 
				
			||||||
@@ -167,14 +184,19 @@ func (b *Birc) handleNewConnection(event *irc.Event) {
 | 
				
			|||||||
	i.AddCallback("JOIN", b.handleJoinPart)
 | 
						i.AddCallback("JOIN", b.handleJoinPart)
 | 
				
			||||||
	i.AddCallback("PART", b.handleJoinPart)
 | 
						i.AddCallback("PART", b.handleJoinPart)
 | 
				
			||||||
	i.AddCallback("QUIT", b.handleJoinPart)
 | 
						i.AddCallback("QUIT", b.handleJoinPart)
 | 
				
			||||||
 | 
						i.AddCallback("KICK", b.handleJoinPart)
 | 
				
			||||||
	i.AddCallback("*", b.handleOther)
 | 
						i.AddCallback("*", b.handleOther)
 | 
				
			||||||
	// we are now fully connected
 | 
						// we are now fully connected
 | 
				
			||||||
	b.connected <- struct{}{}
 | 
						b.connected <- struct{}{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Birc) handleJoinPart(event *irc.Event) {
 | 
					func (b *Birc) handleJoinPart(event *irc.Event) {
 | 
				
			||||||
	flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
 | 
					 | 
				
			||||||
	channel := event.Arguments[0]
 | 
						channel := event.Arguments[0]
 | 
				
			||||||
 | 
						if event.Code == "KICK" {
 | 
				
			||||||
 | 
							flog.Infof("Got kicked from %s by %s", channel, event.Nick)
 | 
				
			||||||
 | 
							b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if event.Code == "QUIT" {
 | 
						if event.Code == "QUIT" {
 | 
				
			||||||
		if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") {
 | 
							if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") {
 | 
				
			||||||
			flog.Infof("%s reconnecting ..", b.Account)
 | 
								flog.Infof("%s reconnecting ..", b.Account)
 | 
				
			||||||
@@ -182,7 +204,11 @@ func (b *Birc) handleJoinPart(event *irc.Event) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
 | 
						if event.Nick != b.Nick {
 | 
				
			||||||
 | 
							flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
 | 
				
			||||||
 | 
							b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	flog.Debugf("handle %#v", event)
 | 
						flog.Debugf("handle %#v", event)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,6 +229,11 @@ func (b *Birc) handleOther(event *irc.Event) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Birc) handlePrivMsg(event *irc.Event) {
 | 
					func (b *Birc) handlePrivMsg(event *irc.Event) {
 | 
				
			||||||
 | 
						b.Nick = b.i.GetNick()
 | 
				
			||||||
 | 
						// freenode doesn't send 001 as first reply
 | 
				
			||||||
 | 
						if event.Code == "NOTICE" {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// don't forward queries to the bot
 | 
						// don't forward queries to the bot
 | 
				
			||||||
	if event.Arguments[0] == b.Nick {
 | 
						if event.Arguments[0] == b.Nick {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -221,7 +252,7 @@ func (b *Birc) handlePrivMsg(event *irc.Event) {
 | 
				
			|||||||
	re := regexp.MustCompile(`[[:cntrl:]](\d+,|)\d+`)
 | 
						re := regexp.MustCompile(`[[:cntrl:]](\d+,|)\d+`)
 | 
				
			||||||
	msg = re.ReplaceAllString(msg, "")
 | 
						msg = re.ReplaceAllString(msg, "")
 | 
				
			||||||
	flog.Debugf("Sending message from %s on %s to gateway", event.Arguments[0], b.Account)
 | 
						flog.Debugf("Sending message from %s on %s to gateway", event.Arguments[0], b.Account)
 | 
				
			||||||
	b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Account: b.Account}
 | 
						b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Account: b.Account, UserID: event.User + "@" + event.Host}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Birc) handleTopicWhoTime(event *irc.Event) {
 | 
					func (b *Birc) handleTopicWhoTime(event *irc.Event) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,12 @@
 | 
				
			|||||||
package bmatrix
 | 
					package bmatrix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
						"github.com/42wim/matterbridge/bridge/config"
 | 
				
			||||||
	log "github.com/Sirupsen/logrus"
 | 
						log "github.com/Sirupsen/logrus"
 | 
				
			||||||
	matrix "github.com/matrix-org/gomatrix"
 | 
						matrix "github.com/matrix-org/gomatrix"
 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Bmatrix struct {
 | 
					type Bmatrix struct {
 | 
				
			||||||
@@ -101,8 +103,13 @@ func (b *Bmatrix) handlematrix() error {
 | 
				
			|||||||
				flog.Debugf("Unknown room %s", ev.RoomID)
 | 
									flog.Debugf("Unknown room %s", ev.RoomID)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								username := ev.Sender[1:]
 | 
				
			||||||
 | 
								if b.Config.NoHomeServerSuffix {
 | 
				
			||||||
 | 
									re := regexp.MustCompile("(.*?):.*")
 | 
				
			||||||
 | 
									username = re.ReplaceAllString(username, `$1`)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
 | 
								flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
 | 
				
			||||||
			b.Remote <- config.Message{Username: ev.Sender, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account}
 | 
								b.Remote <- config.Message{Username: username, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account, UserID: ev.Sender}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		flog.Debugf("Received: %#v", ev)
 | 
							flog.Debugf("Received: %#v", ev)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ type MMMessage struct {
 | 
				
			|||||||
	Text     string
 | 
						Text     string
 | 
				
			||||||
	Channel  string
 | 
						Channel  string
 | 
				
			||||||
	Username string
 | 
						Username string
 | 
				
			||||||
 | 
						UserID   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Bmattermost struct {
 | 
					type Bmattermost struct {
 | 
				
			||||||
@@ -72,6 +73,7 @@ func (b *Bmattermost) Connect() error {
 | 
				
			|||||||
		flog.Info("Connection succeeded")
 | 
							flog.Info("Connection succeeded")
 | 
				
			||||||
		b.TeamId = b.mc.GetTeamId()
 | 
							b.TeamId = b.mc.GetTeamId()
 | 
				
			||||||
		go b.mc.WsReceiver()
 | 
							go b.mc.WsReceiver()
 | 
				
			||||||
 | 
							go b.mc.StatusLoop()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go b.handleMatter()
 | 
						go b.handleMatter()
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
@@ -100,6 +102,7 @@ func (b *Bmattermost) Send(msg config.Message) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if !b.Config.UseAPI {
 | 
						if !b.Config.UseAPI {
 | 
				
			||||||
		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
 | 
							matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
 | 
				
			||||||
 | 
							matterMessage.IconURL = msg.Avatar
 | 
				
			||||||
		matterMessage.Channel = channel
 | 
							matterMessage.Channel = channel
 | 
				
			||||||
		matterMessage.UserName = nick
 | 
							matterMessage.UserName = nick
 | 
				
			||||||
		matterMessage.Type = ""
 | 
							matterMessage.Type = ""
 | 
				
			||||||
@@ -125,20 +128,36 @@ func (b *Bmattermost) handleMatter() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	for message := range mchan {
 | 
						for message := range mchan {
 | 
				
			||||||
		flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
 | 
							flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
 | 
				
			||||||
		b.Remote <- config.Message{Text: message.Text, Username: message.Username, Channel: message.Channel, Account: b.Account}
 | 
							b.Remote <- config.Message{Text: message.Text, Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
 | 
					func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
 | 
				
			||||||
	for message := range b.mc.MessageChan {
 | 
						for message := range b.mc.MessageChan {
 | 
				
			||||||
 | 
							flog.Debugf("%#v", message.Raw.Data)
 | 
				
			||||||
 | 
							if message.Type == "system_join_leave" ||
 | 
				
			||||||
 | 
								message.Type == "system_join_channel" ||
 | 
				
			||||||
 | 
								message.Type == "system_leave_channel" {
 | 
				
			||||||
 | 
								flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
 | 
				
			||||||
 | 
								b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (message.Raw.Event == "post_edited") && b.Config.EditDisable {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		// do not post our own messages back to irc
 | 
							// do not post our own messages back to irc
 | 
				
			||||||
		// only listen to message from our team
 | 
							// only listen to message from our team
 | 
				
			||||||
		if message.Raw.Event == "posted" && b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
 | 
							if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited") &&
 | 
				
			||||||
 | 
								b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
 | 
				
			||||||
			flog.Debugf("Receiving from matterclient %#v", message)
 | 
								flog.Debugf("Receiving from matterclient %#v", message)
 | 
				
			||||||
			m := &MMMessage{}
 | 
								m := &MMMessage{}
 | 
				
			||||||
 | 
								m.UserID = message.UserID
 | 
				
			||||||
			m.Username = message.Username
 | 
								m.Username = message.Username
 | 
				
			||||||
			m.Channel = message.Channel
 | 
								m.Channel = message.Channel
 | 
				
			||||||
			m.Text = message.Text
 | 
								m.Text = message.Text
 | 
				
			||||||
 | 
								if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
 | 
				
			||||||
 | 
									m.Text = message.Text + b.Config.EditSuffix
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if len(message.Post.FileIds) > 0 {
 | 
								if len(message.Post.FileIds) > 0 {
 | 
				
			||||||
				for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
 | 
									for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
 | 
				
			||||||
					m.Text = m.Text + "\n" + link
 | 
										m.Text = m.Text + "\n" + link
 | 
				
			||||||
@@ -154,6 +173,7 @@ func (b *Bmattermost) handleMatterHook(mchan chan *MMMessage) {
 | 
				
			|||||||
		message := b.mh.Receive()
 | 
							message := b.mh.Receive()
 | 
				
			||||||
		flog.Debugf("Receiving from matterhook %#v", message)
 | 
							flog.Debugf("Receiving from matterhook %#v", message)
 | 
				
			||||||
		m := &MMMessage{}
 | 
							m := &MMMessage{}
 | 
				
			||||||
 | 
							m.UserID = message.UserID
 | 
				
			||||||
		m.Username = message.UserName
 | 
							m.Username = message.UserName
 | 
				
			||||||
		m.Text = message.Text
 | 
							m.Text = message.Text
 | 
				
			||||||
		m.Channel = message.ChannelName
 | 
							m.Channel = message.ChannelName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,6 +82,6 @@ func (b *Brocketchat) handleRocketHook() {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		flog.Debugf("Sending message from %s on %s to gateway", message.UserName, b.Account)
 | 
							flog.Debugf("Sending message from %s on %s to gateway", message.UserName, b.Account)
 | 
				
			||||||
		b.Remote <- config.Message{Text: message.Text, Username: message.UserName, Channel: message.ChannelName, Account: b.Account}
 | 
							b.Remote <- config.Message{Text: message.Text, Username: message.UserName, Channel: message.ChannelName, Account: b.Account, UserID: message.UserID}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ type MMMessage struct {
 | 
				
			|||||||
	Text     string
 | 
						Text     string
 | 
				
			||||||
	Channel  string
 | 
						Channel  string
 | 
				
			||||||
	Username string
 | 
						Username string
 | 
				
			||||||
 | 
						UserID   string
 | 
				
			||||||
	Raw      *slack.MessageEvent
 | 
						Raw      *slack.MessageEvent
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,7 +80,9 @@ func (b *Bslack) JoinChannel(channel string) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		_, err := b.sc.JoinChannel(channel)
 | 
							_, err := b.sc.JoinChannel(channel)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								if err.Error() != "name_taken" {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
@@ -87,9 +90,6 @@ func (b *Bslack) JoinChannel(channel string) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (b *Bslack) Send(msg config.Message) error {
 | 
					func (b *Bslack) Send(msg config.Message) error {
 | 
				
			||||||
	flog.Debugf("Receiving %#v", msg)
 | 
						flog.Debugf("Receiving %#v", msg)
 | 
				
			||||||
	if msg.Account == b.Account {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	nick := msg.Username
 | 
						nick := msg.Username
 | 
				
			||||||
	message := msg.Text
 | 
						message := msg.Text
 | 
				
			||||||
	channel := msg.Channel
 | 
						channel := msg.Channel
 | 
				
			||||||
@@ -186,7 +186,7 @@ func (b *Bslack) handleSlack() {
 | 
				
			|||||||
		texts := strings.Split(message.Text, "\n")
 | 
							texts := strings.Split(message.Text, "\n")
 | 
				
			||||||
		for _, text := range texts {
 | 
							for _, text := range texts {
 | 
				
			||||||
			flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
 | 
								flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
 | 
				
			||||||
			b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username)}
 | 
								b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -199,6 +199,11 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
 | 
				
			|||||||
			// ignore first message
 | 
								// ignore first message
 | 
				
			||||||
			if count > 0 {
 | 
								if count > 0 {
 | 
				
			||||||
				flog.Debugf("Receiving from slackclient %#v", ev)
 | 
									flog.Debugf("Receiving from slackclient %#v", ev)
 | 
				
			||||||
 | 
									if !b.Config.EditDisable && ev.SubMessage != nil {
 | 
				
			||||||
 | 
										flog.Debugf("SubMessage %#v", ev.SubMessage)
 | 
				
			||||||
 | 
										ev.User = ev.SubMessage.User
 | 
				
			||||||
 | 
										ev.Text = ev.SubMessage.Text + b.Config.EditSuffix
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				// use our own func because rtm.GetChannelInfo doesn't work for private channels
 | 
									// use our own func because rtm.GetChannelInfo doesn't work for private channels
 | 
				
			||||||
				channel, err := b.getChannelByID(ev.Channel)
 | 
									channel, err := b.getChannelByID(ev.Channel)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
@@ -209,6 +214,7 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
 | 
				
			|||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				m := &MMMessage{}
 | 
									m := &MMMessage{}
 | 
				
			||||||
 | 
									m.UserID = user.ID
 | 
				
			||||||
				m.Username = user.Name
 | 
									m.Username = user.Name
 | 
				
			||||||
				m.Channel = channel.Name
 | 
									m.Channel = channel.Name
 | 
				
			||||||
				m.Text = ev.Text
 | 
									m.Text = ev.Text
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,29 +76,36 @@ func (b *Btelegram) Send(msg config.Message) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
					func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
				
			||||||
	username := ""
 | 
					 | 
				
			||||||
	text := ""
 | 
					 | 
				
			||||||
	channel := ""
 | 
					 | 
				
			||||||
	for update := range updates {
 | 
						for update := range updates {
 | 
				
			||||||
		var message *tgbotapi.Message
 | 
							var message *tgbotapi.Message
 | 
				
			||||||
 | 
							username := ""
 | 
				
			||||||
 | 
							channel := ""
 | 
				
			||||||
 | 
							text := ""
 | 
				
			||||||
		// handle channels
 | 
							// handle channels
 | 
				
			||||||
		if update.ChannelPost != nil {
 | 
							if update.ChannelPost != nil {
 | 
				
			||||||
			message = update.ChannelPost
 | 
								message = update.ChannelPost
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if update.EditedChannelPost != nil {
 | 
							if update.EditedChannelPost != nil && !b.Config.EditDisable {
 | 
				
			||||||
			message = update.EditedChannelPost
 | 
								message = update.EditedChannelPost
 | 
				
			||||||
 | 
								message.Text = message.Text + b.Config.EditSuffix
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// handle groups
 | 
							// handle groups
 | 
				
			||||||
		if update.Message != nil {
 | 
							if update.Message != nil {
 | 
				
			||||||
			message = update.Message
 | 
								message = update.Message
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if update.EditedMessage != nil {
 | 
							if update.EditedMessage != nil && !b.Config.EditDisable {
 | 
				
			||||||
			message = update.EditedMessage
 | 
								message = update.EditedMessage
 | 
				
			||||||
 | 
								message.Text = message.Text + b.Config.EditSuffix
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if message.From != nil {
 | 
							if message.From != nil {
 | 
				
			||||||
			username = message.From.FirstName
 | 
								if b.Config.UseFirstName {
 | 
				
			||||||
 | 
									username = message.From.FirstName
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if username == "" {
 | 
								if username == "" {
 | 
				
			||||||
				username = message.From.UserName
 | 
									username = message.From.UserName
 | 
				
			||||||
 | 
									if username == "" {
 | 
				
			||||||
 | 
										username = message.From.FirstName
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			text = message.Text
 | 
								text = message.Text
 | 
				
			||||||
			channel = strconv.FormatInt(message.Chat.ID, 10)
 | 
								channel = strconv.FormatInt(message.Chat.ID, 10)
 | 
				
			||||||
@@ -107,9 +114,31 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
 | 
				
			|||||||
		if username == "" {
 | 
							if username == "" {
 | 
				
			||||||
			username = "unknown"
 | 
								username = "unknown"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if message.Sticker != nil {
 | 
				
			||||||
 | 
								text = text + " " + b.getFileDirectURL(message.Sticker.FileID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if message.Video != nil {
 | 
				
			||||||
 | 
								text = text + " " + b.getFileDirectURL(message.Video.FileID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if message.Photo != nil {
 | 
				
			||||||
 | 
								photos := *message.Photo
 | 
				
			||||||
 | 
								// last photo is the biggest
 | 
				
			||||||
 | 
								text = text + " " + b.getFileDirectURL(photos[len(photos)-1].FileID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if message.Document != nil {
 | 
				
			||||||
 | 
								text = text + " " + message.Document.FileName + " : " + b.getFileDirectURL(message.Document.FileID)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if text != "" {
 | 
							if text != "" {
 | 
				
			||||||
			flog.Debugf("Sending message from %s on %s to gateway", username, b.Account)
 | 
								flog.Debugf("Sending message from %s on %s to gateway", username, b.Account)
 | 
				
			||||||
			b.Remote <- config.Message{Username: username, Text: text, Channel: channel, Account: b.Account}
 | 
								b.Remote <- config.Message{Username: username, Text: text, Channel: channel, Account: b.Account, UserID: strconv.Itoa(message.From.ID)}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *Btelegram) getFileDirectURL(id string) string {
 | 
				
			||||||
 | 
						res, err := b.c.GetFileDirectURL(id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,7 +119,7 @@ func (b *Bxmpp) handleXmpp() error {
 | 
				
			|||||||
			var channel, nick string
 | 
								var channel, nick string
 | 
				
			||||||
			if v.Type == "groupchat" {
 | 
								if v.Type == "groupchat" {
 | 
				
			||||||
				s := strings.Split(v.Remote, "@")
 | 
									s := strings.Split(v.Remote, "@")
 | 
				
			||||||
				if len(s) == 2 {
 | 
									if len(s) >= 2 {
 | 
				
			||||||
					channel = s[0]
 | 
										channel = s[0]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				s = strings.Split(s[1], "/")
 | 
									s = strings.Split(s[1], "/")
 | 
				
			||||||
@@ -128,7 +128,7 @@ func (b *Bxmpp) handleXmpp() error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				if nick != b.Config.Nick && v.Stamp == nodelay && v.Text != "" {
 | 
									if nick != b.Config.Nick && v.Stamp == nodelay && v.Text != "" {
 | 
				
			||||||
					flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account)
 | 
										flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account)
 | 
				
			||||||
					b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account}
 | 
										b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account, UserID: v.Remote}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case xmpp.Presence:
 | 
							case xmpp.Presence:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										90
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										90
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,8 +1,94 @@
 | 
				
			|||||||
# v0.11.0-dev
 | 
					# v0.15.0
 | 
				
			||||||
## New features
 | 
					## New features
 | 
				
			||||||
* general: reusing the same account on multiple gateways now also reuses the connection. 
 | 
					* general: add option IgnoreMessages for all protocols (see mattebridge.toml.sample)
 | 
				
			||||||
 | 
					  Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					  e.g. IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					* telegram: add support for sticker/video/photo/document #184
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Changes
 | 
				
			||||||
 | 
					* api: add userid to each message #200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* discord: fix crash in memberupdate #198
 | 
				
			||||||
 | 
					* mattermost: Fix incorrect behaviour of EditDisable (mattermost). Fixes #197 
 | 
				
			||||||
 | 
					* irc: Do not relay join/part of ourselves (irc). Closes #190 
 | 
				
			||||||
 | 
					* irc: make reconnections more robust. #153
 | 
				
			||||||
 | 
					* gitter: update library, fixes possible crash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.14.0
 | 
				
			||||||
 | 
					## New features
 | 
				
			||||||
 | 
					* api: add token authentication
 | 
				
			||||||
 | 
					* mattermost: add support for mattermost 3.10.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Changes
 | 
				
			||||||
 | 
					* api: gateway name is added in JSON messages
 | 
				
			||||||
 | 
					* api: lowercase JSON keys
 | 
				
			||||||
 | 
					* api: channel name isn't needed in config #195
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* discord: Add hashtag to channelname (when translating from id) (discord)
 | 
				
			||||||
 | 
					* mattermost: Fix a panic. #186
 | 
				
			||||||
 | 
					* mattermost: use teamid cache if possible. Fixes a panic
 | 
				
			||||||
 | 
					* api: post valid json. #185
 | 
				
			||||||
 | 
					* api: allow reuse of api in different gateways. #189
 | 
				
			||||||
 | 
					* general: Fix utf-8 issues for {NOPINGNICK}. #193
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.13.0
 | 
				
			||||||
 | 
					## New features
 | 
				
			||||||
 | 
					* irc: Limit message length. ```MessageLength=400```
 | 
				
			||||||
 | 
					  Maximum length of message sent to irc server. If it exceeds <message clipped> will be add to the message.
 | 
				
			||||||
 | 
					* irc: Add NOPINGNICK option. 
 | 
				
			||||||
 | 
					  The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged.   
 | 
				
			||||||
 | 
					  See https://github.com/42wim/matterbridge/issues/175 for more information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* slack: Fix sending to different channels on same account (slack). Closes #177
 | 
				
			||||||
 | 
					* telegram: Fix incorrect usernames being sent. Closes #181
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.12.1
 | 
				
			||||||
 | 
					## New features
 | 
				
			||||||
 | 
					* telegram: Add UseFirstName option (telegram). Closes #144
 | 
				
			||||||
 | 
					* matrix: Add NoHomeServerSuffix. Option to disable homeserver on username (matrix). Closes #160.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* xmpp: Add Compatibility for Cisco Jabber (xmpp) (#166)
 | 
				
			||||||
 | 
					* irc: Fix JoinChannel argument to use IRC channel key (#172)
 | 
				
			||||||
 | 
					* discord: Fix possible crash on nil (discord)
 | 
				
			||||||
 | 
					* discord: Replace long ids in channel metions (discord). Fixes #174
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.12.0
 | 
				
			||||||
 | 
					## Changes
 | 
				
			||||||
 | 
					* general: edited messages are now being sent by default on discord/mattermost/telegram/slack. See "New Features"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## New features
 | 
				
			||||||
 | 
					* general: add support for edited messages. 
 | 
				
			||||||
 | 
					  Add new keyword EditDisable (false/true), default false. Which means by default edited messages will be sent to other bridges.
 | 
				
			||||||
 | 
					  Add new keyword EditSuffix , default "". You can change this eg to "(edited)", this will be appended to every edit message.
 | 
				
			||||||
 | 
					* mattermost: support mattermost v3.9.x
 | 
				
			||||||
 | 
					* general: Add support for HTTP{S}_PROXY env variables (#162)
 | 
				
			||||||
 | 
					* discord: Strip custom emoji metadata (discord). Closes #148
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* slack: Ignore error on private channel join (slack) Fixes #150 
 | 
				
			||||||
 | 
					* mattermost: fix crash on reconnects when server is down. Closes #163
 | 
				
			||||||
 | 
					* irc: Relay messages starting with ! (irc). Closes #164
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# v0.11.0
 | 
				
			||||||
 | 
					## New features
 | 
				
			||||||
 | 
					* general: reusing the same account on multiple gateways now also reuses the connection.
 | 
				
			||||||
  This is particuarly useful for irc. See #87
 | 
					  This is particuarly useful for irc. See #87
 | 
				
			||||||
* general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration
 | 
					* general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration
 | 
				
			||||||
 | 
					* telegram:  Support edited messages (telegram). See #141
 | 
				
			||||||
 | 
					* mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147
 | 
				
			||||||
 | 
					* mattermost: Reconnect on session removal/timeout (mattermost)
 | 
				
			||||||
 | 
					* mattermost: Support mattermost v3.8.x
 | 
				
			||||||
 | 
					* irc:  Rejoin channel when kicked (irc).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Bugfix
 | 
				
			||||||
 | 
					* mattermost: Remove space after nick (mattermost). Closes #142
 | 
				
			||||||
 | 
					* mattermost: Modify iconurl correctly (mattermost).
 | 
				
			||||||
 | 
					* irc: Fix join/leave regression (irc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# v0.10.3
 | 
					# v0.10.3
 | 
				
			||||||
## Bugfix
 | 
					## Bugfix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"github.com/42wim/matterbridge/bridge"
 | 
						"github.com/42wim/matterbridge/bridge"
 | 
				
			||||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
						"github.com/42wim/matterbridge/bridge/config"
 | 
				
			||||||
	log "github.com/Sirupsen/logrus"
 | 
						log "github.com/Sirupsen/logrus"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -103,6 +104,15 @@ func (gw *Gateway) handleReceive() {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if msg.Event == config.EVENT_REJOIN_CHANNELS {
 | 
				
			||||||
 | 
									for _, br := range gw.Bridges {
 | 
				
			||||||
 | 
										if msg.Account == br.Account {
 | 
				
			||||||
 | 
											br.Joined = make(map[string]bool)
 | 
				
			||||||
 | 
											br.JoinChannels()
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if !gw.ignoreMessage(&msg) {
 | 
								if !gw.ignoreMessage(&msg) {
 | 
				
			||||||
				msg.Timestamp = time.Now()
 | 
									msg.Timestamp = time.Now()
 | 
				
			||||||
				for _, br := range gw.Bridges {
 | 
									for _, br := range gw.Bridges {
 | 
				
			||||||
@@ -130,6 +140,9 @@ RECONNECT:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (gw *Gateway) mapChannels() error {
 | 
					func (gw *Gateway) mapChannels() error {
 | 
				
			||||||
	for _, br := range append(gw.MyConfig.Out, gw.MyConfig.InOut...) {
 | 
						for _, br := range append(gw.MyConfig.Out, gw.MyConfig.InOut...) {
 | 
				
			||||||
 | 
							if isApi(br.Account) {
 | 
				
			||||||
 | 
								br.Channel = "api"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ID := br.Channel + br.Account
 | 
							ID := br.Channel + br.Account
 | 
				
			||||||
		_, ok := gw.Channels[ID]
 | 
							_, ok := gw.Channels[ID]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
@@ -144,6 +157,9 @@ func (gw *Gateway) mapChannels() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, br := range append(gw.MyConfig.In, gw.MyConfig.InOut...) {
 | 
						for _, br := range append(gw.MyConfig.In, gw.MyConfig.InOut...) {
 | 
				
			||||||
 | 
							if isApi(br.Account) {
 | 
				
			||||||
 | 
								br.Channel = "api"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ID := br.Channel + br.Account
 | 
							ID := br.Channel + br.Account
 | 
				
			||||||
		_, ok := gw.Channels[ID]
 | 
							_, ok := gw.Channels[ID]
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
@@ -165,7 +181,7 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
 | 
				
			|||||||
		if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
 | 
							if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if channel.Direction == "out" && channel.Account == dest.Account && gw.validGatewayDest(*msg, channel) {
 | 
							if channel.Direction == "out" && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
 | 
				
			||||||
			channels = append(channels, *channel)
 | 
								channels = append(channels, *channel)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -173,19 +189,25 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
 | 
					func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
 | 
				
			||||||
 | 
						// only relay join/part when configged
 | 
				
			||||||
 | 
						if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// broadcast to every out channel (irc QUIT)
 | 
						// broadcast to every out channel (irc QUIT)
 | 
				
			||||||
	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
 | 
						if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
 | 
				
			||||||
		log.Debug("empty channel")
 | 
							log.Debug("empty channel")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	originchannel := msg.Channel
 | 
						originchannel := msg.Channel
 | 
				
			||||||
 | 
						origmsg := msg
 | 
				
			||||||
	for _, channel := range gw.DestChannelFunc(&msg, *dest) {
 | 
						for _, channel := range gw.DestChannelFunc(&msg, *dest) {
 | 
				
			||||||
		// do not send to ourself
 | 
							// do not send to ourself
 | 
				
			||||||
		if channel.ID == getChannelID(msg) {
 | 
							if channel.ID == getChannelID(origmsg) {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
 | 
							log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
 | 
				
			||||||
		msg.Channel = channel.Name
 | 
							msg.Channel = channel.Name
 | 
				
			||||||
 | 
							gw.modifyAvatar(&msg, dest)
 | 
				
			||||||
		gw.modifyUsername(&msg, dest)
 | 
							gw.modifyUsername(&msg, dest)
 | 
				
			||||||
		// for api we need originchannel as channel
 | 
							// for api we need originchannel as channel
 | 
				
			||||||
		if dest.Protocol == "api" {
 | 
							if dest.Protocol == "api" {
 | 
				
			||||||
@@ -209,6 +231,20 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
 | 
				
			|||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// TODO do not compile regexps everytime
 | 
				
			||||||
 | 
						for _, entry := range strings.Fields(gw.Bridges[msg.Account].Config.IgnoreMessages) {
 | 
				
			||||||
 | 
							if entry != "" {
 | 
				
			||||||
 | 
								re, err := regexp.Compile(entry)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Errorf("incorrect regexp %s for %s", entry, msg.Account)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if re.MatchString(msg.Text) {
 | 
				
			||||||
 | 
									log.Debugf("matching %s. ignoring %s from %s", entry, msg.Text, msg.Account)
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -219,23 +255,54 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
 | 
				
			|||||||
	if nick == "" {
 | 
						if nick == "" {
 | 
				
			||||||
		nick = dest.Config.RemoteNickFormat
 | 
							nick = dest.Config.RemoteNickFormat
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if len(msg.Username) > 0 {
 | 
				
			||||||
 | 
							// fix utf-8 issue #193
 | 
				
			||||||
 | 
							i := 0
 | 
				
			||||||
 | 
							for index := range msg.Username {
 | 
				
			||||||
 | 
								if i == 1 {
 | 
				
			||||||
 | 
									i = index
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								i++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
 | 
						nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
 | 
				
			||||||
	nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
 | 
						nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
 | 
				
			||||||
	nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
 | 
						nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
 | 
				
			||||||
	msg.Username = nick
 | 
						msg.Username = nick
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) {
 | 
				
			||||||
 | 
						iconurl := gw.Config.General.IconURL
 | 
				
			||||||
 | 
						if iconurl == "" {
 | 
				
			||||||
 | 
							iconurl = dest.Config.IconURL
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
 | 
				
			||||||
 | 
						if msg.Avatar == "" {
 | 
				
			||||||
 | 
							msg.Avatar = iconurl
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getChannelID(msg config.Message) string {
 | 
					func getChannelID(msg config.Message) string {
 | 
				
			||||||
	return msg.Channel + msg.Account
 | 
						return msg.Channel + msg.Account
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (gw *Gateway) validGatewayDest(msg config.Message, channel *config.ChannelInfo) bool {
 | 
					func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
 | 
				
			||||||
	GIDmap := gw.Channels[getChannelID(msg)].GID
 | 
						GIDmap := gw.Channels[getChannelID(*msg)].GID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// gateway is specified in message (probably from api)
 | 
				
			||||||
 | 
						if msg.Gateway != "" {
 | 
				
			||||||
 | 
							return channel.GID[msg.Gateway]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// check if we are running a samechannelgateway.
 | 
						// check if we are running a samechannelgateway.
 | 
				
			||||||
	// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
 | 
						// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
 | 
				
			||||||
	for k, _ := range GIDmap {
 | 
						for k, _ := range GIDmap {
 | 
				
			||||||
		if channel.SameChannel[k] == true {
 | 
							if channel.SameChannel[k] == true {
 | 
				
			||||||
			if msg.Channel == channel.Name {
 | 
								if msg.Channel == channel.Name {
 | 
				
			||||||
 | 
									// add the gateway to our message
 | 
				
			||||||
 | 
									msg.Gateway = k
 | 
				
			||||||
				return true
 | 
									return true
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
@@ -245,8 +312,17 @@ func (gw *Gateway) validGatewayDest(msg config.Message, channel *config.ChannelI
 | 
				
			|||||||
	// check if we are in the correct gateway
 | 
						// check if we are in the correct gateway
 | 
				
			||||||
	for k, _ := range GIDmap {
 | 
						for k, _ := range GIDmap {
 | 
				
			||||||
		if channel.GID[k] == true {
 | 
							if channel.GID[k] == true {
 | 
				
			||||||
 | 
								// add the gateway to our message
 | 
				
			||||||
 | 
								msg.Gateway = k
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isApi(account string) bool {
 | 
				
			||||||
 | 
						if strings.HasPrefix(account, "api.") {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	version = "0.11.0-dev"
 | 
						version = "0.15.0"
 | 
				
			||||||
	githash string
 | 
						githash string
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +34,6 @@ func main() {
 | 
				
			|||||||
		fmt.Printf("version: %s %s\n", version, githash)
 | 
							fmt.Printf("version: %s %s\n", version, githash)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	flag.Parse()
 | 
					 | 
				
			||||||
	if *flagDebug {
 | 
						if *flagDebug {
 | 
				
			||||||
		log.Info("Enabling debug")
 | 
							log.Info("Enabling debug")
 | 
				
			||||||
		log.SetLevel(log.DebugLevel)
 | 
							log.SetLevel(log.DebugLevel)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#This is configuration for matterbridge.
 | 
					#This is configuration for matterbridge.
 | 
				
			||||||
 | 
					#WARNING: as this file contains credentials, be sure to set correct file permissions
 | 
				
			||||||
###################################################################
 | 
					###################################################################
 | 
				
			||||||
#IRC section
 | 
					#IRC section
 | 
				
			||||||
###################################################################
 | 
					###################################################################
 | 
				
			||||||
@@ -48,23 +49,36 @@ MessageDelay=1300
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#Maximum amount of messages to hold in queue. If queue is full 
 | 
					#Maximum amount of messages to hold in queue. If queue is full 
 | 
				
			||||||
#messages will be dropped. 
 | 
					#messages will be dropped. 
 | 
				
			||||||
#<clipped> will be add to the message that fills the queue.
 | 
					#<message clipped> will be add to the message that fills the queue.
 | 
				
			||||||
#OPTIONAL (default 30)
 | 
					#OPTIONAL (default 30)
 | 
				
			||||||
MessageQueue=30
 | 
					MessageQueue=30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Maximum length of message sent to irc server. If it exceeds
 | 
				
			||||||
 | 
					#<message clipped> will be add to the message.
 | 
				
			||||||
 | 
					#OPTIONAL (default 400)
 | 
				
			||||||
 | 
					MessageLength=400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Nicks you want to ignore. 
 | 
					#Nicks you want to ignore. 
 | 
				
			||||||
#Messages from those users will not be sent to other bridges.
 | 
					#Messages from those users will not be sent to other bridges.
 | 
				
			||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
 | 
					#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
 | 
				
			||||||
 | 
					#The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged. See https://github.com/42wim/matterbridge/issues/175 for more information
 | 
				
			||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,6 +121,12 @@ SkipTLSVerify=true
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -114,7 +134,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -150,6 +171,12 @@ Nick="yourlogin"
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="spammer1 spammer2"
 | 
					IgnoreNicks="spammer1 spammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -157,7 +184,8 @@ IgnoreNicks="spammer1 spammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,9 +225,9 @@ IconURL="http://youricon.png"
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
useAPI=false
 | 
					useAPI=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#The mattermost hostname. 
 | 
					#The mattermost hostname. (do not prefix it with http or https)
 | 
				
			||||||
#REQUIRED (when useAPI=true)
 | 
					#REQUIRED (when useAPI=true)
 | 
				
			||||||
Server="yourmattermostserver.domain"
 | 
					Server="yourmattermostserver.domain" 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Your team on mattermost. 
 | 
					#Your team on mattermost. 
 | 
				
			||||||
#REQUIRED (when useAPI=true)
 | 
					#REQUIRED (when useAPI=true)
 | 
				
			||||||
@@ -238,11 +266,25 @@ NicksPerRow=4
 | 
				
			|||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
PrefixMessagesWithNick=false
 | 
					PrefixMessagesWithNick=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Disable sending of edits to other bridges
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					EditDisable=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Message to be appended to every edited message
 | 
				
			||||||
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
 | 
					EditSuffix=" (edited)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Nicks you want to ignore. 
 | 
					#Nicks you want to ignore. 
 | 
				
			||||||
#Messages from those users will not be sent to other bridges.
 | 
					#Messages from those users will not be sent to other bridges.
 | 
				
			||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -250,7 +292,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -275,6 +318,12 @@ Token="Yourtokenhere"
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -282,7 +331,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -342,6 +392,14 @@ NickFormatter="plain"
 | 
				
			|||||||
#OPTIONAL (default 4)
 | 
					#OPTIONAL (default 4)
 | 
				
			||||||
NicksPerRow=4
 | 
					NicksPerRow=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Disable sending of edits to other bridges
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					EditDisable=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Message to be appended to every edited message
 | 
				
			||||||
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
 | 
					EditSuffix=" (edited)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat
 | 
					#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat
 | 
				
			||||||
#Useful if username overrides for incoming webhooks isn't enabled on the 
 | 
					#Useful if username overrides for incoming webhooks isn't enabled on the 
 | 
				
			||||||
#slack server. If you set PrefixMessagesWithNick to true, each message 
 | 
					#slack server. If you set PrefixMessagesWithNick to true, each message 
 | 
				
			||||||
@@ -355,6 +413,12 @@ PrefixMessagesWithNick=false
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -362,7 +426,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -385,11 +450,25 @@ Token="Yourtokenhere"
 | 
				
			|||||||
#REQUIRED
 | 
					#REQUIRED
 | 
				
			||||||
Server="yourservername"
 | 
					Server="yourservername"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Disable sending of edits to other bridges
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					EditDisable=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Message to be appended to every edited message
 | 
				
			||||||
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
 | 
					EditSuffix=" (edited)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Nicks you want to ignore. 
 | 
					#Nicks you want to ignore. 
 | 
				
			||||||
#Messages from those users will not be sent to other bridges.
 | 
					#Messages from those users will not be sent to other bridges.
 | 
				
			||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -397,7 +476,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -420,11 +500,31 @@ Token="Yourtokenhere"
 | 
				
			|||||||
#See https://core.telegram.org/bots/api#html-style
 | 
					#See https://core.telegram.org/bots/api#html-style
 | 
				
			||||||
MessageFormat=""
 | 
					MessageFormat=""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#If enabled use the "First Name" as username. If this is empty use the Username
 | 
				
			||||||
 | 
					#If disabled use the "Username" as username. If this is empty use the First Name 
 | 
				
			||||||
 | 
					#If all names are empty, username will be "unknown"
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					UseFirstName=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Disable sending of edits to other bridges
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					EditDisable=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Message to be appended to every edited message
 | 
				
			||||||
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
 | 
					EditSuffix=" (edited)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Nicks you want to ignore. 
 | 
					#Nicks you want to ignore. 
 | 
				
			||||||
#Messages from those users will not be sent to other bridges.
 | 
					#Messages from those users will not be sent to other bridges.
 | 
				
			||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="spammer1 spammer2"
 | 
					IgnoreNicks="spammer1 spammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -432,7 +532,8 @@ IgnoreNicks="spammer1 spammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -482,6 +583,12 @@ PrefixMessagesWithNick=false
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="ircspammer1 ircspammer2"
 | 
					IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -489,7 +596,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -513,6 +621,11 @@ Server="https://matrix.org"
 | 
				
			|||||||
Login="yourlogin"
 | 
					Login="yourlogin"
 | 
				
			||||||
Password="yourpass"
 | 
					Password="yourpass"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Whether to send the homeserver suffix. eg ":matrix.org" in @username:matrix.org
 | 
				
			||||||
 | 
					#to other bridges, or only send "username".(true only sends username)
 | 
				
			||||||
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
 | 
					NoHomeServerSuffix=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Whether to prefix messages from other bridges to matrix with the sender's nick. 
 | 
					#Whether to prefix messages from other bridges to matrix with the sender's nick. 
 | 
				
			||||||
#Useful if username overrides for incoming webhooks isn't enabled on the 
 | 
					#Useful if username overrides for incoming webhooks isn't enabled on the 
 | 
				
			||||||
#matrix server. If you set PrefixMessagesWithNick to true, each message 
 | 
					#matrix server. If you set PrefixMessagesWithNick to true, each message 
 | 
				
			||||||
@@ -525,6 +638,12 @@ PrefixMessagesWithNick=false
 | 
				
			|||||||
#OPTIONAL
 | 
					#OPTIONAL
 | 
				
			||||||
IgnoreNicks="spammer1 spammer2"
 | 
					IgnoreNicks="spammer1 spammer2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Messages you want to ignore. 
 | 
				
			||||||
 | 
					#Messages matching these regexp will be ignored and not sent to other bridges
 | 
				
			||||||
 | 
					#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
 | 
				
			||||||
 | 
					#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
 | 
				
			||||||
 | 
					IgnoreMessages="^~~ badword"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -532,7 +651,8 @@ IgnoreNicks="spammer1 spammer2"
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
					RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
 | 
					#Enable to show users joins/parts from other bridges 
 | 
				
			||||||
 | 
					#Only works hiding/show messages from irc and mattermost bridge for now
 | 
				
			||||||
#OPTIONAL (default false)
 | 
					#OPTIONAL (default false)
 | 
				
			||||||
ShowJoinPart=false
 | 
					ShowJoinPart=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -553,6 +673,11 @@ BindAddress="127.0.0.1:4242"
 | 
				
			|||||||
#Amount of messages to keep in memory
 | 
					#Amount of messages to keep in memory
 | 
				
			||||||
Buffer=1000
 | 
					Buffer=1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Bearer token used for authentication
 | 
				
			||||||
 | 
					#curl -H "Authorization: Bearer token" http://localhost:4242/api/messages
 | 
				
			||||||
 | 
					#OPTIONAL (no authorization if token is empty)
 | 
				
			||||||
 | 
					Token="mytoken"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#RemoteNickFormat defines how remote users appear on this bridge 
 | 
					#RemoteNickFormat defines how remote users appear on this bridge 
 | 
				
			||||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
					#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
 | 
				
			||||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
					#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
 | 
				
			||||||
@@ -560,6 +685,8 @@ Buffer=1000
 | 
				
			|||||||
#OPTIONAL (default empty)
 | 
					#OPTIONAL (default empty)
 | 
				
			||||||
RemoteNickFormat="{NICK}"
 | 
					RemoteNickFormat="{NICK}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################################################
 | 
					###################################################################
 | 
				
			||||||
#General configuration
 | 
					#General configuration
 | 
				
			||||||
###################################################################
 | 
					###################################################################
 | 
				
			||||||
@@ -603,7 +730,7 @@ enable=true
 | 
				
			|||||||
    #channel to connect on that account
 | 
					    #channel to connect on that account
 | 
				
			||||||
    #How to specify them for the different bridges:
 | 
					    #How to specify them for the different bridges:
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
    #irc        - #channel (# is required)
 | 
					    #irc        - #channel (# is required) (this needs to be lowercase!)
 | 
				
			||||||
    #mattermost - channel (the channel name as seen in the URL, not the displayname)
 | 
					    #mattermost - channel (the channel name as seen in the URL, not the displayname)
 | 
				
			||||||
    #gitter     - username/room 
 | 
					    #gitter     - username/room 
 | 
				
			||||||
    #xmpp       - channel
 | 
					    #xmpp       - channel
 | 
				
			||||||
@@ -614,8 +741,9 @@ enable=true
 | 
				
			|||||||
    #telegram   - chatid (a large negative number, eg -123456789)
 | 
					    #telegram   - chatid (a large negative number, eg -123456789)
 | 
				
			||||||
    #             see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau)
 | 
					    #             see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau)
 | 
				
			||||||
    #hipchat    - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel)
 | 
					    #hipchat    - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel)
 | 
				
			||||||
    #rocketchat - #channel (# is required)
 | 
					    #rocketchat - #channel (# is required (also needed for private channels!)
 | 
				
			||||||
    #matrix     - #channel:server (eg #yourchannel:matrix.org)
 | 
					    #matrix     - #channel:server (eg #yourchannel:matrix.org) 
 | 
				
			||||||
 | 
					    #           - encrypted rooms are not supported in matrix
 | 
				
			||||||
    #REQUIRED
 | 
					    #REQUIRED
 | 
				
			||||||
    channel="#testing"
 | 
					    channel="#testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -651,7 +779,9 @@ enable=true
 | 
				
			|||||||
    #account="api.local"
 | 
					    #account="api.local"
 | 
				
			||||||
    #channel="api"
 | 
					    #channel="api"
 | 
				
			||||||
    #To send data to the api:
 | 
					    #To send data to the api:
 | 
				
			||||||
    #curl -XPOST -H 'Content-Type: application/json'  -d '{"text":"test","username":"randomuser"}' http://localhost:4242/api/message
 | 
					    #curl -XPOST -H 'Content-Type: application/json'  -d '{"text":"test","username":"randomuser","gateway":"gateway1"}' http://localhost:4242/api/message
 | 
				
			||||||
 | 
					    #To read from the api:
 | 
				
			||||||
 | 
					    #curl http://localhost:4242/api/messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#If you want to do a 1:1 mapping between protocols where the channelnames are the same
 | 
					#If you want to do a 1:1 mapping between protocols where the channelnames are the same
 | 
				
			||||||
#e.g. slack and mattermost you can use the samechannelgateway configuration
 | 
					#e.g. slack and mattermost you can use the samechannelgateway configuration
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					#WARNING: as this file contains credentials, be sure to set correct file permissions
 | 
				
			||||||
[irc]
 | 
					[irc]
 | 
				
			||||||
    [irc.freenode]
 | 
					    [irc.freenode]
 | 
				
			||||||
    Server="irc.freenode.net:6667"
 | 
					    Server="irc.freenode.net:6667"
 | 
				
			||||||
@@ -6,7 +7,8 @@
 | 
				
			|||||||
[mattermost]
 | 
					[mattermost]
 | 
				
			||||||
    [mattermost.work]
 | 
					    [mattermost.work]
 | 
				
			||||||
    useAPI=true
 | 
					    useAPI=true
 | 
				
			||||||
    Server="yourmattermostserver.domain"
 | 
					    #do not prefix it wit http:// or https://
 | 
				
			||||||
 | 
					    Server="yourmattermostserver.domain" 
 | 
				
			||||||
    Team="yourteam"
 | 
					    Team="yourteam"
 | 
				
			||||||
    Login="yourlogin"
 | 
					    Login="yourlogin"
 | 
				
			||||||
    Password="yourpass"
 | 
					    Password="yourpass"
 | 
				
			||||||
@@ -15,22 +17,14 @@
 | 
				
			|||||||
[[gateway]]
 | 
					[[gateway]]
 | 
				
			||||||
name="gateway1"
 | 
					name="gateway1"
 | 
				
			||||||
enable=true
 | 
					enable=true
 | 
				
			||||||
    [[gateway.in]]
 | 
					    [[gateway.inout]]
 | 
				
			||||||
    account="irc.freenode"
 | 
					    account="irc.freenode"
 | 
				
			||||||
    channel="#testing"
 | 
					    channel="#testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [[gateway.out]]
 | 
					    [[gateway.inout]]
 | 
				
			||||||
    account="irc.freenode"
 | 
					 | 
				
			||||||
    channel="#testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [[gateway.in]]
 | 
					 | 
				
			||||||
    account="mattermost.work"
 | 
					    account="mattermost.work"
 | 
				
			||||||
    channel="off-topic"
 | 
					    channel="off-topic"
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    [[gateway.out]]
 | 
					 | 
				
			||||||
    account="mattermost.work"
 | 
					 | 
				
			||||||
    channel="off-topic"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#simpler config possible since v0.10.2
 | 
					#simpler config possible since v0.10.2
 | 
				
			||||||
#[[gateway]]
 | 
					#[[gateway]]
 | 
				
			||||||
#name="gateway2"
 | 
					#name="gateway2"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,11 @@ import (
 | 
				
			|||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/cookiejar"
 | 
						"net/http/cookiejar"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -34,6 +36,8 @@ type Message struct {
 | 
				
			|||||||
	Channel  string
 | 
						Channel  string
 | 
				
			||||||
	Username string
 | 
						Username string
 | 
				
			||||||
	Text     string
 | 
						Text     string
 | 
				
			||||||
 | 
						Type     string
 | 
				
			||||||
 | 
						UserID   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Team struct {
 | 
					type Team struct {
 | 
				
			||||||
@@ -47,19 +51,20 @@ type Team struct {
 | 
				
			|||||||
type MMClient struct {
 | 
					type MMClient struct {
 | 
				
			||||||
	sync.RWMutex
 | 
						sync.RWMutex
 | 
				
			||||||
	*Credentials
 | 
						*Credentials
 | 
				
			||||||
	Team        *Team
 | 
						Team          *Team
 | 
				
			||||||
	OtherTeams  []*Team
 | 
						OtherTeams    []*Team
 | 
				
			||||||
	Client      *model.Client
 | 
						Client        *model.Client
 | 
				
			||||||
	User        *model.User
 | 
						User          *model.User
 | 
				
			||||||
	Users       map[string]*model.User
 | 
						Users         map[string]*model.User
 | 
				
			||||||
	MessageChan chan *Message
 | 
						MessageChan   chan *Message
 | 
				
			||||||
	log         *log.Entry
 | 
						log           *log.Entry
 | 
				
			||||||
	WsClient    *websocket.Conn
 | 
						WsClient      *websocket.Conn
 | 
				
			||||||
	WsQuit      bool
 | 
						WsQuit        bool
 | 
				
			||||||
	WsAway      bool
 | 
						WsAway        bool
 | 
				
			||||||
	WsConnected bool
 | 
						WsConnected   bool
 | 
				
			||||||
	WsSequence  int64
 | 
						WsSequence    int64
 | 
				
			||||||
	WsPingChan  chan *model.WebSocketResponse
 | 
						WsPingChan    chan *model.WebSocketResponse
 | 
				
			||||||
 | 
						ServerVersion string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New(login, pass, team, server string) *MMClient {
 | 
					func New(login, pass, team, server string) *MMClient {
 | 
				
			||||||
@@ -102,8 +107,27 @@ func (m *MMClient) Login() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	// login to mattermost
 | 
						// login to mattermost
 | 
				
			||||||
	m.Client = model.NewClient(uriScheme + m.Credentials.Server)
 | 
						m.Client = model.NewClient(uriScheme + m.Credentials.Server)
 | 
				
			||||||
	m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
 | 
						m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, Proxy: http.ProxyFromEnvironment}
 | 
				
			||||||
	m.Client.HttpClient.Timeout = time.Second * 10
 | 
						m.Client.HttpClient.Timeout = time.Second * 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							d := b.Duration()
 | 
				
			||||||
 | 
							// bogus call to get the serverversion
 | 
				
			||||||
 | 
							m.Client.GetClientProperties()
 | 
				
			||||||
 | 
							if firstConnection && !supportedVersion(m.Client.ServerVersion) {
 | 
				
			||||||
 | 
								return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							m.ServerVersion = m.Client.ServerVersion
 | 
				
			||||||
 | 
							if m.ServerVersion == "" {
 | 
				
			||||||
 | 
								m.log.Debugf("Server not up yet, reconnecting in %s", d)
 | 
				
			||||||
 | 
								time.Sleep(d)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								m.log.Infof("Found version %s", m.ServerVersion)
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b.Reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var myinfo *model.Result
 | 
						var myinfo *model.Result
 | 
				
			||||||
	var appErr *model.AppError
 | 
						var appErr *model.AppError
 | 
				
			||||||
	var logmsg = "trying login"
 | 
						var logmsg = "trying login"
 | 
				
			||||||
@@ -177,6 +201,7 @@ func (m *MMClient) Login() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	b.Reset()
 | 
						b.Reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.log.Debug("WsClient: connected")
 | 
				
			||||||
	m.WsSequence = 1
 | 
						m.WsSequence = 1
 | 
				
			||||||
	m.WsPingChan = make(chan *model.WebSocketResponse)
 | 
						m.WsPingChan = make(chan *model.WebSocketResponse)
 | 
				
			||||||
	// only start to parse WS messages when login is completely done
 | 
						// only start to parse WS messages when login is completely done
 | 
				
			||||||
@@ -238,7 +263,7 @@ func (m *MMClient) WsReceiver() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (m *MMClient) parseMessage(rmsg *Message) {
 | 
					func (m *MMClient) parseMessage(rmsg *Message) {
 | 
				
			||||||
	switch rmsg.Raw.Event {
 | 
						switch rmsg.Raw.Event {
 | 
				
			||||||
	case model.WEBSOCKET_EVENT_POSTED:
 | 
						case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED:
 | 
				
			||||||
		m.parseActionPost(rmsg)
 | 
							m.parseActionPost(rmsg)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
			case model.ACTION_USER_REMOVED:
 | 
								case model.ACTION_USER_REMOVED:
 | 
				
			||||||
@@ -264,9 +289,20 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
 | 
				
			|||||||
	if m.GetUser(data.UserId) == nil {
 | 
						if m.GetUser(data.UserId) == nil {
 | 
				
			||||||
		m.UpdateUsers()
 | 
							m.UpdateUsers()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rmsg.Username = m.GetUser(data.UserId).Username
 | 
						rmsg.Username = m.GetUserName(data.UserId)
 | 
				
			||||||
	rmsg.Channel = m.GetChannelName(data.ChannelId)
 | 
						rmsg.Channel = m.GetChannelName(data.ChannelId)
 | 
				
			||||||
	rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string))
 | 
						rmsg.UserID = data.UserId
 | 
				
			||||||
 | 
						rmsg.Type = data.Type
 | 
				
			||||||
 | 
						teamid, _ := rmsg.Raw.Data["team_id"].(string)
 | 
				
			||||||
 | 
						// edit messsages have no team_id for some reason
 | 
				
			||||||
 | 
						if teamid == "" {
 | 
				
			||||||
 | 
							// we can find the team_id from the channelid
 | 
				
			||||||
 | 
							teamid = m.GetChannelTeamId(data.ChannelId)
 | 
				
			||||||
 | 
							rmsg.Raw.Data["team_id"] = teamid
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if teamid != "" {
 | 
				
			||||||
 | 
							rmsg.Team = m.GetTeamName(teamid)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	// direct message
 | 
						// direct message
 | 
				
			||||||
	if rmsg.Raw.Data["channel_type"] == "D" {
 | 
						if rmsg.Raw.Data["channel_type"] == "D" {
 | 
				
			||||||
		rmsg.Channel = m.GetUser(data.UserId).Username
 | 
							rmsg.Channel = m.GetUser(data.UserId).Username
 | 
				
			||||||
@@ -292,7 +328,12 @@ func (m *MMClient) UpdateChannels() error {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.New(err.DetailedError)
 | 
							return errors.New(err.DetailedError)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mmchannels2, err := m.Client.GetMoreChannels("")
 | 
						var mmchannels2 *model.Result
 | 
				
			||||||
 | 
						if m.mmVersion() >= 3.08 {
 | 
				
			||||||
 | 
							mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mmchannels2, err = m.Client.GetMoreChannels("")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return errors.New(err.DetailedError)
 | 
							return errors.New(err.DetailedError)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -334,6 +375,19 @@ func (m *MMClient) GetChannelId(name string, teamId string) string {
 | 
				
			|||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *MMClient) GetChannelTeamId(id string) string {
 | 
				
			||||||
 | 
						m.RLock()
 | 
				
			||||||
 | 
						defer m.RUnlock()
 | 
				
			||||||
 | 
						for _, t := range append(m.OtherTeams, m.Team) {
 | 
				
			||||||
 | 
							for _, channel := range append(*t.Channels, *t.MoreChannels...) {
 | 
				
			||||||
 | 
								if channel.Id == id {
 | 
				
			||||||
 | 
									return channel.TeamId
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *MMClient) GetChannelHeader(channelId string) string {
 | 
					func (m *MMClient) GetChannelHeader(channelId string) string {
 | 
				
			||||||
	m.RLock()
 | 
						m.RLock()
 | 
				
			||||||
	defer m.RUnlock()
 | 
						defer m.RUnlock()
 | 
				
			||||||
@@ -427,6 +481,14 @@ func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (m *MMClient) UpdateLastViewed(channelId string) {
 | 
					func (m *MMClient) UpdateLastViewed(channelId string) {
 | 
				
			||||||
	m.log.Debugf("posting lastview %#v", channelId)
 | 
						m.log.Debugf("posting lastview %#v", channelId)
 | 
				
			||||||
 | 
						if m.mmVersion() >= 3.08 {
 | 
				
			||||||
 | 
							view := model.ChannelView{ChannelId: channelId}
 | 
				
			||||||
 | 
							res, _ := m.Client.ViewChannel(view)
 | 
				
			||||||
 | 
							if res == false {
 | 
				
			||||||
 | 
								m.log.Errorf("ChannelView update for %s failed", channelId)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	_, err := m.Client.UpdateLastViewedAt(channelId, true)
 | 
						_, err := m.Client.UpdateLastViewedAt(channelId, true)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		m.log.Error(err)
 | 
							m.log.Error(err)
 | 
				
			||||||
@@ -573,6 +635,14 @@ func (m *MMClient) GetUser(userId string) *model.User {
 | 
				
			|||||||
	return m.Users[userId]
 | 
						return m.Users[userId]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *MMClient) GetUserName(userId string) string {
 | 
				
			||||||
 | 
						user := m.GetUser(userId)
 | 
				
			||||||
 | 
						if user != nil {
 | 
				
			||||||
 | 
							return user.Username
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ""
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *MMClient) GetStatus(userId string) string {
 | 
					func (m *MMClient) GetStatus(userId string) string {
 | 
				
			||||||
	res, err := m.Client.GetStatuses()
 | 
						res, err := m.Client.GetStatuses()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -628,6 +698,7 @@ func (m *MMClient) StatusLoop() {
 | 
				
			|||||||
				m.Logout()
 | 
									m.Logout()
 | 
				
			||||||
				m.WsQuit = false
 | 
									m.WsQuit = false
 | 
				
			||||||
				m.Login()
 | 
									m.Login()
 | 
				
			||||||
 | 
									go m.WsReceiver()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		time.Sleep(time.Second * 60)
 | 
							time.Sleep(time.Second * 60)
 | 
				
			||||||
@@ -659,7 +730,11 @@ func (m *MMClient) initUser() error {
 | 
				
			|||||||
			return errors.New(err.DetailedError)
 | 
								return errors.New(err.DetailedError)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		t.Channels = mmchannels.Data.(*model.ChannelList)
 | 
							t.Channels = mmchannels.Data.(*model.ChannelList)
 | 
				
			||||||
		mmchannels, err = m.Client.GetMoreChannels("")
 | 
							if m.mmVersion() >= 3.08 {
 | 
				
			||||||
 | 
								mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								mmchannels, err = m.Client.GetMoreChannels("")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errors.New(err.DetailedError)
 | 
								return errors.New(err.DetailedError)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -687,3 +762,23 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err
 | 
				
			|||||||
	m.WsClient.WriteJSON(req)
 | 
						m.WsClient.WriteJSON(req)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *MMClient) mmVersion() float64 {
 | 
				
			||||||
 | 
						v, _ := strconv.ParseFloat(string(m.ServerVersion[0:2])+"0"+string(m.ServerVersion[2]), 64)
 | 
				
			||||||
 | 
						if string(m.ServerVersion[4]) == "." {
 | 
				
			||||||
 | 
							v, _ = strconv.ParseFloat(m.ServerVersion[0:4], 64)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return v
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func supportedVersion(version string) bool {
 | 
				
			||||||
 | 
						if strings.HasPrefix(version, "3.5.0") ||
 | 
				
			||||||
 | 
							strings.HasPrefix(version, "3.6.0") ||
 | 
				
			||||||
 | 
							strings.HasPrefix(version, "3.7.0") ||
 | 
				
			||||||
 | 
							strings.HasPrefix(version, "3.8.0") ||
 | 
				
			||||||
 | 
							strings.HasPrefix(version, "3.9.0") ||
 | 
				
			||||||
 | 
							strings.HasPrefix(version, "3.10.0") {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								vendor/github.com/labstack/echo/bind.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/labstack/echo/bind.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -30,16 +30,16 @@ type (
 | 
				
			|||||||
// Bind implements the `Binder#Bind` function.
 | 
					// Bind implements the `Binder#Bind` function.
 | 
				
			||||||
func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
 | 
					func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
 | 
				
			||||||
	req := c.Request()
 | 
						req := c.Request()
 | 
				
			||||||
	if req.Method == GET {
 | 
					 | 
				
			||||||
		if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
 | 
					 | 
				
			||||||
			return NewHTTPError(http.StatusBadRequest, err.Error())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctype := req.Header.Get(HeaderContentType)
 | 
					 | 
				
			||||||
	if req.ContentLength == 0 {
 | 
						if req.ContentLength == 0 {
 | 
				
			||||||
 | 
							if req.Method == GET || req.Method == DELETE {
 | 
				
			||||||
 | 
								if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
 | 
				
			||||||
 | 
									return NewHTTPError(http.StatusBadRequest, err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
 | 
							return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						ctype := req.Header.Get(HeaderContentType)
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case strings.HasPrefix(ctype, MIMEApplicationJSON):
 | 
						case strings.HasPrefix(ctype, MIMEApplicationJSON):
 | 
				
			||||||
		if err = json.NewDecoder(req.Body).Decode(i); err != nil {
 | 
							if err = json.NewDecoder(req.Body).Decode(i); err != nil {
 | 
				
			||||||
@@ -51,7 +51,7 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
 | 
				
			|||||||
				return NewHTTPError(http.StatusBadRequest, err.Error())
 | 
									return NewHTTPError(http.StatusBadRequest, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case strings.HasPrefix(ctype, MIMEApplicationXML):
 | 
						case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
 | 
				
			||||||
		if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
 | 
							if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
 | 
				
			||||||
			if ute, ok := err.(*xml.UnsupportedTypeError); ok {
 | 
								if ute, ok := err.(*xml.UnsupportedTypeError); ok {
 | 
				
			||||||
				return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
 | 
									return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error()))
 | 
				
			||||||
@@ -142,6 +142,8 @@ func setWithProperType(valueKind reflect.Kind, val string, structField reflect.V
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch valueKind {
 | 
						switch valueKind {
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
 | 
				
			||||||
	case reflect.Int:
 | 
						case reflect.Int:
 | 
				
			||||||
		return setIntField(val, 0, structField)
 | 
							return setIntField(val, 0, structField)
 | 
				
			||||||
	case reflect.Int8:
 | 
						case reflect.Int8:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								vendor/github.com/labstack/echo/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/labstack/echo/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -31,6 +31,9 @@ type (
 | 
				
			|||||||
		// IsTLS returns true if HTTP connection is TLS otherwise false.
 | 
							// IsTLS returns true if HTTP connection is TLS otherwise false.
 | 
				
			||||||
		IsTLS() bool
 | 
							IsTLS() bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
 | 
				
			||||||
 | 
							IsWebSocket() bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Scheme returns the HTTP protocol scheme, `http` or `https`.
 | 
							// Scheme returns the HTTP protocol scheme, `http` or `https`.
 | 
				
			||||||
		Scheme() string
 | 
							Scheme() string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -219,19 +222,36 @@ func (c *context) IsTLS() bool {
 | 
				
			|||||||
	return c.request.TLS != nil
 | 
						return c.request.TLS != nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *context) IsWebSocket() bool {
 | 
				
			||||||
 | 
						upgrade := c.request.Header.Get(HeaderUpgrade)
 | 
				
			||||||
 | 
						return upgrade == "websocket" || upgrade == "Websocket"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) Scheme() string {
 | 
					func (c *context) Scheme() string {
 | 
				
			||||||
	// Can't use `r.Request.URL.Scheme`
 | 
						// Can't use `r.Request.URL.Scheme`
 | 
				
			||||||
	// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
 | 
						// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
 | 
				
			||||||
	if c.IsTLS() {
 | 
						if c.IsTLS() {
 | 
				
			||||||
		return "https"
 | 
							return "https"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
 | 
				
			||||||
 | 
							return scheme
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
 | 
				
			||||||
 | 
							return scheme
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
 | 
				
			||||||
 | 
							return "https"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
 | 
				
			||||||
 | 
							return scheme
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return "http"
 | 
						return "http"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) RealIP() string {
 | 
					func (c *context) RealIP() string {
 | 
				
			||||||
	ra := c.request.RemoteAddr
 | 
						ra := c.request.RemoteAddr
 | 
				
			||||||
	if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
 | 
						if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
 | 
				
			||||||
		ra = ip
 | 
							ra = strings.Split(ip, ", ")[0]
 | 
				
			||||||
	} else if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
 | 
						} else if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
 | 
				
			||||||
		ra = ip
 | 
							ra = ip
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -275,7 +295,7 @@ func (c *context) SetParamNames(names ...string) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) ParamValues() []string {
 | 
					func (c *context) ParamValues() []string {
 | 
				
			||||||
	return c.pvalues
 | 
						return c.pvalues[:len(c.pnames)]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) SetParamValues(values ...string) {
 | 
					func (c *context) SetParamValues(values ...string) {
 | 
				
			||||||
@@ -385,7 +405,8 @@ func (c *context) String(code int, s string) (err error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) JSON(code int, i interface{}) (err error) {
 | 
					func (c *context) JSON(code int, i interface{}) (err error) {
 | 
				
			||||||
	if c.echo.Debug {
 | 
						_, pretty := c.QueryParams()["pretty"]
 | 
				
			||||||
 | 
						if c.echo.Debug || pretty {
 | 
				
			||||||
		return c.JSONPretty(code, i, "  ")
 | 
							return c.JSONPretty(code, i, "  ")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	b, err := json.Marshal(i)
 | 
						b, err := json.Marshal(i)
 | 
				
			||||||
@@ -429,7 +450,8 @@ func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) XML(code int, i interface{}) (err error) {
 | 
					func (c *context) XML(code int, i interface{}) (err error) {
 | 
				
			||||||
	if c.echo.Debug {
 | 
						_, pretty := c.QueryParams()["pretty"]
 | 
				
			||||||
 | 
						if c.echo.Debug || pretty {
 | 
				
			||||||
		return c.XMLPretty(code, i, "  ")
 | 
							return c.XMLPretty(code, i, "  ")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	b, err := xml.Marshal(i)
 | 
						b, err := xml.Marshal(i)
 | 
				
			||||||
@@ -471,7 +493,12 @@ func (c *context) Stream(code int, contentType string, r io.Reader) (err error)
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) File(file string) error {
 | 
					func (c *context) File(file string) (err error) {
 | 
				
			||||||
 | 
						file, err = url.QueryUnescape(file) // Issue #839
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f, err := os.Open(file)
 | 
						f, err := os.Open(file)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return ErrNotFound
 | 
							return ErrNotFound
 | 
				
			||||||
@@ -487,11 +514,11 @@ func (c *context) File(file string) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		defer f.Close()
 | 
							defer f.Close()
 | 
				
			||||||
		if fi, err = f.Stat(); err != nil {
 | 
							if fi, err = f.Stat(); err != nil {
 | 
				
			||||||
			return err
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
 | 
						http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
 | 
				
			||||||
	return nil
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) Attachment(file, name string) (err error) {
 | 
					func (c *context) Attachment(file, name string) (err error) {
 | 
				
			||||||
@@ -514,7 +541,7 @@ func (c *context) NoContent(code int) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *context) Redirect(code int, url string) error {
 | 
					func (c *context) Redirect(code int, url string) error {
 | 
				
			||||||
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
 | 
						if code < 300 || code > 308 {
 | 
				
			||||||
		return ErrInvalidRedirectCode
 | 
							return ErrInvalidRedirectCode
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.response.Header().Set(HeaderLocation, url)
 | 
						c.response.Header().Set(HeaderLocation, url)
 | 
				
			||||||
@@ -548,4 +575,8 @@ func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
 | 
				
			|||||||
	c.query = nil
 | 
						c.query = nil
 | 
				
			||||||
	c.handler = NotFoundHandler
 | 
						c.handler = NotFoundHandler
 | 
				
			||||||
	c.store = nil
 | 
						c.store = nil
 | 
				
			||||||
 | 
						c.path = ""
 | 
				
			||||||
 | 
						c.pnames = nil
 | 
				
			||||||
 | 
						// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
 | 
				
			||||||
 | 
						// c.pvalues = nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								vendor/github.com/labstack/echo/cookbook/auto-tls/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/labstack/echo/cookbook/auto-tls/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,26 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"golang.org/x/crypto/acme/autocert"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	// e.AutoTLSManager.HostPolicy = autocert.HostWhitelist("<DOMAIN>")
 | 
					 | 
				
			||||||
	// Cache certificates
 | 
					 | 
				
			||||||
	e.AutoTLSManager.Cache = autocert.DirCache("/var/www/.cache")
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.HTML(http.StatusOK, `
 | 
					 | 
				
			||||||
			<h1>Welcome to Echo!</h1>
 | 
					 | 
				
			||||||
			<h3>TLS certificates automatically installed from Let's Encrypt :)</h3>
 | 
					 | 
				
			||||||
		`)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.StartAutoTLS(":443"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										38
									
								
								vendor/github.com/labstack/echo/cookbook/cors/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/labstack/echo/cookbook/cors/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,38 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	users = []string{"Joe", "Veer", "Zion"}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getUsers(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, users)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CORS default
 | 
					 | 
				
			||||||
	// Allows requests from any origin wth GET, HEAD, PUT, POST or DELETE method.
 | 
					 | 
				
			||||||
	// e.Use(middleware.CORS())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// CORS restricted
 | 
					 | 
				
			||||||
	// Allows requests from any `https://labstack.com` or `https://labstack.net` origin
 | 
					 | 
				
			||||||
	// wth GET, PUT, POST or DELETE method.
 | 
					 | 
				
			||||||
	e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
 | 
					 | 
				
			||||||
		AllowOrigins: []string{"https://labstack.com", "https://labstack.net"},
 | 
					 | 
				
			||||||
		AllowMethods: []string{echo.GET, echo.PUT, echo.POST, echo.DELETE},
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.GET("/api/users", getUsers)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										75
									
								
								vendor/github.com/labstack/echo/cookbook/crud/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										75
									
								
								vendor/github.com/labstack/echo/cookbook/crud/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,75 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	user struct {
 | 
					 | 
				
			||||||
		ID   int    `json:"id"`
 | 
					 | 
				
			||||||
		Name string `json:"name"`
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	users = map[int]*user{}
 | 
					 | 
				
			||||||
	seq   = 1
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//----------
 | 
					 | 
				
			||||||
// Handlers
 | 
					 | 
				
			||||||
//----------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	u := &user{
 | 
					 | 
				
			||||||
		ID: seq,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := c.Bind(u); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	users[u.ID] = u
 | 
					 | 
				
			||||||
	seq++
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusCreated, u)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	id, _ := strconv.Atoi(c.Param("id"))
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, users[id])
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func updateUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	u := new(user)
 | 
					 | 
				
			||||||
	if err := c.Bind(u); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	id, _ := strconv.Atoi(c.Param("id"))
 | 
					 | 
				
			||||||
	users[id].Name = u.Name
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, users[id])
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func deleteUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	id, _ := strconv.Atoi(c.Param("id"))
 | 
					 | 
				
			||||||
	delete(users, id)
 | 
					 | 
				
			||||||
	return c.NoContent(http.StatusNoContent)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Middleware
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Routes
 | 
					 | 
				
			||||||
	e.POST("/users", createUser)
 | 
					 | 
				
			||||||
	e.GET("/users/:id", getUser)
 | 
					 | 
				
			||||||
	e.PUT("/users/:id", updateUser)
 | 
					 | 
				
			||||||
	e.DELETE("/users/:id", deleteUser)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Start server
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										21
									
								
								vendor/github.com/labstack/echo/cookbook/embed-resources/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/labstack/echo/cookbook/embed-resources/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rice "github.com/GeertJohan/go.rice"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	// the file server for rice. "app" is the folder where the files come from.
 | 
					 | 
				
			||||||
	assetHandler := http.FileServer(rice.MustFindBox("app").HTTPBox())
 | 
					 | 
				
			||||||
	// serves the index.html from rice
 | 
					 | 
				
			||||||
	e.GET("/", echo.WrapHandler(assetHandler))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// servers other static files
 | 
					 | 
				
			||||||
	e.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", assetHandler)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										65
									
								
								vendor/github.com/labstack/echo/cookbook/file-upload/multiple/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/labstack/echo/cookbook/file-upload/multiple/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,65 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func upload(c echo.Context) error {
 | 
					 | 
				
			||||||
	// Read form fields
 | 
					 | 
				
			||||||
	name := c.FormValue("name")
 | 
					 | 
				
			||||||
	email := c.FormValue("email")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//------------
 | 
					 | 
				
			||||||
	// Read files
 | 
					 | 
				
			||||||
	//------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Multipart form
 | 
					 | 
				
			||||||
	form, err := c.MultipartForm()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	files := form.File["files"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, file := range files {
 | 
					 | 
				
			||||||
		// Source
 | 
					 | 
				
			||||||
		src, err := file.Open()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer src.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Destination
 | 
					 | 
				
			||||||
		dst, err := os.Create(file.Filename)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		defer dst.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Copy
 | 
					 | 
				
			||||||
		if _, err = io.Copy(dst, src); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c.HTML(http.StatusOK, fmt.Sprintf("<p>Uploaded successfully %d files with fields name=%s and email=%s.</p>", len(files), name, email))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Static("/", "public")
 | 
					 | 
				
			||||||
	e.POST("/upload", upload)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										59
									
								
								vendor/github.com/labstack/echo/cookbook/file-upload/single/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/labstack/echo/cookbook/file-upload/single/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,59 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func upload(c echo.Context) error {
 | 
					 | 
				
			||||||
	// Read form fields
 | 
					 | 
				
			||||||
	name := c.FormValue("name")
 | 
					 | 
				
			||||||
	email := c.FormValue("email")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//-----------
 | 
					 | 
				
			||||||
	// Read file
 | 
					 | 
				
			||||||
	//-----------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Source
 | 
					 | 
				
			||||||
	file, err := c.FormFile("file")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	src, err := file.Open()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer src.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Destination
 | 
					 | 
				
			||||||
	dst, err := os.Create(file.Filename)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer dst.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Copy
 | 
					 | 
				
			||||||
	if _, err = io.Copy(dst, src); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c.HTML(http.StatusOK, fmt.Sprintf("<p>File %s uploaded successfully with fields name=%s and email=%s.</p>", file.Filename, name, email))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Static("/", "public")
 | 
					 | 
				
			||||||
	e.POST("/upload", upload)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										17
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-engine.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-engine.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,17 +0,0 @@
 | 
				
			|||||||
// +build appengine
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createMux() *echo.Echo {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	// note: we don't need to provide the middleware or static handlers, that's taken care of by the platform
 | 
					 | 
				
			||||||
	// app engine has it's own "main" wrapper - we just need to hook echo into the default handler
 | 
					 | 
				
			||||||
	http.Handle("/", e)
 | 
					 | 
				
			||||||
	return e
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										25
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-managed.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-managed.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,25 +0,0 @@
 | 
				
			|||||||
// +build appenginevm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"google.golang.org/appengine"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createMux() *echo.Echo {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	// note: we don't need to provide the middleware or static handlers
 | 
					 | 
				
			||||||
	// for the appengine vm version - that's taken care of by the platform
 | 
					 | 
				
			||||||
	return e
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	// the appengine package provides a convenient method to handle the health-check requests
 | 
					 | 
				
			||||||
	// and also run the app on the correct port. We just need to add Echo to the default handler
 | 
					 | 
				
			||||||
	e := echo.New(":8080")
 | 
					 | 
				
			||||||
	http.Handle("/", e)
 | 
					 | 
				
			||||||
	appengine.Main()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										24
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-standalone.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app-standalone.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,24 +0,0 @@
 | 
				
			|||||||
// +build !appengine,!appenginevm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createMux() *echo.Echo {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Gzip())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Static("/", "public")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return e
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":8080"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										4
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/app.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// reference our echo instance and create it early
 | 
					 | 
				
			||||||
var e = createMux()
 | 
					 | 
				
			||||||
							
								
								
									
										54
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,54 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	user struct {
 | 
					 | 
				
			||||||
		ID   string `json:"id"`
 | 
					 | 
				
			||||||
		Name string `json:"name"`
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	users map[string]user
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	users = map[string]user{
 | 
					 | 
				
			||||||
		"1": user{
 | 
					 | 
				
			||||||
			ID:   "1",
 | 
					 | 
				
			||||||
			Name: "Wreck-It Ralph",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// hook into the echo instance to create an endpoint group
 | 
					 | 
				
			||||||
	// and add specific middleware to it plus handlers
 | 
					 | 
				
			||||||
	g := e.Group("/users")
 | 
					 | 
				
			||||||
	g.Use(middleware.CORS())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	g.POST("", createUser)
 | 
					 | 
				
			||||||
	g.GET("", getUsers)
 | 
					 | 
				
			||||||
	g.GET("/:id", getUser)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	u := new(user)
 | 
					 | 
				
			||||||
	if err := c.Bind(u); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	users[u.ID] = *u
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusCreated, u)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getUsers(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, users)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getUser(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, users[c.Param("id")])
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										31
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/welcome.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/labstack/echo/cookbook/google-app-engine/welcome.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,31 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"html/template"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Template struct {
 | 
					 | 
				
			||||||
		templates *template.Template
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	t := &Template{
 | 
					 | 
				
			||||||
		templates: template.Must(template.ParseFiles("templates/welcome.html")),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	e.Renderer = t
 | 
					 | 
				
			||||||
	e.GET("/welcome", welcome)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
 | 
					 | 
				
			||||||
	return t.templates.ExecuteTemplate(w, name, data)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func welcome(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.Render(http.StatusOK, "welcome", "Joe")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										20
									
								
								vendor/github.com/labstack/echo/cookbook/graceful-shutdown/grace/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/labstack/echo/cookbook/graceful-shutdown/grace/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,20 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/facebookgo/grace/gracehttp"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	// Setup
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Six sick bricks tick")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	e.Server.Addr = ":1323"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Serve it like a boss
 | 
					 | 
				
			||||||
	e.Logger.Fatal(gracehttp.Serve(e.Server))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										21
									
								
								vendor/github.com/labstack/echo/cookbook/graceful-shutdown/graceful/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/labstack/echo/cookbook/graceful-shutdown/graceful/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/tylerb/graceful"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	// Setup
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Sue sews rose on slow joe crows nose")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	e.Server.Addr = ":1323"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Serve it like a boss
 | 
					 | 
				
			||||||
	graceful.ListenAndServe(e.Server, 5*time.Second)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										25
									
								
								vendor/github.com/labstack/echo/cookbook/hello-world/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/labstack/echo/cookbook/hello-world/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,25 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	// Echo instance
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Middleware
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Route => handler
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Hello, World!\n")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Start server
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										42
									
								
								vendor/github.com/labstack/echo/cookbook/http2/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/labstack/echo/cookbook/http2/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,42 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func request(c echo.Context) error {
 | 
					 | 
				
			||||||
	req := c.Request()
 | 
					 | 
				
			||||||
	format := "<pre><strong>Request Information</strong>\n\n<code>Protocol: %s\nHost: %s\nRemote Address: %s\nMethod: %s\nPath: %s\n</code></pre>"
 | 
					 | 
				
			||||||
	return c.HTML(http.StatusOK, fmt.Sprintf(format, req.Proto, req.Host, req.RemoteAddr, req.Method, req.URL.Path))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func stream(c echo.Context) error {
 | 
					 | 
				
			||||||
	res := c.Response()
 | 
					 | 
				
			||||||
	gone := res.CloseNotify()
 | 
					 | 
				
			||||||
	res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
 | 
					 | 
				
			||||||
	res.WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
	ticker := time.NewTicker(1 * time.Second)
 | 
					 | 
				
			||||||
	defer ticker.Stop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fmt.Fprint(res, "<pre><strong>Clock Stream</strong>\n\n<code>")
 | 
					 | 
				
			||||||
	for {
 | 
					 | 
				
			||||||
		fmt.Fprintf(res, "%v\n", time.Now())
 | 
					 | 
				
			||||||
		res.Flush()
 | 
					 | 
				
			||||||
		select {
 | 
					 | 
				
			||||||
		case <-ticker.C:
 | 
					 | 
				
			||||||
		case <-gone:
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.GET("/request", request)
 | 
					 | 
				
			||||||
	e.GET("/stream", stream)
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										35
									
								
								vendor/github.com/labstack/echo/cookbook/jsonp/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/labstack/echo/cookbook/jsonp/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,35 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"math/rand"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Static("/", "public")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// JSONP
 | 
					 | 
				
			||||||
	e.GET("/jsonp", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		callback := c.QueryParam("callback")
 | 
					 | 
				
			||||||
		var content struct {
 | 
					 | 
				
			||||||
			Response  string    `json:"response"`
 | 
					 | 
				
			||||||
			Timestamp time.Time `json:"timestamp"`
 | 
					 | 
				
			||||||
			Random    int       `json:"random"`
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		content.Response = "Sent via JSONP"
 | 
					 | 
				
			||||||
		content.Timestamp = time.Now().UTC()
 | 
					 | 
				
			||||||
		content.Random = rand.Intn(1000)
 | 
					 | 
				
			||||||
		return c.JSONP(http.StatusOK, callback, &content)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Start server
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										86
									
								
								vendor/github.com/labstack/echo/cookbook/jwt/custom-claims/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/labstack/echo/cookbook/jwt/custom-claims/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,86 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	jwt "github.com/dgrijalva/jwt-go"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// jwtCustomClaims are custom claims extending default ones.
 | 
					 | 
				
			||||||
type jwtCustomClaims struct {
 | 
					 | 
				
			||||||
	Name  string `json:"name"`
 | 
					 | 
				
			||||||
	Admin bool   `json:"admin"`
 | 
					 | 
				
			||||||
	jwt.StandardClaims
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func login(c echo.Context) error {
 | 
					 | 
				
			||||||
	username := c.FormValue("username")
 | 
					 | 
				
			||||||
	password := c.FormValue("password")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if username == "jon" && password == "shhh!" {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Set custom claims
 | 
					 | 
				
			||||||
		claims := &jwtCustomClaims{
 | 
					 | 
				
			||||||
			"Jon Snow",
 | 
					 | 
				
			||||||
			true,
 | 
					 | 
				
			||||||
			jwt.StandardClaims{
 | 
					 | 
				
			||||||
				ExpiresAt: time.Now().Add(time.Hour * 72).Unix(),
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Create token with claims
 | 
					 | 
				
			||||||
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Generate encoded token and send it as response.
 | 
					 | 
				
			||||||
		t, err := token.SignedString([]byte("secret"))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return c.JSON(http.StatusOK, echo.Map{
 | 
					 | 
				
			||||||
			"token": t,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return echo.ErrUnauthorized
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func accessible(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.String(http.StatusOK, "Accessible")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func restricted(c echo.Context) error {
 | 
					 | 
				
			||||||
	user := c.Get("user").(*jwt.Token)
 | 
					 | 
				
			||||||
	claims := user.Claims.(*jwtCustomClaims)
 | 
					 | 
				
			||||||
	name := claims.Name
 | 
					 | 
				
			||||||
	return c.String(http.StatusOK, "Welcome "+name+"!")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Middleware
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Login route
 | 
					 | 
				
			||||||
	e.POST("/login", login)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Unauthenticated route
 | 
					 | 
				
			||||||
	e.GET("/", accessible)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Restricted group
 | 
					 | 
				
			||||||
	r := e.Group("/restricted")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Configure middleware with the custom claims type
 | 
					 | 
				
			||||||
	config := middleware.JWTConfig{
 | 
					 | 
				
			||||||
		Claims:     &jwtCustomClaims{},
 | 
					 | 
				
			||||||
		SigningKey: []byte("secret"),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	r.Use(middleware.JWTWithConfig(config))
 | 
					 | 
				
			||||||
	r.GET("", restricted)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										69
									
								
								vendor/github.com/labstack/echo/cookbook/jwt/map-claims/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/labstack/echo/cookbook/jwt/map-claims/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,69 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	jwt "github.com/dgrijalva/jwt-go"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func login(c echo.Context) error {
 | 
					 | 
				
			||||||
	username := c.FormValue("username")
 | 
					 | 
				
			||||||
	password := c.FormValue("password")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if username == "jon" && password == "shhh!" {
 | 
					 | 
				
			||||||
		// Create token
 | 
					 | 
				
			||||||
		token := jwt.New(jwt.SigningMethodHS256)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Set claims
 | 
					 | 
				
			||||||
		claims := token.Claims.(jwt.MapClaims)
 | 
					 | 
				
			||||||
		claims["name"] = "Jon Snow"
 | 
					 | 
				
			||||||
		claims["admin"] = true
 | 
					 | 
				
			||||||
		claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Generate encoded token and send it as response.
 | 
					 | 
				
			||||||
		t, err := token.SignedString([]byte("secret"))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return c.JSON(http.StatusOK, map[string]string{
 | 
					 | 
				
			||||||
			"token": t,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return echo.ErrUnauthorized
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func accessible(c echo.Context) error {
 | 
					 | 
				
			||||||
	return c.String(http.StatusOK, "Accessible")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func restricted(c echo.Context) error {
 | 
					 | 
				
			||||||
	user := c.Get("user").(*jwt.Token)
 | 
					 | 
				
			||||||
	claims := user.Claims.(jwt.MapClaims)
 | 
					 | 
				
			||||||
	name := claims["name"].(string)
 | 
					 | 
				
			||||||
	return c.String(http.StatusOK, "Welcome "+name+"!")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Middleware
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Login route
 | 
					 | 
				
			||||||
	e.POST("/login", login)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Unauthenticated route
 | 
					 | 
				
			||||||
	e.GET("/", accessible)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Restricted group
 | 
					 | 
				
			||||||
	r := e.Group("/restricted")
 | 
					 | 
				
			||||||
	r.Use(middleware.JWT([]byte("secret")))
 | 
					 | 
				
			||||||
	r.GET("", restricted)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										82
									
								
								vendor/github.com/labstack/echo/cookbook/middleware/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/labstack/echo/cookbook/middleware/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,82 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Stats struct {
 | 
					 | 
				
			||||||
		Uptime       time.Time      `json:"uptime"`
 | 
					 | 
				
			||||||
		RequestCount uint64         `json:"requestCount"`
 | 
					 | 
				
			||||||
		Statuses     map[string]int `json:"statuses"`
 | 
					 | 
				
			||||||
		mutex        sync.RWMutex
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewStats() *Stats {
 | 
					 | 
				
			||||||
	return &Stats{
 | 
					 | 
				
			||||||
		Uptime:   time.Now(),
 | 
					 | 
				
			||||||
		Statuses: make(map[string]int),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Process is the middleware function.
 | 
					 | 
				
			||||||
func (s *Stats) Process(next echo.HandlerFunc) echo.HandlerFunc {
 | 
					 | 
				
			||||||
	return func(c echo.Context) error {
 | 
					 | 
				
			||||||
		if err := next(c); err != nil {
 | 
					 | 
				
			||||||
			c.Error(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		s.mutex.Lock()
 | 
					 | 
				
			||||||
		defer s.mutex.Unlock()
 | 
					 | 
				
			||||||
		s.RequestCount++
 | 
					 | 
				
			||||||
		status := strconv.Itoa(c.Response().Status)
 | 
					 | 
				
			||||||
		s.Statuses[status]++
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Handle is the endpoint to get stats.
 | 
					 | 
				
			||||||
func (s *Stats) Handle(c echo.Context) error {
 | 
					 | 
				
			||||||
	s.mutex.RLock()
 | 
					 | 
				
			||||||
	defer s.mutex.RUnlock()
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, s)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ServerHeader middleware adds a `Server` header to the response.
 | 
					 | 
				
			||||||
func ServerHeader(next echo.HandlerFunc) echo.HandlerFunc {
 | 
					 | 
				
			||||||
	return func(c echo.Context) error {
 | 
					 | 
				
			||||||
		c.Response().Header().Set(echo.HeaderServer, "Echo/3.0")
 | 
					 | 
				
			||||||
		return next(c)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Debug mode
 | 
					 | 
				
			||||||
	e.Debug = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//-------------------
 | 
					 | 
				
			||||||
	// Custom middleware
 | 
					 | 
				
			||||||
	//-------------------
 | 
					 | 
				
			||||||
	// Stats
 | 
					 | 
				
			||||||
	s := NewStats()
 | 
					 | 
				
			||||||
	e.Use(s.Process)
 | 
					 | 
				
			||||||
	e.GET("/stats", s.Handle) // Endpoint to get stats
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Server header
 | 
					 | 
				
			||||||
	e.Use(ServerHeader)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Handler
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Hello, World!")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Start server
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										45
									
								
								vendor/github.com/labstack/echo/cookbook/streaming-response/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/labstack/echo/cookbook/streaming-response/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,45 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Geolocation struct {
 | 
					 | 
				
			||||||
		Altitude  float64
 | 
					 | 
				
			||||||
		Latitude  float64
 | 
					 | 
				
			||||||
		Longitude float64
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	locations = []Geolocation{
 | 
					 | 
				
			||||||
		{-97, 37.819929, -122.478255},
 | 
					 | 
				
			||||||
		{1899, 39.096849, -120.032351},
 | 
					 | 
				
			||||||
		{2619, 37.865101, -119.538329},
 | 
					 | 
				
			||||||
		{42, 33.812092, -117.918974},
 | 
					 | 
				
			||||||
		{15, 37.77493, -122.419416},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
 | 
					 | 
				
			||||||
		c.Response().WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
		for _, l := range locations {
 | 
					 | 
				
			||||||
			if err := json.NewEncoder(c.Response()).Encode(l); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			c.Response().Flush()
 | 
					 | 
				
			||||||
			time.Sleep(1 * time.Second)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										78
									
								
								vendor/github.com/labstack/echo/cookbook/subdomains/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										78
									
								
								vendor/github.com/labstack/echo/cookbook/subdomains/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,78 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Host struct {
 | 
					 | 
				
			||||||
		Echo *echo.Echo
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	// Hosts
 | 
					 | 
				
			||||||
	hosts := make(map[string]*Host)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//-----
 | 
					 | 
				
			||||||
	// API
 | 
					 | 
				
			||||||
	//-----
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	api := echo.New()
 | 
					 | 
				
			||||||
	api.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	api.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hosts["api.localhost:1323"] = &Host{api}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	api.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "API")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//------
 | 
					 | 
				
			||||||
	// Blog
 | 
					 | 
				
			||||||
	//------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blog := echo.New()
 | 
					 | 
				
			||||||
	blog.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	blog.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hosts["blog.localhost:1323"] = &Host{blog}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	blog.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Blog")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//---------
 | 
					 | 
				
			||||||
	// Website
 | 
					 | 
				
			||||||
	//---------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	site := echo.New()
 | 
					 | 
				
			||||||
	site.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	site.Use(middleware.Recover())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hosts["localhost:1323"] = &Host{site}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	site.GET("/", func(c echo.Context) error {
 | 
					 | 
				
			||||||
		return c.String(http.StatusOK, "Website")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Server
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Any("/*", func(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
		req := c.Request()
 | 
					 | 
				
			||||||
		res := c.Response()
 | 
					 | 
				
			||||||
		host := hosts[req.Host]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if host == nil {
 | 
					 | 
				
			||||||
			err = echo.ErrNotFound
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			host.Echo.ServeHTTP(res, req)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/handler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,14 +0,0 @@
 | 
				
			|||||||
package handler
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import mgo "gopkg.in/mgo.v2"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Handler struct {
 | 
					 | 
				
			||||||
		DB *mgo.Session
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	// Key (Should come from somewhere else).
 | 
					 | 
				
			||||||
	Key = "secret"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
							
								
								
									
										73
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,73 +0,0 @@
 | 
				
			|||||||
package handler
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/cookbook/twitter/model"
 | 
					 | 
				
			||||||
	mgo "gopkg.in/mgo.v2"
 | 
					 | 
				
			||||||
	"gopkg.in/mgo.v2/bson"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h *Handler) CreatePost(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
	u := &model.User{
 | 
					 | 
				
			||||||
		ID: bson.ObjectIdHex(userIDFromToken(c)),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	p := &model.Post{
 | 
					 | 
				
			||||||
		ID:   bson.NewObjectId(),
 | 
					 | 
				
			||||||
		From: u.ID.Hex(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err = c.Bind(p); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Validation
 | 
					 | 
				
			||||||
	if p.To == "" || p.Message == "" {
 | 
					 | 
				
			||||||
		return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid to or message fields"}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Find user from database
 | 
					 | 
				
			||||||
	db := h.DB.Clone()
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("users").FindId(u.ID).One(u); err != nil {
 | 
					 | 
				
			||||||
		if err == mgo.ErrNotFound {
 | 
					 | 
				
			||||||
			return echo.ErrNotFound
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Save post in database
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("posts").Insert(p); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusCreated, p)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h *Handler) FetchPost(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
	userID := userIDFromToken(c)
 | 
					 | 
				
			||||||
	page, _ := strconv.Atoi(c.QueryParam("page"))
 | 
					 | 
				
			||||||
	limit, _ := strconv.Atoi(c.QueryParam("limit"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Defaults
 | 
					 | 
				
			||||||
	if page == 0 {
 | 
					 | 
				
			||||||
		page = 1
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if limit == 0 {
 | 
					 | 
				
			||||||
		limit = 100
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Retrieve posts from database
 | 
					 | 
				
			||||||
	posts := []*model.Post{}
 | 
					 | 
				
			||||||
	db := h.DB.Clone()
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("posts").
 | 
					 | 
				
			||||||
		Find(bson.M{"to": userID}).
 | 
					 | 
				
			||||||
		Skip((page - 1) * limit).
 | 
					 | 
				
			||||||
		Limit(limit).
 | 
					 | 
				
			||||||
		All(&posts); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, posts)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										97
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/handler/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,97 +0,0 @@
 | 
				
			|||||||
package handler
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	jwt "github.com/dgrijalva/jwt-go"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/cookbook/twitter/model"
 | 
					 | 
				
			||||||
	mgo "gopkg.in/mgo.v2"
 | 
					 | 
				
			||||||
	"gopkg.in/mgo.v2/bson"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h *Handler) Signup(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
	// Bind
 | 
					 | 
				
			||||||
	u := &model.User{ID: bson.NewObjectId()}
 | 
					 | 
				
			||||||
	if err = c.Bind(u); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Validate
 | 
					 | 
				
			||||||
	if u.Email == "" || u.Password == "" {
 | 
					 | 
				
			||||||
		return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid email or password"}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Save user
 | 
					 | 
				
			||||||
	db := h.DB.Clone()
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("users").Insert(u); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusCreated, u)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h *Handler) Login(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
	// Bind
 | 
					 | 
				
			||||||
	u := new(model.User)
 | 
					 | 
				
			||||||
	if err = c.Bind(u); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Find user
 | 
					 | 
				
			||||||
	db := h.DB.Clone()
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("users").
 | 
					 | 
				
			||||||
		Find(bson.M{"email": u.Email, "password": u.Password}).One(u); err != nil {
 | 
					 | 
				
			||||||
		if err == mgo.ErrNotFound {
 | 
					 | 
				
			||||||
			return &echo.HTTPError{Code: http.StatusUnauthorized, Message: "invalid email or password"}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//-----
 | 
					 | 
				
			||||||
	// JWT
 | 
					 | 
				
			||||||
	//-----
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Create token
 | 
					 | 
				
			||||||
	token := jwt.New(jwt.SigningMethodHS256)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Set claims
 | 
					 | 
				
			||||||
	claims := token.Claims.(jwt.MapClaims)
 | 
					 | 
				
			||||||
	claims["id"] = u.ID
 | 
					 | 
				
			||||||
	claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Generate encoded token and send it as response
 | 
					 | 
				
			||||||
	u.Token, err = token.SignedString([]byte(Key))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u.Password = "" // Don't send password
 | 
					 | 
				
			||||||
	return c.JSON(http.StatusOK, u)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (h *Handler) Follow(c echo.Context) (err error) {
 | 
					 | 
				
			||||||
	userID := userIDFromToken(c)
 | 
					 | 
				
			||||||
	id := c.Param("id")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Add a follower to user
 | 
					 | 
				
			||||||
	db := h.DB.Clone()
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	if err = db.DB("twitter").C("users").
 | 
					 | 
				
			||||||
		UpdateId(bson.ObjectIdHex(id), bson.M{"$addToSet": bson.M{"followers": userID}}); err != nil {
 | 
					 | 
				
			||||||
		if err == mgo.ErrNotFound {
 | 
					 | 
				
			||||||
			return echo.ErrNotFound
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func userIDFromToken(c echo.Context) string {
 | 
					 | 
				
			||||||
	user := c.Get("user").(*jwt.Token)
 | 
					 | 
				
			||||||
	claims := user.Claims.(jwt.MapClaims)
 | 
					 | 
				
			||||||
	return claims["id"].(string)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/model/post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/model/post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,12 +0,0 @@
 | 
				
			|||||||
package model
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "gopkg.in/mgo.v2/bson"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	Post struct {
 | 
					 | 
				
			||||||
		ID      bson.ObjectId `json:"id" bson:"_id,omitempty"`
 | 
					 | 
				
			||||||
		To      string        `json:"to" bson:"to"`
 | 
					 | 
				
			||||||
		From    string        `json:"from" bson:"from"`
 | 
					 | 
				
			||||||
		Message string        `json:"message" bson:"message"`
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
							
								
								
									
										13
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/model/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/model/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,13 +0,0 @@
 | 
				
			|||||||
package model
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "gopkg.in/mgo.v2/bson"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type (
 | 
					 | 
				
			||||||
	User struct {
 | 
					 | 
				
			||||||
		ID        bson.ObjectId `json:"id" bson:"_id,omitempty"`
 | 
					 | 
				
			||||||
		Email     string        `json:"email" bson:"email"`
 | 
					 | 
				
			||||||
		Password  string        `json:"password,omitempty" bson:"password"`
 | 
					 | 
				
			||||||
		Token     string        `json:"token,omitempty" bson:"-"`
 | 
					 | 
				
			||||||
		Followers []string      `json:"followers,omitempty" bson:"followers,omitempty"`
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
							
								
								
									
										52
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/labstack/echo/cookbook/twitter/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,52 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/cookbook/twitter/handler"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
	"github.com/labstack/gommon/log"
 | 
					 | 
				
			||||||
	mgo "gopkg.in/mgo.v2"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Logger.SetLevel(log.ERROR)
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
 | 
					 | 
				
			||||||
		SigningKey: []byte(handler.Key),
 | 
					 | 
				
			||||||
		Skipper: func(c echo.Context) bool {
 | 
					 | 
				
			||||||
			// Skip authentication for and signup login requests
 | 
					 | 
				
			||||||
			if c.Path() == "/login" || c.Path() == "/signup" {
 | 
					 | 
				
			||||||
				return true
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return false
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Database connection
 | 
					 | 
				
			||||||
	db, err := mgo.Dial("localhost")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		e.Logger.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Create indices
 | 
					 | 
				
			||||||
	if err = db.Copy().DB("twitter").C("users").EnsureIndex(mgo.Index{
 | 
					 | 
				
			||||||
		Key:    []string{"email"},
 | 
					 | 
				
			||||||
		Unique: true,
 | 
					 | 
				
			||||||
	}); err != nil {
 | 
					 | 
				
			||||||
		log.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Initialize handler
 | 
					 | 
				
			||||||
	h := &handler.Handler{DB: db}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Routes
 | 
					 | 
				
			||||||
	e.POST("/signup", h.Signup)
 | 
					 | 
				
			||||||
	e.POST("/login", h.Login)
 | 
					 | 
				
			||||||
	e.POST("/follow/:id", h.Follow)
 | 
					 | 
				
			||||||
	e.POST("/posts", h.CreatePost)
 | 
					 | 
				
			||||||
	e.GET("/feed", h.FetchPost)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Start server
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										47
									
								
								vendor/github.com/labstack/echo/cookbook/websocket/gorilla/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/labstack/echo/cookbook/websocket/gorilla/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,47 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gorilla/websocket"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	upgrader = websocket.Upgrader{}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func hello(c echo.Context) error {
 | 
					 | 
				
			||||||
	ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer ws.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for {
 | 
					 | 
				
			||||||
		// Write
 | 
					 | 
				
			||||||
		err := ws.WriteMessage(websocket.TextMessage, []byte("Hello, Client!"))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Fatal(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Read
 | 
					 | 
				
			||||||
		_, msg, err := ws.ReadMessage()
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Fatal(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Printf("%s\n", msg)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
	e.Static("/", "../public")
 | 
					 | 
				
			||||||
	e.GET("/ws", hello)
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										41
									
								
								vendor/github.com/labstack/echo/cookbook/websocket/net/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/labstack/echo/cookbook/websocket/net/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,41 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/labstack/echo"
 | 
					 | 
				
			||||||
	"github.com/labstack/echo/middleware"
 | 
					 | 
				
			||||||
	"golang.org/x/net/websocket"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func hello(c echo.Context) error {
 | 
					 | 
				
			||||||
	websocket.Handler(func(ws *websocket.Conn) {
 | 
					 | 
				
			||||||
		defer ws.Close()
 | 
					 | 
				
			||||||
		for {
 | 
					 | 
				
			||||||
			// Write
 | 
					 | 
				
			||||||
			err := websocket.Message.Send(ws, "Hello, Client!")
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				log.Fatal(err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Read
 | 
					 | 
				
			||||||
			msg := ""
 | 
					 | 
				
			||||||
			err = websocket.Message.Receive(ws, &msg)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				log.Fatal(err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			fmt.Printf("%s\n", msg)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}).ServeHTTP(c.Response(), c.Request())
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func main() {
 | 
					 | 
				
			||||||
	e := echo.New()
 | 
					 | 
				
			||||||
	e.Use(middleware.Logger())
 | 
					 | 
				
			||||||
	e.Use(middleware.Recover())
 | 
					 | 
				
			||||||
	e.Static("/", "../public")
 | 
					 | 
				
			||||||
	e.GET("/ws", hello)
 | 
					 | 
				
			||||||
	e.Logger.Fatal(e.Start(":1323"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										124
									
								
								vendor/github.com/labstack/echo/echo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/labstack/echo/echo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -42,10 +42,11 @@ import (
 | 
				
			|||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	slog "log"
 | 
						stdLog "log"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -59,7 +60,7 @@ import (
 | 
				
			|||||||
type (
 | 
					type (
 | 
				
			||||||
	// Echo is the top-level framework instance.
 | 
						// Echo is the top-level framework instance.
 | 
				
			||||||
	Echo struct {
 | 
						Echo struct {
 | 
				
			||||||
		stdLogger        *slog.Logger
 | 
							stdLogger        *stdLog.Logger
 | 
				
			||||||
		colorer          *color.Color
 | 
							colorer          *color.Color
 | 
				
			||||||
		premiddleware    []MiddlewareFunc
 | 
							premiddleware    []MiddlewareFunc
 | 
				
			||||||
		middleware       []MiddlewareFunc
 | 
							middleware       []MiddlewareFunc
 | 
				
			||||||
@@ -73,20 +74,21 @@ type (
 | 
				
			|||||||
		TLSListener      net.Listener
 | 
							TLSListener      net.Listener
 | 
				
			||||||
		DisableHTTP2     bool
 | 
							DisableHTTP2     bool
 | 
				
			||||||
		Debug            bool
 | 
							Debug            bool
 | 
				
			||||||
 | 
							HideBanner       bool
 | 
				
			||||||
		HTTPErrorHandler HTTPErrorHandler
 | 
							HTTPErrorHandler HTTPErrorHandler
 | 
				
			||||||
		Binder           Binder
 | 
							Binder           Binder
 | 
				
			||||||
		Validator        Validator
 | 
							Validator        Validator
 | 
				
			||||||
		Renderer         Renderer
 | 
							Renderer         Renderer
 | 
				
			||||||
		AutoTLSManager   autocert.Manager
 | 
							AutoTLSManager   autocert.Manager
 | 
				
			||||||
		Mutex            sync.RWMutex
 | 
							// Mutex            sync.RWMutex
 | 
				
			||||||
		Logger           Logger
 | 
							Logger Logger
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Route contains a handler and information for matching against requests.
 | 
						// Route contains a handler and information for matching against requests.
 | 
				
			||||||
	Route struct {
 | 
						Route struct {
 | 
				
			||||||
		Method  string
 | 
							Method  string `json:"method"`
 | 
				
			||||||
		Path    string
 | 
							Path    string `json:"path"`
 | 
				
			||||||
		Handler string
 | 
							Handler string `json:"handler"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// HTTPError represents an error that occurred while handling a request.
 | 
						// HTTPError represents an error that occurred while handling a request.
 | 
				
			||||||
@@ -144,6 +146,8 @@ const (
 | 
				
			|||||||
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
 | 
						MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
 | 
				
			||||||
	MIMEApplicationXML                   = "application/xml"
 | 
						MIMEApplicationXML                   = "application/xml"
 | 
				
			||||||
	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
 | 
						MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
 | 
				
			||||||
 | 
						MIMETextXML                          = "text/xml"
 | 
				
			||||||
 | 
						MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + charsetUTF8
 | 
				
			||||||
	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
 | 
						MIMEApplicationForm                  = "application/x-www-form-urlencoded"
 | 
				
			||||||
	MIMEApplicationProtobuf              = "application/protobuf"
 | 
						MIMEApplicationProtobuf              = "application/protobuf"
 | 
				
			||||||
	MIMEApplicationMsgpack               = "application/msgpack"
 | 
						MIMEApplicationMsgpack               = "application/msgpack"
 | 
				
			||||||
@@ -161,27 +165,34 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Headers
 | 
					// Headers
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	HeaderAcceptEncoding                = "Accept-Encoding"
 | 
						HeaderAccept              = "Accept"
 | 
				
			||||||
	HeaderAllow                         = "Allow"
 | 
						HeaderAcceptEncoding      = "Accept-Encoding"
 | 
				
			||||||
	HeaderAuthorization                 = "Authorization"
 | 
						HeaderAllow               = "Allow"
 | 
				
			||||||
	HeaderContentDisposition            = "Content-Disposition"
 | 
						HeaderAuthorization       = "Authorization"
 | 
				
			||||||
	HeaderContentEncoding               = "Content-Encoding"
 | 
						HeaderContentDisposition  = "Content-Disposition"
 | 
				
			||||||
	HeaderContentLength                 = "Content-Length"
 | 
						HeaderContentEncoding     = "Content-Encoding"
 | 
				
			||||||
	HeaderContentType                   = "Content-Type"
 | 
						HeaderContentLength       = "Content-Length"
 | 
				
			||||||
	HeaderCookie                        = "Cookie"
 | 
						HeaderContentType         = "Content-Type"
 | 
				
			||||||
	HeaderSetCookie                     = "Set-Cookie"
 | 
						HeaderCookie              = "Cookie"
 | 
				
			||||||
	HeaderIfModifiedSince               = "If-Modified-Since"
 | 
						HeaderSetCookie           = "Set-Cookie"
 | 
				
			||||||
	HeaderLastModified                  = "Last-Modified"
 | 
						HeaderIfModifiedSince     = "If-Modified-Since"
 | 
				
			||||||
	HeaderLocation                      = "Location"
 | 
						HeaderLastModified        = "Last-Modified"
 | 
				
			||||||
	HeaderUpgrade                       = "Upgrade"
 | 
						HeaderLocation            = "Location"
 | 
				
			||||||
	HeaderVary                          = "Vary"
 | 
						HeaderUpgrade             = "Upgrade"
 | 
				
			||||||
	HeaderWWWAuthenticate               = "WWW-Authenticate"
 | 
						HeaderVary                = "Vary"
 | 
				
			||||||
	HeaderXForwardedProto               = "X-Forwarded-Proto"
 | 
						HeaderWWWAuthenticate     = "WWW-Authenticate"
 | 
				
			||||||
	HeaderXHTTPMethodOverride           = "X-HTTP-Method-Override"
 | 
						HeaderXForwardedFor       = "X-Forwarded-For"
 | 
				
			||||||
	HeaderXForwardedFor                 = "X-Forwarded-For"
 | 
						HeaderXForwardedProto     = "X-Forwarded-Proto"
 | 
				
			||||||
	HeaderXRealIP                       = "X-Real-IP"
 | 
						HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
 | 
				
			||||||
	HeaderServer                        = "Server"
 | 
						HeaderXForwardedSsl       = "X-Forwarded-Ssl"
 | 
				
			||||||
	HeaderOrigin                        = "Origin"
 | 
						HeaderXUrlScheme          = "X-Url-Scheme"
 | 
				
			||||||
 | 
						HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
 | 
				
			||||||
 | 
						HeaderXRealIP             = "X-Real-IP"
 | 
				
			||||||
 | 
						HeaderXRequestID          = "X-Request-ID"
 | 
				
			||||||
 | 
						HeaderServer              = "Server"
 | 
				
			||||||
 | 
						HeaderOrigin              = "Origin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Access control
 | 
				
			||||||
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
 | 
						HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
 | 
				
			||||||
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
 | 
						HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
 | 
				
			||||||
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
 | 
						HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
 | 
				
			||||||
@@ -200,6 +211,22 @@ const (
 | 
				
			|||||||
	HeaderXCSRFToken              = "X-CSRF-Token"
 | 
						HeaderXCSRFToken              = "X-CSRF-Token"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						version = "3.1.0"
 | 
				
			||||||
 | 
						website = "https://echo.labstack.com"
 | 
				
			||||||
 | 
						// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
 | 
				
			||||||
 | 
						banner = `
 | 
				
			||||||
 | 
					   ____    __
 | 
				
			||||||
 | 
					  / __/___/ /  ___
 | 
				
			||||||
 | 
					 / _// __/ _ \/ _ \
 | 
				
			||||||
 | 
					/___/\__/_//_/\___/ %s
 | 
				
			||||||
 | 
					High performance, minimalist Go web framework
 | 
				
			||||||
 | 
					%s
 | 
				
			||||||
 | 
					____________________________________O/_______
 | 
				
			||||||
 | 
					                                    O\
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	methods = [...]string{
 | 
						methods = [...]string{
 | 
				
			||||||
		CONNECT,
 | 
							CONNECT,
 | 
				
			||||||
@@ -219,6 +246,7 @@ var (
 | 
				
			|||||||
	ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
 | 
						ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
 | 
				
			||||||
	ErrNotFound                    = NewHTTPError(http.StatusNotFound)
 | 
						ErrNotFound                    = NewHTTPError(http.StatusNotFound)
 | 
				
			||||||
	ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
 | 
						ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
 | 
				
			||||||
 | 
						ErrForbidden                   = NewHTTPError(http.StatusForbidden)
 | 
				
			||||||
	ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
 | 
						ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
 | 
				
			||||||
	ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
 | 
						ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
 | 
				
			||||||
	ErrValidatorNotRegistered      = errors.New("Validator not registered")
 | 
						ErrValidatorNotRegistered      = errors.New("Validator not registered")
 | 
				
			||||||
@@ -255,7 +283,7 @@ func New() (e *Echo) {
 | 
				
			|||||||
	e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
 | 
						e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
 | 
				
			||||||
	e.Binder = &DefaultBinder{}
 | 
						e.Binder = &DefaultBinder{}
 | 
				
			||||||
	e.Logger.SetLevel(log.OFF)
 | 
						e.Logger.SetLevel(log.OFF)
 | 
				
			||||||
	e.stdLogger = slog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
 | 
						e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
 | 
				
			||||||
	e.pool.New = func() interface{} {
 | 
						e.pool.New = func() interface{} {
 | 
				
			||||||
		return e.NewContext(nil, nil)
 | 
							return e.NewContext(nil, nil)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -398,12 +426,16 @@ func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middlew
 | 
				
			|||||||
// Static registers a new route with path prefix to serve static files from the
 | 
					// Static registers a new route with path prefix to serve static files from the
 | 
				
			||||||
// provided root directory.
 | 
					// provided root directory.
 | 
				
			||||||
func (e *Echo) Static(prefix, root string) {
 | 
					func (e *Echo) Static(prefix, root string) {
 | 
				
			||||||
 | 
						if root == "" {
 | 
				
			||||||
 | 
							root = "." // For security we want to restrict to CWD.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	static(e, prefix, root)
 | 
						static(e, prefix, root)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func static(i i, prefix, root string) {
 | 
					func static(i i, prefix, root string) {
 | 
				
			||||||
	h := func(c Context) error {
 | 
						h := func(c Context) error {
 | 
				
			||||||
		return c.File(path.Join(root, c.Param("*")))
 | 
							name := filepath.Join(root, path.Clean("/"+c.Param("*"))) // "/"+ for security
 | 
				
			||||||
 | 
							return c.File(name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i.GET(prefix, h)
 | 
						i.GET(prefix, h)
 | 
				
			||||||
	if prefix == "/" {
 | 
						if prefix == "/" {
 | 
				
			||||||
@@ -430,7 +462,7 @@ func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...Middl
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return h(c)
 | 
							return h(c)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	r := Route{
 | 
						r := &Route{
 | 
				
			||||||
		Method:  method,
 | 
							Method:  method,
 | 
				
			||||||
		Path:    path,
 | 
							Path:    path,
 | 
				
			||||||
		Handler: name,
 | 
							Handler: name,
 | 
				
			||||||
@@ -476,8 +508,8 @@ func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Routes returns the registered routes.
 | 
					// Routes returns the registered routes.
 | 
				
			||||||
func (e *Echo) Routes() []Route {
 | 
					func (e *Echo) Routes() []*Route {
 | 
				
			||||||
	routes := []Route{}
 | 
						routes := []*Route{}
 | 
				
			||||||
	for _, v := range e.router.routes {
 | 
						for _, v := range e.router.routes {
 | 
				
			||||||
		routes = append(routes, v)
 | 
							routes = append(routes, v)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -499,8 +531,8 @@ func (e *Echo) ReleaseContext(c Context) {
 | 
				
			|||||||
// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
 | 
					// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
 | 
				
			||||||
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
					func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	// Acquire lock
 | 
						// Acquire lock
 | 
				
			||||||
	e.Mutex.RLock()
 | 
						// e.Mutex.RLock()
 | 
				
			||||||
	defer e.Mutex.RUnlock()
 | 
						// defer e.Mutex.RUnlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Acquire context
 | 
						// Acquire context
 | 
				
			||||||
	c := e.pool.Get().(*context)
 | 
						c := e.pool.Get().(*context)
 | 
				
			||||||
@@ -510,7 +542,10 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
	// Middleware
 | 
						// Middleware
 | 
				
			||||||
	h := func(c Context) error {
 | 
						h := func(c Context) error {
 | 
				
			||||||
		method := r.Method
 | 
							method := r.Method
 | 
				
			||||||
		path := r.URL.EscapedPath()
 | 
							path := r.URL.RawPath
 | 
				
			||||||
 | 
							if path == "" {
 | 
				
			||||||
 | 
								path = r.URL.Path
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		e.router.Find(method, path, c)
 | 
							e.router.Find(method, path, c)
 | 
				
			||||||
		h := c.Handler()
 | 
							h := c.Handler()
 | 
				
			||||||
		for i := len(e.middleware) - 1; i >= 0; i-- {
 | 
							for i := len(e.middleware) - 1; i >= 0; i-- {
 | 
				
			||||||
@@ -572,8 +607,15 @@ func (e *Echo) startTLS(address string) error {
 | 
				
			|||||||
func (e *Echo) StartServer(s *http.Server) (err error) {
 | 
					func (e *Echo) StartServer(s *http.Server) (err error) {
 | 
				
			||||||
	// Setup
 | 
						// Setup
 | 
				
			||||||
	e.colorer.SetOutput(e.Logger.Output())
 | 
						e.colorer.SetOutput(e.Logger.Output())
 | 
				
			||||||
	s.Handler = e
 | 
					 | 
				
			||||||
	s.ErrorLog = e.stdLogger
 | 
						s.ErrorLog = e.stdLogger
 | 
				
			||||||
 | 
						s.Handler = e
 | 
				
			||||||
 | 
						if e.Debug {
 | 
				
			||||||
 | 
							e.Logger.SetLevel(log.DEBUG)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !e.HideBanner {
 | 
				
			||||||
 | 
							e.colorer.Printf(banner, e.colorer.Red("v"+version), e.colorer.Blue(website))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if s.TLSConfig == nil {
 | 
						if s.TLSConfig == nil {
 | 
				
			||||||
		if e.Listener == nil {
 | 
							if e.Listener == nil {
 | 
				
			||||||
@@ -582,7 +624,9 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		e.colorer.Printf("⇛ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
 | 
							if !e.HideBanner {
 | 
				
			||||||
 | 
								e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return s.Serve(e.Listener)
 | 
							return s.Serve(e.Listener)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if e.TLSListener == nil {
 | 
						if e.TLSListener == nil {
 | 
				
			||||||
@@ -592,7 +636,9 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		e.TLSListener = tls.NewListener(l, s.TLSConfig)
 | 
							e.TLSListener = tls.NewListener(l, s.TLSConfig)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	e.colorer.Printf("⇛ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
 | 
						if !e.HideBanner {
 | 
				
			||||||
 | 
							e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return s.Serve(e.TLSListener)
 | 
						return s.Serve(e.TLSListener)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								vendor/github.com/labstack/echo/echo_go1.8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/labstack/echo/echo_go1.8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					// +build go1.8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						stdContext "context"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Close immediately stops the server.
 | 
				
			||||||
 | 
					// It internally calls `http.Server#Close()`.
 | 
				
			||||||
 | 
					func (e *Echo) Close() error {
 | 
				
			||||||
 | 
						if err := e.TLSServer.Close(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return e.Server.Close()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Shutdown stops server the gracefully.
 | 
				
			||||||
 | 
					// It internally calls `http.Server#Shutdown()`.
 | 
				
			||||||
 | 
					func (e *Echo) Shutdown(ctx stdContext.Context) error {
 | 
				
			||||||
 | 
						if err := e.TLSServer.Shutdown(ctx); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return e.Server.Shutdown(ctx)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								vendor/github.com/labstack/echo/group.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/labstack/echo/group.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,8 +1,12 @@
 | 
				
			|||||||
package echo
 | 
					package echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type (
 | 
					type (
 | 
				
			||||||
	// Group is a set of sub-routes for a specified route. It can be used for inner
 | 
						// Group is a set of sub-routes for a specified route. It can be used for inner
 | 
				
			||||||
	// routes that share a common middlware or functionality that should be separate
 | 
						// routes that share a common middleware or functionality that should be separate
 | 
				
			||||||
	// from the parent echo instance while still inheriting from it.
 | 
						// from the parent echo instance while still inheriting from it.
 | 
				
			||||||
	Group struct {
 | 
						Group struct {
 | 
				
			||||||
		prefix     string
 | 
							prefix     string
 | 
				
			||||||
@@ -14,6 +18,11 @@ type (
 | 
				
			|||||||
// Use implements `Echo#Use()` for sub-routes within the Group.
 | 
					// Use implements `Echo#Use()` for sub-routes within the Group.
 | 
				
			||||||
func (g *Group) Use(middleware ...MiddlewareFunc) {
 | 
					func (g *Group) Use(middleware ...MiddlewareFunc) {
 | 
				
			||||||
	g.middleware = append(g.middleware, middleware...)
 | 
						g.middleware = append(g.middleware, middleware...)
 | 
				
			||||||
 | 
						// Allow all requests to reach the group as they might get dropped if router
 | 
				
			||||||
 | 
						// doesn't find a match, making none of the group middleware process.
 | 
				
			||||||
 | 
						g.echo.Any(path.Clean(g.prefix+"/*"), func(c Context) error {
 | 
				
			||||||
 | 
							return ErrNotFound
 | 
				
			||||||
 | 
						}, g.middleware...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
 | 
					// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								vendor/github.com/labstack/echo/middleware/basic_auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/labstack/echo/middleware/basic_auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,6 +2,7 @@ package middleware
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/base64"
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/labstack/echo"
 | 
						"github.com/labstack/echo"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -15,20 +16,26 @@ type (
 | 
				
			|||||||
		// Validator is a function to validate BasicAuth credentials.
 | 
							// Validator is a function to validate BasicAuth credentials.
 | 
				
			||||||
		// Required.
 | 
							// Required.
 | 
				
			||||||
		Validator BasicAuthValidator
 | 
							Validator BasicAuthValidator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Realm is a string to define realm attribute of BasicAuth.
 | 
				
			||||||
 | 
							// Default value "Restricted".
 | 
				
			||||||
 | 
							Realm string
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// BasicAuthValidator defines a function to validate BasicAuth credentials.
 | 
						// BasicAuthValidator defines a function to validate BasicAuth credentials.
 | 
				
			||||||
	BasicAuthValidator func(string, string, echo.Context) bool
 | 
						BasicAuthValidator func(string, string, echo.Context) (bool, error)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	basic = "Basic"
 | 
						basic        = "Basic"
 | 
				
			||||||
 | 
						defaultRealm = "Restricted"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	// DefaultBasicAuthConfig is the default BasicAuth middleware config.
 | 
						// DefaultBasicAuthConfig is the default BasicAuth middleware config.
 | 
				
			||||||
	DefaultBasicAuthConfig = BasicAuthConfig{
 | 
						DefaultBasicAuthConfig = BasicAuthConfig{
 | 
				
			||||||
		Skipper: DefaultSkipper,
 | 
							Skipper: DefaultSkipper,
 | 
				
			||||||
 | 
							Realm:   defaultRealm,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -52,6 +59,9 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
	if config.Skipper == nil {
 | 
						if config.Skipper == nil {
 | 
				
			||||||
		config.Skipper = DefaultBasicAuthConfig.Skipper
 | 
							config.Skipper = DefaultBasicAuthConfig.Skipper
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if config.Realm == "" {
 | 
				
			||||||
 | 
							config.Realm = defaultRealm
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
						return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
				
			||||||
		return func(c echo.Context) error {
 | 
							return func(c echo.Context) error {
 | 
				
			||||||
@@ -71,15 +81,25 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
				for i := 0; i < len(cred); i++ {
 | 
									for i := 0; i < len(cred); i++ {
 | 
				
			||||||
					if cred[i] == ':' {
 | 
										if cred[i] == ':' {
 | 
				
			||||||
						// Verify credentials
 | 
											// Verify credentials
 | 
				
			||||||
						if config.Validator(cred[:i], cred[i+1:], c) {
 | 
											valid, err := config.Validator(cred[:i], cred[i+1:], c)
 | 
				
			||||||
 | 
											if err != nil {
 | 
				
			||||||
 | 
												return err
 | 
				
			||||||
 | 
											} else if valid {
 | 
				
			||||||
							return next(c)
 | 
												return next(c)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								realm := ""
 | 
				
			||||||
 | 
								if config.Realm == defaultRealm {
 | 
				
			||||||
 | 
									realm = defaultRealm
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									realm = strconv.Quote(config.Realm)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Need to return `401` for browsers to pop-up login box.
 | 
								// Need to return `401` for browsers to pop-up login box.
 | 
				
			||||||
			c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm=Restricted")
 | 
								c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm="+realm)
 | 
				
			||||||
			return echo.ErrUnauthorized
 | 
								return echo.ErrUnauthorized
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								vendor/github.com/labstack/echo/middleware/compress.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/labstack/echo/middleware/compress.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -108,8 +108,8 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) {
 | 
				
			|||||||
	return w.Writer.Write(b)
 | 
						return w.Writer.Write(b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w *gzipResponseWriter) Flush() error {
 | 
					func (w *gzipResponseWriter) Flush() {
 | 
				
			||||||
	return w.Writer.(*gzip.Writer).Flush()
 | 
						w.Writer.(*gzip.Writer).Flush()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
 | 
					func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/labstack/echo/middleware/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/labstack/echo/middleware/jwt.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -91,7 +91,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
		config.Skipper = DefaultJWTConfig.Skipper
 | 
							config.Skipper = DefaultJWTConfig.Skipper
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if config.SigningKey == nil {
 | 
						if config.SigningKey == nil {
 | 
				
			||||||
		panic("jwt middleware requires signing key")
 | 
							panic("echo: jwt middleware requires signing key")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if config.SigningMethod == "" {
 | 
						if config.SigningMethod == "" {
 | 
				
			||||||
		config.SigningMethod = DefaultJWTConfig.SigningMethod
 | 
							config.SigningMethod = DefaultJWTConfig.SigningMethod
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								vendor/github.com/labstack/echo/middleware/key_auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/labstack/echo/middleware/key_auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -32,7 +32,7 @@ type (
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// KeyAuthValidator defines a function to validate KeyAuth credentials.
 | 
						// KeyAuthValidator defines a function to validate KeyAuth credentials.
 | 
				
			||||||
	KeyAuthValidator func(string, echo.Context) bool
 | 
						KeyAuthValidator func(string, echo.Context) (bool, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keyExtractor func(echo.Context) (string, error)
 | 
						keyExtractor func(echo.Context) (string, error)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -94,7 +94,10 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return echo.NewHTTPError(http.StatusBadRequest, err.Error())
 | 
									return echo.NewHTTPError(http.StatusBadRequest, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if config.Validator(key, c) {
 | 
								valid, err := config.Validator(key, c)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								} else if valid {
 | 
				
			||||||
				return next(c)
 | 
									return next(c)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								vendor/github.com/labstack/echo/middleware/logger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/labstack/echo/middleware/logger.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -26,7 +26,7 @@ type (
 | 
				
			|||||||
		// - time_unix_nano
 | 
							// - time_unix_nano
 | 
				
			||||||
		// - time_rfc3339
 | 
							// - time_rfc3339
 | 
				
			||||||
		// - time_rfc3339_nano
 | 
							// - time_rfc3339_nano
 | 
				
			||||||
		// - id (Request ID - Not implemented)
 | 
							// - id (Request ID)
 | 
				
			||||||
		// - remote_ip
 | 
							// - remote_ip
 | 
				
			||||||
		// - uri
 | 
							// - uri
 | 
				
			||||||
		// - host
 | 
							// - host
 | 
				
			||||||
@@ -62,7 +62,7 @@ var (
 | 
				
			|||||||
	// DefaultLoggerConfig is the default Logger middleware config.
 | 
						// DefaultLoggerConfig is the default Logger middleware config.
 | 
				
			||||||
	DefaultLoggerConfig = LoggerConfig{
 | 
						DefaultLoggerConfig = LoggerConfig{
 | 
				
			||||||
		Skipper: DefaultSkipper,
 | 
							Skipper: DefaultSkipper,
 | 
				
			||||||
		Format: `{"time":"${time_rfc3339_nano}","remote_ip":"${remote_ip}","host":"${host}",` +
 | 
							Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}","host":"${host}",` +
 | 
				
			||||||
			`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
 | 
								`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
 | 
				
			||||||
			`"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
 | 
								`"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
 | 
				
			||||||
			`"bytes_out":${bytes_out}}` + "\n",
 | 
								`"bytes_out":${bytes_out}}` + "\n",
 | 
				
			||||||
@@ -126,6 +126,12 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
					return buf.WriteString(time.Now().Format(time.RFC3339))
 | 
										return buf.WriteString(time.Now().Format(time.RFC3339))
 | 
				
			||||||
				case "time_rfc3339_nano":
 | 
									case "time_rfc3339_nano":
 | 
				
			||||||
					return buf.WriteString(time.Now().Format(time.RFC3339Nano))
 | 
										return buf.WriteString(time.Now().Format(time.RFC3339Nano))
 | 
				
			||||||
 | 
									case "id":
 | 
				
			||||||
 | 
										id := req.Header.Get(echo.HeaderXRequestID)
 | 
				
			||||||
 | 
										if id == "" {
 | 
				
			||||||
 | 
											id = res.Header().Get(echo.HeaderXRequestID)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return buf.WriteString(id)
 | 
				
			||||||
				case "remote_ip":
 | 
									case "remote_ip":
 | 
				
			||||||
					return buf.WriteString(c.RealIP())
 | 
										return buf.WriteString(c.RealIP())
 | 
				
			||||||
				case "host":
 | 
									case "host":
 | 
				
			||||||
@@ -177,6 +183,11 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
						return buf.Write([]byte(c.QueryParam(tag[6:])))
 | 
											return buf.Write([]byte(c.QueryParam(tag[6:])))
 | 
				
			||||||
					case strings.HasPrefix(tag, "form:"):
 | 
										case strings.HasPrefix(tag, "form:"):
 | 
				
			||||||
						return buf.Write([]byte(c.FormValue(tag[5:])))
 | 
											return buf.Write([]byte(c.FormValue(tag[5:])))
 | 
				
			||||||
 | 
										case strings.HasPrefix(tag, "cookie:"):
 | 
				
			||||||
 | 
											cookie, err := c.Cookie(tag[7:])
 | 
				
			||||||
 | 
											if err == nil {
 | 
				
			||||||
 | 
												return buf.Write([]byte(cookie.Value))
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return 0, nil
 | 
									return 0, nil
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/labstack/echo/middleware/middleware.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/labstack/echo/middleware/middleware.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -9,6 +9,6 @@ type (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DefaultSkipper returns false which processes the middleware.
 | 
					// DefaultSkipper returns false which processes the middleware.
 | 
				
			||||||
func DefaultSkipper(c echo.Context) bool {
 | 
					func DefaultSkipper(echo.Context) bool {
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										160
									
								
								vendor/github.com/labstack/echo/middleware/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/labstack/echo/middleware/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
				
			|||||||
 | 
					package middleware
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httputil"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"sync/atomic"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/labstack/echo"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Handle TLS proxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type (
 | 
				
			||||||
 | 
						// ProxyConfig defines the config for Proxy middleware.
 | 
				
			||||||
 | 
						ProxyConfig struct {
 | 
				
			||||||
 | 
							// Skipper defines a function to skip middleware.
 | 
				
			||||||
 | 
							Skipper Skipper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Balancer defines a load balancing technique.
 | 
				
			||||||
 | 
							// Required.
 | 
				
			||||||
 | 
							// Possible values:
 | 
				
			||||||
 | 
							// - RandomBalancer
 | 
				
			||||||
 | 
							// - RoundRobinBalancer
 | 
				
			||||||
 | 
							Balancer ProxyBalancer
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ProxyTarget defines the upstream target.
 | 
				
			||||||
 | 
						ProxyTarget struct {
 | 
				
			||||||
 | 
							URL *url.URL
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RandomBalancer implements a random load balancing technique.
 | 
				
			||||||
 | 
						RandomBalancer struct {
 | 
				
			||||||
 | 
							Targets []*ProxyTarget
 | 
				
			||||||
 | 
							random  *rand.Rand
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RoundRobinBalancer implements a round-robin load balancing technique.
 | 
				
			||||||
 | 
						RoundRobinBalancer struct {
 | 
				
			||||||
 | 
							Targets []*ProxyTarget
 | 
				
			||||||
 | 
							i       uint32
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ProxyBalancer defines an interface to implement a load balancing technique.
 | 
				
			||||||
 | 
						ProxyBalancer interface {
 | 
				
			||||||
 | 
							Next() *ProxyTarget
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func proxyHTTP(t *ProxyTarget) http.Handler {
 | 
				
			||||||
 | 
						return httputil.NewSingleHostReverseProxy(t.URL)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
 | 
				
			||||||
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							h, ok := w.(http.Hijacker)
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								c.Error(errors.New("proxy raw, not a hijacker"))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							in, _, err := h.Hijack()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", r.URL, err))
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							defer in.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							out, err := net.Dial("tcp", t.URL.Host)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", r.URL, err))
 | 
				
			||||||
 | 
								c.Error(he)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							defer out.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = r.Write(out)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request copy error=%v, url=%s", r.URL, err))
 | 
				
			||||||
 | 
								c.Error(he)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							errc := make(chan error, 2)
 | 
				
			||||||
 | 
							cp := func(dst io.Writer, src io.Reader) {
 | 
				
			||||||
 | 
								_, err := io.Copy(dst, src)
 | 
				
			||||||
 | 
								errc <- err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							go cp(out, in)
 | 
				
			||||||
 | 
							go cp(in, out)
 | 
				
			||||||
 | 
							err = <-errc
 | 
				
			||||||
 | 
							if err != nil && err != io.EOF {
 | 
				
			||||||
 | 
								c.Logger().Errorf("proxy raw, error=%v, url=%s", r.URL, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Next randomly returns an upstream target.
 | 
				
			||||||
 | 
					func (r *RandomBalancer) Next() *ProxyTarget {
 | 
				
			||||||
 | 
						if r.random == nil {
 | 
				
			||||||
 | 
							r.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return r.Targets[r.random.Intn(len(r.Targets))]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Next returns an upstream target using round-robin technique.
 | 
				
			||||||
 | 
					func (r *RoundRobinBalancer) Next() *ProxyTarget {
 | 
				
			||||||
 | 
						r.i = r.i % uint32(len(r.Targets))
 | 
				
			||||||
 | 
						t := r.Targets[r.i]
 | 
				
			||||||
 | 
						atomic.AddUint32(&r.i, 1)
 | 
				
			||||||
 | 
						return t
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Proxy returns an HTTP/WebSocket reverse proxy middleware.
 | 
				
			||||||
 | 
					func Proxy(config ProxyConfig) echo.MiddlewareFunc {
 | 
				
			||||||
 | 
						// Defaults
 | 
				
			||||||
 | 
						if config.Skipper == nil {
 | 
				
			||||||
 | 
							config.Skipper = DefaultLoggerConfig.Skipper
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if config.Balancer == nil {
 | 
				
			||||||
 | 
							panic("echo: proxy middleware requires balancer")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
				
			||||||
 | 
							return func(c echo.Context) (err error) {
 | 
				
			||||||
 | 
								req := c.Request()
 | 
				
			||||||
 | 
								res := c.Response()
 | 
				
			||||||
 | 
								tgt := config.Balancer.Next()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Fix header
 | 
				
			||||||
 | 
								if req.Header.Get(echo.HeaderXRealIP) == "" {
 | 
				
			||||||
 | 
									req.Header.Set(echo.HeaderXRealIP, c.RealIP())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if req.Header.Get(echo.HeaderXForwardedProto) == "" {
 | 
				
			||||||
 | 
									req.Header.Set(echo.HeaderXForwardedProto, c.Scheme())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if c.IsWebSocket() && req.Header.Get(echo.HeaderXForwardedFor) == "" { // For HTTP, it is automatically set by Go HTTP reverse proxy.
 | 
				
			||||||
 | 
									req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Proxy
 | 
				
			||||||
 | 
								switch {
 | 
				
			||||||
 | 
								case c.IsWebSocket():
 | 
				
			||||||
 | 
									proxyRaw(tgt, c).ServeHTTP(res, req)
 | 
				
			||||||
 | 
								case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									proxyHTTP(tgt).ServeHTTP(res, req)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								vendor/github.com/labstack/echo/middleware/request_id.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/labstack/echo/middleware/request_id.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					package middleware
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/labstack/echo"
 | 
				
			||||||
 | 
						"github.com/labstack/gommon/random"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type (
 | 
				
			||||||
 | 
						// RequestIDConfig defines the config for RequestID middleware.
 | 
				
			||||||
 | 
						RequestIDConfig struct {
 | 
				
			||||||
 | 
							// Skipper defines a function to skip middleware.
 | 
				
			||||||
 | 
							Skipper Skipper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Generator defines a function to generate an ID.
 | 
				
			||||||
 | 
							// Optional. Default value random.String(32).
 | 
				
			||||||
 | 
							Generator func() string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// DefaultRequestIDConfig is the default RequestID middleware config.
 | 
				
			||||||
 | 
						DefaultRequestIDConfig = RequestIDConfig{
 | 
				
			||||||
 | 
							Skipper:   DefaultSkipper,
 | 
				
			||||||
 | 
							Generator: generator,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RequestID returns a X-Request-ID middleware.
 | 
				
			||||||
 | 
					func RequestID() echo.MiddlewareFunc {
 | 
				
			||||||
 | 
						return RequestIDWithConfig(DefaultRequestIDConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RequestIDWithConfig returns a X-Request-ID middleware with config.
 | 
				
			||||||
 | 
					func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {
 | 
				
			||||||
 | 
						// Defaults
 | 
				
			||||||
 | 
						if config.Skipper == nil {
 | 
				
			||||||
 | 
							config.Skipper = DefaultRequestIDConfig.Skipper
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if config.Generator == nil {
 | 
				
			||||||
 | 
							config.Generator = generator
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
				
			||||||
 | 
							return func(c echo.Context) error {
 | 
				
			||||||
 | 
								if config.Skipper(c) {
 | 
				
			||||||
 | 
									return next(c)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req := c.Request()
 | 
				
			||||||
 | 
								res := c.Response()
 | 
				
			||||||
 | 
								rid := req.Header.Get(echo.HeaderXRequestID)
 | 
				
			||||||
 | 
								if rid == "" {
 | 
				
			||||||
 | 
									rid = config.Generator()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								res.Header().Set(echo.HeaderXRequestID, rid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return next(c)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generator() string {
 | 
				
			||||||
 | 
						return random.String(32)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								vendor/github.com/labstack/echo/middleware/static.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/labstack/echo/middleware/static.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,7 +3,9 @@ package middleware
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/labstack/echo"
 | 
						"github.com/labstack/echo"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -53,6 +55,9 @@ func Static(root string) echo.MiddlewareFunc {
 | 
				
			|||||||
// See `Static()`.
 | 
					// See `Static()`.
 | 
				
			||||||
func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 | 
					func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 | 
				
			||||||
	// Defaults
 | 
						// Defaults
 | 
				
			||||||
 | 
						if config.Root == "" {
 | 
				
			||||||
 | 
							config.Root = "." // For security we want to restrict to CWD.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if config.Skipper == nil {
 | 
						if config.Skipper == nil {
 | 
				
			||||||
		config.Skipper = DefaultStaticConfig.Skipper
 | 
							config.Skipper = DefaultStaticConfig.Skipper
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -62,26 +67,44 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
						return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
				
			||||||
		return func(c echo.Context) error {
 | 
							return func(c echo.Context) error {
 | 
				
			||||||
			p := c.Param("*")
 | 
								if config.Skipper(c) {
 | 
				
			||||||
			name := filepath.Join(config.Root, p)
 | 
									return next(c)
 | 
				
			||||||
			fi, err := os.Stat(name)
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								p := c.Request().URL.Path
 | 
				
			||||||
 | 
								if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
 | 
				
			||||||
 | 
									p = c.Param("*")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								fi, err := os.Stat(name)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				if os.IsNotExist(err) {
 | 
									if os.IsNotExist(err) {
 | 
				
			||||||
					if config.HTML5 {
 | 
										if config.HTML5 && path.Ext(p) == "" {
 | 
				
			||||||
						return c.File(filepath.Join(config.Root, config.Index))
 | 
											return c.File(filepath.Join(config.Root, config.Index))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return echo.ErrNotFound
 | 
										return next(c)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if fi.IsDir() {
 | 
								if fi.IsDir() {
 | 
				
			||||||
				if config.Browse {
 | 
									index := filepath.Join(name, config.Index)
 | 
				
			||||||
					return listDir(name, c.Response())
 | 
									fi, err = os.Stat(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										if config.Browse {
 | 
				
			||||||
 | 
											return listDir(name, c.Response())
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if os.IsNotExist(err) {
 | 
				
			||||||
 | 
											return next(c)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return c.File(filepath.Join(name, config.Index))
 | 
					
 | 
				
			||||||
 | 
									return c.File(index)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return c.File(name)
 | 
								return c.File(name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								vendor/github.com/labstack/echo/router.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/labstack/echo/router.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -7,7 +7,7 @@ type (
 | 
				
			|||||||
	// request matching and URL path parameter parsing.
 | 
						// request matching and URL path parameter parsing.
 | 
				
			||||||
	Router struct {
 | 
						Router struct {
 | 
				
			||||||
		tree   *node
 | 
							tree   *node
 | 
				
			||||||
		routes map[string]Route
 | 
							routes map[string]*Route
 | 
				
			||||||
		echo   *Echo
 | 
							echo   *Echo
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	node struct {
 | 
						node struct {
 | 
				
			||||||
@@ -47,7 +47,7 @@ func NewRouter(e *Echo) *Router {
 | 
				
			|||||||
		tree: &node{
 | 
							tree: &node{
 | 
				
			||||||
			methodHandler: new(methodHandler),
 | 
								methodHandler: new(methodHandler),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		routes: make(map[string]Route),
 | 
							routes: map[string]*Route{},
 | 
				
			||||||
		echo:   e,
 | 
							echo:   e,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -101,7 +101,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cn := r.tree // Current node as root
 | 
						cn := r.tree // Current node as root
 | 
				
			||||||
	if cn == nil {
 | 
						if cn == nil {
 | 
				
			||||||
		panic("echo ⇛ invalid method")
 | 
							panic("echo: invalid method")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	search := path
 | 
						search := path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -296,18 +296,19 @@ func (n *node) checkMethodNotAllowed() HandlerFunc {
 | 
				
			|||||||
// - Get context from `Echo#AcquireContext()`
 | 
					// - Get context from `Echo#AcquireContext()`
 | 
				
			||||||
// - Reset it `Context#Reset()`
 | 
					// - Reset it `Context#Reset()`
 | 
				
			||||||
// - Return it `Echo#ReleaseContext()`.
 | 
					// - Return it `Echo#ReleaseContext()`.
 | 
				
			||||||
func (r *Router) Find(method, path string, context Context) {
 | 
					func (r *Router) Find(method, path string, c Context) {
 | 
				
			||||||
	context.SetPath(path)
 | 
						ctx := c.(*context)
 | 
				
			||||||
 | 
						ctx.path = path
 | 
				
			||||||
	cn := r.tree // Current node as root
 | 
						cn := r.tree // Current node as root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		search  = path
 | 
							search  = path
 | 
				
			||||||
		c       *node  // Child node
 | 
							child   *node         // Child node
 | 
				
			||||||
		n       int    // Param counter
 | 
							n       int           // Param counter
 | 
				
			||||||
		nk      kind   // Next kind
 | 
							nk      kind          // Next kind
 | 
				
			||||||
		nn      *node  // Next node
 | 
							nn      *node         // Next node
 | 
				
			||||||
		ns      string // Next search
 | 
							ns      string        // Next search
 | 
				
			||||||
		pvalues = context.ParamValues()
 | 
							pvalues = ctx.pvalues // Use the internal slice so the interface can keep the illusion of a dynamic slice
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Search order static > param > any
 | 
						// Search order static > param > any
 | 
				
			||||||
@@ -352,20 +353,20 @@ func (r *Router) Find(method, path string, context Context) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Static node
 | 
							// Static node
 | 
				
			||||||
		if c = cn.findChild(search[0], skind); c != nil {
 | 
							if child = cn.findChild(search[0], skind); child != nil {
 | 
				
			||||||
			// Save next
 | 
								// Save next
 | 
				
			||||||
			if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
 | 
								if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
 | 
				
			||||||
				nk = pkind
 | 
									nk = pkind
 | 
				
			||||||
				nn = cn
 | 
									nn = cn
 | 
				
			||||||
				ns = search
 | 
									ns = search
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			cn = c
 | 
								cn = child
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Param node
 | 
							// Param node
 | 
				
			||||||
	Param:
 | 
						Param:
 | 
				
			||||||
		if c = cn.findChildByKind(pkind); c != nil {
 | 
							if child = cn.findChildByKind(pkind); child != nil {
 | 
				
			||||||
			// Issue #378
 | 
								// Issue #378
 | 
				
			||||||
			if len(pvalues) == n {
 | 
								if len(pvalues) == n {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
@@ -378,7 +379,7 @@ func (r *Router) Find(method, path string, context Context) {
 | 
				
			|||||||
				ns = search
 | 
									ns = search
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cn = c
 | 
								cn = child
 | 
				
			||||||
			i, l := 0, len(search)
 | 
								i, l := 0, len(search)
 | 
				
			||||||
			for ; i < l && search[i] != '/'; i++ {
 | 
								for ; i < l && search[i] != '/'; i++ {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -409,13 +410,13 @@ func (r *Router) Find(method, path string, context Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
End:
 | 
					End:
 | 
				
			||||||
	context.SetHandler(cn.findHandler(method))
 | 
						ctx.handler = cn.findHandler(method)
 | 
				
			||||||
	context.SetPath(cn.ppath)
 | 
						ctx.path = cn.ppath
 | 
				
			||||||
	context.SetParamNames(cn.pnames...)
 | 
						ctx.pnames = cn.pnames
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// NOTE: Slow zone...
 | 
						// NOTE: Slow zone...
 | 
				
			||||||
	if context.Handler() == nil {
 | 
						if ctx.handler == nil {
 | 
				
			||||||
		context.SetHandler(cn.checkMethodNotAllowed())
 | 
							ctx.handler = cn.checkMethodNotAllowed()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Dig further for any, might have an empty value for *, e.g.
 | 
							// Dig further for any, might have an empty value for *, e.g.
 | 
				
			||||||
		// serving a directory. Issue #207.
 | 
							// serving a directory. Issue #207.
 | 
				
			||||||
@@ -423,12 +424,12 @@ End:
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if h := cn.findHandler(method); h != nil {
 | 
							if h := cn.findHandler(method); h != nil {
 | 
				
			||||||
			context.SetHandler(h)
 | 
								ctx.handler = h
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			context.SetHandler(cn.checkMethodNotAllowed())
 | 
								ctx.handler = cn.checkMethodNotAllowed()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		context.SetPath(cn.ppath)
 | 
							ctx.path = cn.ppath
 | 
				
			||||||
		context.SetParamNames(cn.pnames...)
 | 
							ctx.pnames = cn.pnames
 | 
				
			||||||
		pvalues[len(cn.pnames)-1] = ""
 | 
							pvalues[len(cn.pnames)-1] = ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										42
									
								
								vendor/github.com/labstack/gommon/random/random.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/labstack/gommon/random/random.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,22 +2,24 @@ package random
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type (
 | 
					type (
 | 
				
			||||||
	Random struct {
 | 
						Random struct {
 | 
				
			||||||
		charset Charset
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	Charset string
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Charsets
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	Alphanumeric Charset = Alphabetic + Numeric
 | 
						Uppercase    string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
				
			||||||
	Alphabetic   Charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
						Lowercase           = "abcdefghijklmnopqrstuvwxyz"
 | 
				
			||||||
	Numeric      Charset = "0123456789"
 | 
						Alphabetic          = Uppercase + Lowercase
 | 
				
			||||||
	Hex          Charset = Numeric + "abcdef"
 | 
						Numeric             = "0123456789"
 | 
				
			||||||
 | 
						Alphanumeric        = Alphabetic + Numeric
 | 
				
			||||||
 | 
						Symbols             = "`" + `~!@#$%^&*()-_+={}[]|\;:"<>,./?`
 | 
				
			||||||
 | 
						Hex                 = Numeric + "abcdef"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -26,27 +28,21 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func New() *Random {
 | 
					func New() *Random {
 | 
				
			||||||
	rand.Seed(time.Now().UnixNano())
 | 
						rand.Seed(time.Now().UnixNano())
 | 
				
			||||||
	return &Random{
 | 
						return new(Random)
 | 
				
			||||||
		charset: Alphanumeric,
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *Random) String(length uint8, charsets ...string) string {
 | 
				
			||||||
 | 
						charset := strings.Join(charsets, "")
 | 
				
			||||||
 | 
						if charset == "" {
 | 
				
			||||||
 | 
							charset = Alphanumeric
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *Random) SetCharset(c Charset) {
 | 
					 | 
				
			||||||
	r.charset = c
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *Random) String(length uint8) string {
 | 
					 | 
				
			||||||
	b := make([]byte, length)
 | 
						b := make([]byte, length)
 | 
				
			||||||
	for i := range b {
 | 
						for i := range b {
 | 
				
			||||||
		b[i] = r.charset[rand.Int63()%int64(len(r.charset))]
 | 
							b[i] = charset[rand.Int63()%int64(len(charset))]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return string(b)
 | 
						return string(b)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func SetCharset(c Charset) {
 | 
					func String(length uint8, charsets ...string) string {
 | 
				
			||||||
	global.SetCharset(c)
 | 
						return global.String(length, charsets...)
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func String(length uint8) string {
 | 
					 | 
				
			||||||
	return global.String(length)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
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"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,57 +0,0 @@
 | 
				
			|||||||
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)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,42 +0,0 @@
 | 
				
			|||||||
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))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
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()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
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?")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										5
									
								
								vendor/github.com/sromku/go-gitter/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/sromku/go-gitter/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -137,7 +137,10 @@ func (stream *Stream) connect() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	res, err := stream.gitter.getResponse(stream.url, stream)
 | 
						res, err := stream.gitter.getResponse(stream.url, stream)
 | 
				
			||||||
	if err != nil || res.StatusCode != 200 {
 | 
						if err != nil || res.StatusCode != 200 {
 | 
				
			||||||
		stream.gitter.log(fmt.Sprintf("Failed to get response, trying reconnect (Status code: %v)", res.StatusCode))
 | 
							stream.gitter.log("Failed to get response, trying reconnect")
 | 
				
			||||||
 | 
							if res != nil {
 | 
				
			||||||
 | 
								stream.gitter.log(fmt.Sprintf("Status code: %v", res.StatusCode))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		stream.gitter.log(err)
 | 
							stream.gitter.log(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// sleep and wait
 | 
							// sleep and wait
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								vendor/github.com/valyala/fasttemplate/unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/valyala/fasttemplate/unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					// +build !appengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package fasttemplate
 | 
					package fasttemplate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								vendor/github.com/valyala/fasttemplate/unsafe_gae.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/valyala/fasttemplate/unsafe_gae.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					// +build appengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package fasttemplate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func unsafeBytes2String(b []byte) string {
 | 
				
			||||||
 | 
						return string(b)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func unsafeString2Bytes(s string) []byte {
 | 
				
			||||||
 | 
						return []byte(s)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							@@ -53,7 +53,7 @@
 | 
				
			|||||||
			"importpath": "github.com/dgrijalva/jwt-go",
 | 
								"importpath": "github.com/dgrijalva/jwt-go",
 | 
				
			||||||
			"repository": "https://github.com/dgrijalva/jwt-go",
 | 
								"repository": "https://github.com/dgrijalva/jwt-go",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "2268707a8f0843315e2004ee4f1d021dc08baedf",
 | 
								"revision": "6c8dedd55f8a2e41f605de6d5d66e51ed1f299fc",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -170,7 +170,7 @@
 | 
				
			|||||||
			"importpath": "github.com/labstack/echo",
 | 
								"importpath": "github.com/labstack/echo",
 | 
				
			||||||
			"repository": "https://github.com/labstack/echo",
 | 
								"repository": "https://github.com/labstack/echo",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "0b53f397ad7709a27d37500a67735c0a639b5c38",
 | 
								"revision": "c3887ebb131d996411cf13a9688ab02c8dba599e",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -178,7 +178,7 @@
 | 
				
			|||||||
			"importpath": "github.com/labstack/gommon/bytes",
 | 
								"importpath": "github.com/labstack/gommon/bytes",
 | 
				
			||||||
			"repository": "https://github.com/labstack/gommon",
 | 
								"repository": "https://github.com/labstack/gommon",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "f72d3c883f8ea180da8f085dd320804c41332ad1",
 | 
								"revision": "1121fd3e243c202482226a7afe4dcd07ffc4139a",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"path": "/bytes",
 | 
								"path": "/bytes",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
@@ -187,7 +187,7 @@
 | 
				
			|||||||
			"importpath": "github.com/labstack/gommon/color",
 | 
								"importpath": "github.com/labstack/gommon/color",
 | 
				
			||||||
			"repository": "https://github.com/labstack/gommon",
 | 
								"repository": "https://github.com/labstack/gommon",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "f72d3c883f8ea180da8f085dd320804c41332ad1",
 | 
								"revision": "1121fd3e243c202482226a7afe4dcd07ffc4139a",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"path": "/color",
 | 
								"path": "/color",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
@@ -196,7 +196,7 @@
 | 
				
			|||||||
			"importpath": "github.com/labstack/gommon/log",
 | 
								"importpath": "github.com/labstack/gommon/log",
 | 
				
			||||||
			"repository": "https://github.com/labstack/gommon",
 | 
								"repository": "https://github.com/labstack/gommon",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "f72d3c883f8ea180da8f085dd320804c41332ad1",
 | 
								"revision": "1121fd3e243c202482226a7afe4dcd07ffc4139a",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"path": "/log",
 | 
								"path": "/log",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
@@ -205,7 +205,7 @@
 | 
				
			|||||||
			"importpath": "github.com/labstack/gommon/random",
 | 
								"importpath": "github.com/labstack/gommon/random",
 | 
				
			||||||
			"repository": "https://github.com/labstack/gommon",
 | 
								"repository": "https://github.com/labstack/gommon",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "f72d3c883f8ea180da8f085dd320804c41332ad1",
 | 
								"revision": "1121fd3e243c202482226a7afe4dcd07ffc4139a",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"path": "/random",
 | 
								"path": "/random",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
@@ -384,7 +384,7 @@
 | 
				
			|||||||
			"importpath": "github.com/sromku/go-gitter",
 | 
								"importpath": "github.com/sromku/go-gitter",
 | 
				
			||||||
			"repository": "https://github.com/sromku/go-gitter",
 | 
								"repository": "https://github.com/sromku/go-gitter",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "0b9f26da1844acd3c6c2fd4ee2bdd30eb1a40568",
 | 
								"revision": "16aadfbb65c6641501ea8eebb6bcf23b9011912b",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -424,7 +424,7 @@
 | 
				
			|||||||
			"importpath": "github.com/valyala/fasttemplate",
 | 
								"importpath": "github.com/valyala/fasttemplate",
 | 
				
			||||||
			"repository": "https://github.com/valyala/fasttemplate",
 | 
								"repository": "https://github.com/valyala/fasttemplate",
 | 
				
			||||||
			"vcs": "git",
 | 
								"vcs": "git",
 | 
				
			||||||
			"revision": "d090d65668a286d9a180d43a19dfdc5dcad8fe88",
 | 
								"revision": "dcecefd839c4193db0d35b88ec65b4c12d360ab0",
 | 
				
			||||||
			"branch": "master",
 | 
								"branch": "master",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user