forked from lug/matterbridge
		
	Compare commits
	
		
			26 Commits
		
	
	
		
			v0.11.0-be
			...
			v0.12.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 7a16146304 | ||
|   | 3d3809a21b | ||
|   | 29465397dd | ||
|   | d300bb1735 | ||
|   | 2e703472f1 | ||
|   | 8fede90b9e | ||
|   | d128f157c4 | ||
|   | 4fcedabfd0 | ||
|   | 246c8e4f74 | ||
|   | 4d2207aba7 | ||
|   | 17b8b86d68 | ||
|   | fdb57230a3 | ||
|   | 7469732bbc | ||
|   | d1dd6c3440 | ||
|   | 02612c0061 | ||
|   | a4db63a773 | ||
|   | 035c2b906a | ||
|   | 6ea8be5749 | ||
|   | 36024d5439 | ||
|   | 8d52c98373 | ||
|   | b4a4eb0057 | ||
|   | b469c8ddbd | ||
|   | eee0036c7f | ||
|   | 89c66b9430 | ||
|   | bd38319d83 | ||
|   | 33dffd5ea8 | 
| @@ -28,7 +28,7 @@ Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, R | |||||||
|  |  | ||||||
| # Requirements | # Requirements | ||||||
| Accounts to one of the supported bridges | Accounts to one of the supported bridges | ||||||
| * [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.7.x | * [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.9.x | ||||||
| * [IRC](http://www.mirc.com/servers.html) | * [IRC](http://www.mirc.com/servers.html) | ||||||
| * [XMPP](https://jabber.org) | * [XMPP](https://jabber.org) | ||||||
| * [Gitter](https://gitter.im) | * [Gitter](https://gitter.im) | ||||||
| @@ -42,7 +42,7 @@ Accounts to one of the supported bridges | |||||||
| # Installing | # Installing | ||||||
| ## Binaries | ## Binaries | ||||||
| Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/) | Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/) | ||||||
| * Latest release [v0.10.3](https://github.com/42wim/matterbridge/releases/latest) | * Latest stable release [v0.12.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) | ||||||
|   | |||||||
| @@ -10,8 +10,9 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	EVENT_JOIN_LEAVE = "join_leave" | 	EVENT_JOIN_LEAVE      = "join_leave" | ||||||
| 	EVENT_FAILURE    = "failure" | 	EVENT_FAILURE         = "failure" | ||||||
|  | 	EVENT_REJOIN_CHANNELS = "rejoin_channels" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Message struct { | type Message struct { | ||||||
| @@ -38,6 +39,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 | ||||||
|   | |||||||
| @@ -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,7 @@ 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) | ||||||
| 	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"} | ||||||
| } | } | ||||||
| @@ -195,3 +210,9 @@ func (b *bdiscord) replaceRoleMentions(text string) string { | |||||||
| 	} | 	} | ||||||
| 	return text | 	return text | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (b *bdiscord) stripCustomoji(text string) string { | ||||||
|  | 	// <:doge:302803592035958784> | ||||||
|  | 	re := regexp.MustCompile("<(:.*?:)[0-9]+>") | ||||||
|  | 	return re.ReplaceAllString(text, `$1`) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -109,7 +109,6 @@ 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(b.Local) < b.Config.MessageQueue { | 		if len(b.Local) < b.Config.MessageQueue { | ||||||
| @@ -167,14 +166,19 @@ func (b *Birc) handleNewConnection(event *irc.Event) { | |||||||
| 	i.AddCallback("JOIN", b.handleJoinPart) | 	i.AddCallback("JOIN", b.handleJoinPart) | ||||||
| 	i.AddCallback("PART", b.handleJoinPart) | 	i.AddCallback("PART", b.handleJoinPart) | ||||||
| 	i.AddCallback("QUIT", b.handleJoinPart) | 	i.AddCallback("QUIT", b.handleJoinPart) | ||||||
|  | 	i.AddCallback("KICK", b.handleJoinPart) | ||||||
| 	i.AddCallback("*", b.handleOther) | 	i.AddCallback("*", b.handleOther) | ||||||
| 	// we are now fully connected | 	// we are now fully connected | ||||||
| 	b.connected <- struct{}{} | 	b.connected <- struct{}{} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (b *Birc) handleJoinPart(event *irc.Event) { | func (b *Birc) handleJoinPart(event *irc.Event) { | ||||||
| 	flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) |  | ||||||
| 	channel := event.Arguments[0] | 	channel := event.Arguments[0] | ||||||
|  | 	if event.Code == "KICK" { | ||||||
|  | 		flog.Infof("Got kicked from %s by %s", channel, event.Nick) | ||||||
|  | 		b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	if event.Code == "QUIT" { | 	if event.Code == "QUIT" { | ||||||
| 		if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") { | 		if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") { | ||||||
| 			flog.Infof("%s reconnecting ..", b.Account) | 			flog.Infof("%s reconnecting ..", b.Account) | ||||||
| @@ -182,6 +186,7 @@ func (b *Birc) handleJoinPart(event *irc.Event) { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||||
| 	b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | 	b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||||
| 	flog.Debugf("handle %#v", event) | 	flog.Debugf("handle %#v", event) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -72,6 +72,7 @@ func (b *Bmattermost) Connect() error { | |||||||
| 		flog.Info("Connection succeeded") | 		flog.Info("Connection succeeded") | ||||||
| 		b.TeamId = b.mc.GetTeamId() | 		b.TeamId = b.mc.GetTeamId() | ||||||
| 		go b.mc.WsReceiver() | 		go b.mc.WsReceiver() | ||||||
|  | 		go b.mc.StatusLoop() | ||||||
| 	} | 	} | ||||||
| 	go b.handleMatter() | 	go b.handleMatter() | ||||||
| 	return nil | 	return nil | ||||||
| @@ -100,6 +101,7 @@ func (b *Bmattermost) Send(msg config.Message) error { | |||||||
| 	} | 	} | ||||||
| 	if !b.Config.UseAPI { | 	if !b.Config.UseAPI { | ||||||
| 		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | 		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | ||||||
|  | 		matterMessage.IconURL = msg.Avatar | ||||||
| 		matterMessage.Channel = channel | 		matterMessage.Channel = channel | ||||||
| 		matterMessage.UserName = nick | 		matterMessage.UserName = nick | ||||||
| 		matterMessage.Type = "" | 		matterMessage.Type = "" | ||||||
| @@ -131,14 +133,26 @@ func (b *Bmattermost) handleMatter() { | |||||||
|  |  | ||||||
| func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { | func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { | ||||||
| 	for message := range b.mc.MessageChan { | 	for message := range b.mc.MessageChan { | ||||||
|  | 		flog.Debugf("%#v", message.Raw.Data) | ||||||
|  | 		if message.Type == "system_join_leave" || | ||||||
|  | 			message.Type == "system_join_channel" || | ||||||
|  | 			message.Type == "system_leave_channel" { | ||||||
|  | 			flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||||
|  | 			b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE} | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
| 		// 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 | ||||||
| @@ -199,6 +201,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 { | ||||||
|   | |||||||
| @@ -85,15 +85,17 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | |||||||
| 		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 | 			username = message.From.FirstName | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,8 +1,29 @@ | |||||||
| # v0.11.0-dev | # v0.12.0 | ||||||
|  | ## Changes | ||||||
|  | * general: edited messages are now being sent by default on discord/mattermost/telegram/slack. See "New Features" | ||||||
|  |  | ||||||
| ## New features | ## New features | ||||||
| * general: reusing the same account on multiple gateways now also reuses the connection.  | * 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. | ||||||
|  |  | ||||||
|  | ## Enhancements | ||||||
|  | * discord: Strip custom emoji metadata (discord). Closes #148 | ||||||
|  |  | ||||||
|  | # v0.11.0 | ||||||
|  | ## New features | ||||||
|  | * general: reusing the same account on multiple gateways now also reuses the connection. | ||||||
|   This is particuarly useful for irc. See #87 |   This is particuarly useful for irc. See #87 | ||||||
| * general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration | * general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration | ||||||
|  | * telegram:  Support edited messages (telegram). See #141 | ||||||
|  | * mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147 | ||||||
|  | * mattermost: Reconnect on session removal/timeout (mattermost) | ||||||
|  | * irc:  Rejoin channel when kicked (irc). | ||||||
|  |  | ||||||
|  | ## Bugfix | ||||||
|  | * mattermost: Remove space after nick (mattermost). Closes #142 | ||||||
|  | * mattermost: Modify iconurl correctly (mattermost). | ||||||
|  | * irc: Fix join/leave regression (irc) | ||||||
|  |  | ||||||
| # v0.10.3 | # v0.10.3 | ||||||
| ## Bugfix | ## Bugfix | ||||||
|   | |||||||
| @@ -103,6 +103,15 @@ func (gw *Gateway) handleReceive() { | |||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 			if msg.Event == config.EVENT_REJOIN_CHANNELS { | ||||||
|  | 				for _, br := range gw.Bridges { | ||||||
|  | 					if msg.Account == br.Account { | ||||||
|  | 						br.Joined = make(map[string]bool) | ||||||
|  | 						br.JoinChannels() | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 			if !gw.ignoreMessage(&msg) { | 			if !gw.ignoreMessage(&msg) { | ||||||
| 				msg.Timestamp = time.Now() | 				msg.Timestamp = time.Now() | ||||||
| 				for _, br := range gw.Bridges { | 				for _, br := range gw.Bridges { | ||||||
| @@ -173,6 +182,10 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con | |||||||
| } | } | ||||||
|  |  | ||||||
| func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | ||||||
|  | 	// only relay join/part when configged | ||||||
|  | 	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	// broadcast to every out channel (irc QUIT) | 	// broadcast to every out channel (irc QUIT) | ||||||
| 	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE { | 	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE { | ||||||
| 		log.Debug("empty channel") | 		log.Debug("empty channel") | ||||||
| @@ -186,6 +199,7 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | |||||||
| 		} | 		} | ||||||
| 		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name) | 		log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name) | ||||||
| 		msg.Channel = channel.Name | 		msg.Channel = channel.Name | ||||||
|  | 		gw.modifyAvatar(&msg, dest) | ||||||
| 		gw.modifyUsername(&msg, dest) | 		gw.modifyUsername(&msg, dest) | ||||||
| 		// for api we need originchannel as channel | 		// for api we need originchannel as channel | ||||||
| 		if dest.Protocol == "api" { | 		if dest.Protocol == "api" { | ||||||
| @@ -225,6 +239,17 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) { | |||||||
| 	msg.Username = nick | 	msg.Username = nick | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) { | ||||||
|  | 	iconurl := gw.Config.General.IconURL | ||||||
|  | 	if iconurl == "" { | ||||||
|  | 		iconurl = dest.Config.IconURL | ||||||
|  | 	} | ||||||
|  | 	iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1) | ||||||
|  | 	if msg.Avatar == "" { | ||||||
|  | 		msg.Avatar = iconurl | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func getChannelID(msg config.Message) string { | func getChannelID(msg config.Message) string { | ||||||
| 	return msg.Channel + msg.Account | 	return msg.Channel + msg.Account | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	version = "0.11.0-dev" | 	version = "0.12.0" | ||||||
| 	githash string | 	githash string | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -64,7 +64,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -114,7 +115,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -157,7 +159,8 @@ IgnoreNicks="spammer1 spammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -197,9 +200,9 @@ IconURL="http://youricon.png" | |||||||
| #OPTIONAL | #OPTIONAL | ||||||
| useAPI=false | useAPI=false | ||||||
|  |  | ||||||
| #The mattermost hostname.  | #The mattermost hostname. (do not prefix it with http or https) | ||||||
| #REQUIRED (when useAPI=true) | #REQUIRED (when useAPI=true) | ||||||
| Server="yourmattermostserver.domain" | Server="yourmattermostserver.domain"  | ||||||
|  |  | ||||||
| #Your team on mattermost.  | #Your team on mattermost.  | ||||||
| #REQUIRED (when useAPI=true) | #REQUIRED (when useAPI=true) | ||||||
| @@ -238,6 +241,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 | ||||||
| @@ -250,7 +261,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -282,7 +294,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -342,6 +355,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  | ||||||
| @@ -362,7 +383,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -385,6 +407,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 | ||||||
| @@ -397,7 +427,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -420,6 +451,14 @@ Token="Yourtokenhere" | |||||||
| #See https://core.telegram.org/bots/api#html-style | #See https://core.telegram.org/bots/api#html-style | ||||||
| MessageFormat="" | MessageFormat="" | ||||||
|  |  | ||||||
|  | #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 | ||||||
| @@ -432,7 +471,8 @@ IgnoreNicks="spammer1 spammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -489,7 +529,8 @@ IgnoreNicks="ircspammer1 ircspammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
| @@ -532,7 +573,8 @@ IgnoreNicks="spammer1 spammer2" | |||||||
| #OPTIONAL (default empty) | #OPTIONAL (default empty) | ||||||
| RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | RemoteNickFormat="[{PROTOCOL}] <{NICK}> " | ||||||
|  |  | ||||||
| #Enable to show users joins/parts from other bridges (only from irc-bridge at the moment) | #Enable to show users joins/parts from other bridges  | ||||||
|  | #Only works hiding/show messages from irc and mattermost bridge for now | ||||||
| #OPTIONAL (default false) | #OPTIONAL (default false) | ||||||
| ShowJoinPart=false | ShowJoinPart=false | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,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" | ||||||
|   | |||||||
| @@ -4,9 +4,11 @@ import ( | |||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/cookiejar" | 	"net/http/cookiejar" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| @@ -34,6 +36,7 @@ type Message struct { | |||||||
| 	Channel  string | 	Channel  string | ||||||
| 	Username string | 	Username string | ||||||
| 	Text     string | 	Text     string | ||||||
|  | 	Type     string | ||||||
| } | } | ||||||
|  |  | ||||||
| type Team struct { | type Team struct { | ||||||
| @@ -47,19 +50,20 @@ type Team struct { | |||||||
| type MMClient struct { | type MMClient struct { | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| 	*Credentials | 	*Credentials | ||||||
| 	Team        *Team | 	Team          *Team | ||||||
| 	OtherTeams  []*Team | 	OtherTeams    []*Team | ||||||
| 	Client      *model.Client | 	Client        *model.Client | ||||||
| 	User        *model.User | 	User          *model.User | ||||||
| 	Users       map[string]*model.User | 	Users         map[string]*model.User | ||||||
| 	MessageChan chan *Message | 	MessageChan   chan *Message | ||||||
| 	log         *log.Entry | 	log           *log.Entry | ||||||
| 	WsClient    *websocket.Conn | 	WsClient      *websocket.Conn | ||||||
| 	WsQuit      bool | 	WsQuit        bool | ||||||
| 	WsAway      bool | 	WsAway        bool | ||||||
| 	WsConnected bool | 	WsConnected   bool | ||||||
| 	WsSequence  int64 | 	WsSequence    int64 | ||||||
| 	WsPingChan  chan *model.WebSocketResponse | 	WsPingChan    chan *model.WebSocketResponse | ||||||
|  | 	ServerVersion string | ||||||
| } | } | ||||||
|  |  | ||||||
| func New(login, pass, team, server string) *MMClient { | func New(login, pass, team, server string) *MMClient { | ||||||
| @@ -102,8 +106,27 @@ func (m *MMClient) Login() error { | |||||||
| 	} | 	} | ||||||
| 	// login to mattermost | 	// login to mattermost | ||||||
| 	m.Client = model.NewClient(uriScheme + m.Credentials.Server) | 	m.Client = model.NewClient(uriScheme + m.Credentials.Server) | ||||||
| 	m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}} | 	m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, Proxy: http.ProxyFromEnvironment} | ||||||
| 	m.Client.HttpClient.Timeout = time.Second * 10 | 	m.Client.HttpClient.Timeout = time.Second * 10 | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		d := b.Duration() | ||||||
|  | 		// bogus call to get the serverversion | ||||||
|  | 		m.Client.GetClientProperties() | ||||||
|  | 		if firstConnection && !supportedVersion(m.Client.ServerVersion) { | ||||||
|  | 			return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion) | ||||||
|  | 		} | ||||||
|  | 		m.ServerVersion = m.Client.ServerVersion | ||||||
|  | 		if m.ServerVersion == "" { | ||||||
|  | 			m.log.Debugf("Server not up yet, reconnecting in %s", d) | ||||||
|  | 			time.Sleep(d) | ||||||
|  | 		} else { | ||||||
|  | 			m.log.Infof("Found version %s", m.ServerVersion) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	b.Reset() | ||||||
|  |  | ||||||
| 	var myinfo *model.Result | 	var myinfo *model.Result | ||||||
| 	var appErr *model.AppError | 	var appErr *model.AppError | ||||||
| 	var logmsg = "trying login" | 	var logmsg = "trying login" | ||||||
| @@ -177,6 +200,7 @@ func (m *MMClient) Login() error { | |||||||
| 	} | 	} | ||||||
| 	b.Reset() | 	b.Reset() | ||||||
|  |  | ||||||
|  | 	m.log.Debug("WsClient: connected") | ||||||
| 	m.WsSequence = 1 | 	m.WsSequence = 1 | ||||||
| 	m.WsPingChan = make(chan *model.WebSocketResponse) | 	m.WsPingChan = make(chan *model.WebSocketResponse) | ||||||
| 	// only start to parse WS messages when login is completely done | 	// only start to parse WS messages when login is completely done | ||||||
| @@ -238,7 +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: | ||||||
| @@ -266,7 +290,18 @@ func (m *MMClient) parseActionPost(rmsg *Message) { | |||||||
| 	} | 	} | ||||||
| 	rmsg.Username = m.GetUser(data.UserId).Username | 	rmsg.Username = m.GetUser(data.UserId).Username | ||||||
| 	rmsg.Channel = m.GetChannelName(data.ChannelId) | 	rmsg.Channel = m.GetChannelName(data.ChannelId) | ||||||
| 	rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string)) | 	rmsg.Type = data.Type | ||||||
|  | 	teamid, _ := rmsg.Raw.Data["team_id"].(string) | ||||||
|  | 	// edit messsages have no team_id for some reason | ||||||
|  | 	if teamid == "" { | ||||||
|  | 		// we can find the team_id from the channelid | ||||||
|  | 		result, _ := m.Client.GetChannel(data.ChannelId, "") | ||||||
|  | 		teamid = result.Data.(*model.ChannelData).Channel.TeamId | ||||||
|  | 		rmsg.Raw.Data["team_id"] = teamid | ||||||
|  | 	} | ||||||
|  | 	if teamid != "" { | ||||||
|  | 		rmsg.Team = m.GetTeamName(teamid) | ||||||
|  | 	} | ||||||
| 	// direct message | 	// direct message | ||||||
| 	if rmsg.Raw.Data["channel_type"] == "D" { | 	if rmsg.Raw.Data["channel_type"] == "D" { | ||||||
| 		rmsg.Channel = m.GetUser(data.UserId).Username | 		rmsg.Channel = m.GetUser(data.UserId).Username | ||||||
| @@ -292,7 +327,12 @@ func (m *MMClient) UpdateChannels() error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return errors.New(err.DetailedError) | 		return errors.New(err.DetailedError) | ||||||
| 	} | 	} | ||||||
| 	mmchannels2, err := m.Client.GetMoreChannels("") | 	var mmchannels2 *model.Result | ||||||
|  | 	if m.mmVersion() >= 3.8 { | ||||||
|  | 		mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||||
|  | 	} else { | ||||||
|  | 		mmchannels2, err = m.Client.GetMoreChannels("") | ||||||
|  | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return errors.New(err.DetailedError) | 		return errors.New(err.DetailedError) | ||||||
| 	} | 	} | ||||||
| @@ -427,6 +467,14 @@ func (m *MMClient) UpdateChannelHeader(channelId string, header string) { | |||||||
|  |  | ||||||
| func (m *MMClient) UpdateLastViewed(channelId string) { | func (m *MMClient) UpdateLastViewed(channelId string) { | ||||||
| 	m.log.Debugf("posting lastview %#v", channelId) | 	m.log.Debugf("posting lastview %#v", channelId) | ||||||
|  | 	if m.mmVersion() >= 3.8 { | ||||||
|  | 		view := model.ChannelView{ChannelId: channelId} | ||||||
|  | 		res, _ := m.Client.ViewChannel(view) | ||||||
|  | 		if res == false { | ||||||
|  | 			m.log.Errorf("ChannelView update for %s failed", channelId) | ||||||
|  | 		} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
| 	_, err := m.Client.UpdateLastViewedAt(channelId, true) | 	_, err := m.Client.UpdateLastViewedAt(channelId, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		m.log.Error(err) | 		m.log.Error(err) | ||||||
| @@ -628,6 +676,7 @@ func (m *MMClient) StatusLoop() { | |||||||
| 				m.Logout() | 				m.Logout() | ||||||
| 				m.WsQuit = false | 				m.WsQuit = false | ||||||
| 				m.Login() | 				m.Login() | ||||||
|  | 				go m.WsReceiver() | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		time.Sleep(time.Second * 60) | 		time.Sleep(time.Second * 60) | ||||||
| @@ -659,7 +708,11 @@ func (m *MMClient) initUser() error { | |||||||
| 			return errors.New(err.DetailedError) | 			return errors.New(err.DetailedError) | ||||||
| 		} | 		} | ||||||
| 		t.Channels = mmchannels.Data.(*model.ChannelList) | 		t.Channels = mmchannels.Data.(*model.ChannelList) | ||||||
| 		mmchannels, err = m.Client.GetMoreChannels("") | 		if m.mmVersion() >= 3.8 { | ||||||
|  | 			mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||||
|  | 		} else { | ||||||
|  | 			mmchannels, err = m.Client.GetMoreChannels("") | ||||||
|  | 		} | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return errors.New(err.DetailedError) | 			return errors.New(err.DetailedError) | ||||||
| 		} | 		} | ||||||
| @@ -687,3 +740,19 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err | |||||||
| 	m.WsClient.WriteJSON(req) | 	m.WsClient.WriteJSON(req) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (m *MMClient) mmVersion() float64 { | ||||||
|  | 	v, _ := strconv.ParseFloat(m.ServerVersion[0:3], 64) | ||||||
|  | 	return v | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func supportedVersion(version string) bool { | ||||||
|  | 	if strings.HasPrefix(version, "3.5.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.6.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.7.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.8.0") || | ||||||
|  | 		strings.HasPrefix(version, "3.9.0") { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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?") |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user