forked from lug/matterbridge
		
	Compare commits
	
		
			53 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 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 | 
| @@ -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.8.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 stable release [v0.11.0](https://github.com/42wim/matterbridge/releases/latest) | * Latest stable release [v0.14.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" | ||||||
| @@ -21,6 +22,7 @@ type ApiMessage struct { | |||||||
| 	Text     string `json:"text"` | 	Text     string `json:"text"` | ||||||
| 	Username string `json:"username"` | 	Username string `json:"username"` | ||||||
| 	Avatar   string `json:"avatar"` | 	Avatar   string `json:"avatar"` | ||||||
|  | 	Gateway  string `json:"gateway"` | ||||||
| } | } | ||||||
|  |  | ||||||
| var flog *log.Entry | var flog *log.Entry | ||||||
| @@ -38,6 +40,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 +77,15 @@ 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, | ||||||
| 		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 +93,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 | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -16,14 +16,15 @@ const ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| 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 | 	Avatar    string    `json:"avatar"` | ||||||
| 	Account   string | 	Account   string    `json:"account"` | ||||||
| 	Event     string | 	Event     string    `json:"event"` | ||||||
| 	Protocol  string | 	Protocol  string    `json:"protocol"` | ||||||
| 	Timestamp time.Time | 	Gateway   string    `json:"gateway"` | ||||||
|  | 	Timestamp time.Time `json:"timestamp"` | ||||||
| } | } | ||||||
|  |  | ||||||
| type ChannelInfo struct { | type ChannelInfo struct { | ||||||
| @@ -39,6 +40,8 @@ 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 | ||||||
| 	Jid                    string // xmpp | 	Jid                    string // xmpp | ||||||
| @@ -50,23 +53,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,6 +139,8 @@ 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"} | ||||||
| } | } | ||||||
| @@ -143,12 +159,14 @@ 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) | 	b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID) | ||||||
| @@ -195,3 +213,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`) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -46,6 +46,9 @@ 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 | ||||||
|  | 	} | ||||||
| 	return b | 	return b | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -109,9 +112,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>" | ||||||
|   | |||||||
| @@ -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} | ||||||
| 		} | 		} | ||||||
| 		flog.Debugf("Received: %#v", ev) | 		flog.Debugf("Received: %#v", ev) | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
| @@ -143,12 +143,16 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { | |||||||
| 		} | 		} | ||||||
| 		// 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.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 | ||||||
|   | |||||||
| @@ -79,7 +79,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 +89,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 | ||||||
| @@ -199,6 +198,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 { | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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], "/") | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,3 +1,62 @@ | |||||||
|  | # 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 | # v0.11.0 | ||||||
| ## New features | ## New features | ||||||
| * general: reusing the same account on multiple gateways now also reuses the connection. | * general: reusing the same account on multiple gateways now also reuses the connection. | ||||||
| @@ -6,6 +65,7 @@ | |||||||
| * telegram:  Support edited messages (telegram). See #141 | * telegram:  Support edited messages (telegram). See #141 | ||||||
| * mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147 | * mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147 | ||||||
| * mattermost: Reconnect on session removal/timeout (mattermost) | * mattermost: Reconnect on session removal/timeout (mattermost) | ||||||
|  | * mattermost: Support mattermost v3.8.x | ||||||
| * irc:  Rejoin channel when kicked (irc). | * irc:  Rejoin channel when kicked (irc). | ||||||
|  |  | ||||||
| ## Bugfix | ## Bugfix | ||||||
|   | |||||||
| @@ -139,6 +139,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 { | ||||||
| @@ -153,6 +156,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 { | ||||||
| @@ -174,7 +180,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) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -192,9 +198,10 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | |||||||
| 		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) | ||||||
| @@ -233,6 +240,18 @@ 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) | ||||||
| @@ -254,13 +273,21 @@ 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 | ||||||
| @@ -270,8 +297,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" | 	version = "0.14.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,10 +49,15 @@ 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 | ||||||
| @@ -61,6 +67,7 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #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}> " | ||||||
|  |  | ||||||
| @@ -200,9 +207,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) | ||||||
| @@ -241,6 +248,14 @@ 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 | ||||||
| @@ -347,6 +362,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  | ||||||
| @@ -391,6 +414,14 @@ 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 | ||||||
| @@ -427,6 +458,20 @@ 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 | ||||||
| @@ -522,6 +567,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  | ||||||
| @@ -563,6 +613,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 | ||||||
| @@ -570,6 +625,8 @@ Buffer=1000 | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="{NICK}" | RemoteNickFormat="{NICK}" | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ################################################################### | ################################################################### | ||||||
| #General configuration | #General configuration | ||||||
| ################################################################### | ################################################################### | ||||||
| @@ -613,7 +670,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 | ||||||
| @@ -625,7 +682,8 @@ enable=true | |||||||
|     #             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) | ||||||
|     #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" | ||||||
|  |  | ||||||
| @@ -661,7 +719,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" | ||||||
|   | |||||||
| @@ -106,15 +106,26 @@ 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 | ||||||
| 	// bogus call to get the serverversion |  | ||||||
| 	m.Client.GetClientProperties() | 	for { | ||||||
| 	if firstConnection && !supportedVersion(m.Client.ServerVersion) { | 		d := b.Duration() | ||||||
| 		return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion) | 		// 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 | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	m.ServerVersion = m.Client.ServerVersion | 	b.Reset() | ||||||
| 	m.log.Infof("Found version %s", m.ServerVersion) |  | ||||||
|  |  | ||||||
| 	var myinfo *model.Result | 	var myinfo *model.Result | ||||||
| 	var appErr *model.AppError | 	var appErr *model.AppError | ||||||
| @@ -251,7 +262,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: | ||||||
| @@ -277,10 +288,19 @@ 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.Type = data.Type | 	rmsg.Type = data.Type | ||||||
| 	rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string)) | 	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 | ||||||
| @@ -307,7 +327,7 @@ func (m *MMClient) UpdateChannels() error { | |||||||
| 		return errors.New(err.DetailedError) | 		return errors.New(err.DetailedError) | ||||||
| 	} | 	} | ||||||
| 	var mmchannels2 *model.Result | 	var mmchannels2 *model.Result | ||||||
| 	if m.mmVersion() >= 3.8 { | 	if m.mmVersion() >= 3.08 { | ||||||
| 		mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000) | 		mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||||
| 	} else { | 	} else { | ||||||
| 		mmchannels2, err = m.Client.GetMoreChannels("") | 		mmchannels2, err = m.Client.GetMoreChannels("") | ||||||
| @@ -353,6 +373,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() | ||||||
| @@ -446,7 +479,7 @@ 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.8 { | 	if m.mmVersion() >= 3.08 { | ||||||
| 		view := model.ChannelView{ChannelId: channelId} | 		view := model.ChannelView{ChannelId: channelId} | ||||||
| 		res, _ := m.Client.ViewChannel(view) | 		res, _ := m.Client.ViewChannel(view) | ||||||
| 		if res == false { | 		if res == false { | ||||||
| @@ -600,6 +633,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 { | ||||||
| @@ -687,7 +728,7 @@ 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) | ||||||
| 		if m.mmVersion() >= 3.8 { | 		if m.mmVersion() >= 3.08 { | ||||||
| 			mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000) | 			mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||||
| 		} else { | 		} else { | ||||||
| 			mmchannels, err = m.Client.GetMoreChannels("") | 			mmchannels, err = m.Client.GetMoreChannels("") | ||||||
| @@ -721,7 +762,10 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err | |||||||
| } | } | ||||||
|  |  | ||||||
| func (m *MMClient) mmVersion() float64 { | func (m *MMClient) mmVersion() float64 { | ||||||
| 	v, _ := strconv.ParseFloat(m.ServerVersion[0:3], 64) | 	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 | 	return v | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -729,7 +773,9 @@ func supportedVersion(version string) bool { | |||||||
| 	if strings.HasPrefix(version, "3.5.0") || | 	if strings.HasPrefix(version, "3.5.0") || | ||||||
| 		strings.HasPrefix(version, "3.6.0") || | 		strings.HasPrefix(version, "3.6.0") || | ||||||
| 		strings.HasPrefix(version, "3.7.0") || | 		strings.HasPrefix(version, "3.7.0") || | ||||||
| 		strings.HasPrefix(version, "3.8.0") { | 		strings.HasPrefix(version, "3.8.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.9.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.10.0") { | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
| 	return false | 	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?") |  | ||||||
| } |  | ||||||
							
								
								
									
										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) | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								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 | ||||||
| @@ -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