Example #1
0
// HandleIncoming checks incoming SendEvents for URLs and posts the link title
// for the first URL returning a valid title.
func (l *LinkTitleHandler) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
	if p.Type != proto.SendEventType {
		return nil, nil
	}
	r.Logger.Debugf("Handler received SendEvent")
	payload, err := p.Payload()
	if err != nil {
		return nil, err
	}
	msg, ok := payload.(*proto.SendEvent)
	if !ok {
		return nil, fmt.Errorf("Could not assert SendEvent as such.")
	}
	if msg.Sender.Name == "euphoriabot" {
		return nil, nil
	}
	r.Logger.Debugf("Received message with content: %s", msg.Content)
	urls := linkMatcher.FindAllString(msg.Content, -1)
	for _, url := range urls {
		r.Logger.Debugf("Trying URL %s", url)
		if !strings.HasPrefix(url, "http") {
			url = "http://" + url
		}
		title, err := getLinkTitle(url)
		if err == nil && title != "" {
			r.SendText(&msg.ID, "Link title: "+title)
			break
		}
	}
	return nil, nil
}
Example #2
0
// HandleIncoming responds to messages that equal "!ping" or "!ping @MaiMai"
// with a "pong!" message over the Connection.
func (h *PongHandler) HandleIncoming(conn mproto.Connection, p *proto.Packet) error {
	if p.Type != proto.SendEventType {
		return nil
	}
	payload, err := p.Payload()
	if err != nil {
		return err
	}
	sendEvent, ok := payload.(*proto.SendEvent)
	if !ok {
		return fmt.Errorf("Error asserting send-event as such.")
	}
	if sendEvent.Content != "!ping" && sendEvent.Content != "!ping @MaiMai" {
		return nil
	}
	reply := &proto.SendCommand{
		Content: "pong!",
		Parent:  sendEvent.ID,
	}
	marshal, err := json.Marshal(reply)
	if err != nil {
		return err
	}
	return conn.Send(&proto.Packet{
		Type: proto.SendType,
		Data: marshal,
	})
}
Example #3
0
// HandleIncoming checks incoming commands for !uptime or !uptime @[BotName] and
// responds with the duration the bot has been up.
func (u *UptimeHandler) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
	if p.Type != proto.SendEventType {
		return nil, nil
	}
	raw, err := p.Payload()
	if err != nil {
		return nil, err
	}
	payload, ok := raw.(*proto.SendEvent)
	if !ok {
		r.Logger.Warningln("Unable to assert packet as SendEvent.")
		return nil, err
	}
	if !strings.HasPrefix(payload.Content, "!uptime") {
		return nil, nil
	}
	if payload.Content != "!uptime" && payload.Content != "!uptime @"+r.BotName {
		return nil, nil
	}
	uptime := time.Since(u.t0)
	days := int(uptime.Hours()) / 24
	hours := int(uptime.Hours()) % 24
	minutes := int(uptime.Minutes()) % 60
	seconds := int(uptime.Seconds()) % 60
	if _, err := r.SendText(&payload.ID, fmt.Sprintf(
		"This bot has been up for %dd %dh %dm %.3fs.",
		days, hours, minutes, seconds)); err != nil {
		return nil, err
	}
	return nil, nil
}
Example #4
0
// HandleIncoming checks incoming SendEvents for help commands and responds
// appropriately.
func (h *HelpHandler) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
	if p.Type != proto.SendEventType {
		return nil, nil
	}
	raw, err := p.Payload()
	if err != nil {
		return nil, err
	}
	payload, ok := raw.(*proto.SendEvent)
	if !ok {
		r.Logger.Warningln("Unable to assert packet as SendEvent.")
		return nil, err
	}
	if !strings.HasPrefix(payload.Content, "!help") {
		return nil, nil
	}
	if payload.Content != "!help @"+r.BotName && payload.Content != "!help" {
		return nil, nil
	}
	if payload.Content == "!help" {
		if _, err := r.SendText(&payload.ID, h.ShortDesc); err != nil {
			return nil, err
		}
		return nil, nil
	}
	if _, err := r.SendText(&payload.ID, h.LongDesc); err != nil {
		return nil, err
	}
	return nil, nil
}
Example #5
0
// HandleIncoming satisfies the Handler interface.
func (ph *PongHandler) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
	r.Logger.Debugln("Checking for ping command...")
	if p.Type != proto.SendEventType {
		return nil, nil
	}
	raw, err := p.Payload()
	if err != nil {
		return nil, err
	}
	payload, ok := raw.(*proto.SendEvent)
	if !ok {
		r.Logger.Warningln("Unable to assert packet as SendEvent.")
		return nil, err
	}
	if !strings.HasPrefix(payload.Content, "!ping") {
		return nil, nil
	}
	if strings.Contains(payload.Content, "@") && !strings.HasPrefix(payload.Content, "!ping @"+r.BotName) {
		return nil, nil
	}
	r.Logger.Debugln("Sending !ping reply...")
	if _, err := r.SendText(&payload.ID, "pong!"); err != nil {
		return nil, err
	}
	return nil, nil
}
Example #6
0
func (r *Room) handleBadPacket(p *proto.Packet) {
	if p == nil {
		return
	}
	payload, err := p.Payload()
	if err != nil {
		r.Logger.Errorf("Could not extract payload: %s", payload)
		r.Ctx.Cancel()
		return
	}
	if p.Error != "" {
		r.Logger.Errorf("Error in received packet of type %s: %s", p.Type, p.Error)
		r.Ctx.Cancel()
	}
	switch msg := payload.(type) {
	case proto.ErrorReply:
		r.Logger.Errorf("Error packet received: %s", msg.Error)
		r.Ctx.Cancel()
	case proto.BounceEvent:
		r.Logger.Errorf("Bounced: %s", msg.Reason)
	case proto.DisconnectEvent:
		r.Logger.Errorf("disconnect-event received: reason: %s", msg.Reason)
		r.Ctx.Cancel()
	}
}
Example #7
0
func (s *session) joinedState(cmd *proto.Packet) *response {
	payload, err := cmd.Payload()
	if err != nil {
		return &response{err: fmt.Errorf("payload: %s", err)}
	}

	switch msg := payload.(type) {
	case *proto.AuthCommand:
		return &response{err: fmt.Errorf("already joined")}
	case *proto.SendCommand:
		return s.handleSendCommand(msg)
	case *proto.GetMessageCommand:
		ret, err := s.room.GetMessage(s.ctx, msg.ID)
		if err != nil {
			return &response{err: err}
		}
		return &response{
			packet: proto.GetMessageReply(*ret),
		}
	case *proto.LogCommand:
		msgs, err := s.room.Latest(s.ctx, msg.N, msg.Before)
		if err != nil {
			return &response{err: err}
		}
		packet, err := proto.DecryptPayload(
			proto.LogReply{Log: msgs, Before: msg.Before}, &s.client.Authorization)
		return &response{
			packet: packet,
			err:    err,
			cost:   1,
		}
	case *proto.NickCommand:
		nick, err := proto.NormalizeNick(msg.Name)
		if err != nil {
			return &response{err: err}
		}
		formerName := s.identity.Name()
		s.identity.name = nick
		event, err := s.room.RenameUser(s.ctx, s, formerName)
		if err != nil {
			return &response{err: err}
		}
		return &response{
			packet: proto.NickReply(*event),
			cost:   1,
		}
	case *proto.WhoCommand:
		listing, err := s.room.Listing(s.ctx)
		if err != nil {
			return &response{err: err}
		}
		return &response{packet: &proto.WhoReply{Listing: listing}}
	default:
		if resp := s.handleCoreCommands(payload); resp != nil {
			return resp
		}
		return &response{err: fmt.Errorf("command type %T not implemented", payload)}
	}
}
Example #8
0
func (r *Room) handlePing(p *proto.Packet) error {
	r.Logger.Debugln("Handling ping...")
	raw, err := p.Payload()
	if err != nil {
		return err
	}
	payload, ok := raw.(*proto.PingEvent)
	if !ok {
		return fmt.Errorf("Could not assert payload as *packet.PingEvent")
	}
	r.queuePayload(proto.PingReply{UnixTime: payload.UnixTime}, proto.PingReplyType)
	return nil
}
Example #9
0
func (s *session) unauthedState(cmd *proto.Packet) *response {
	payload, err := cmd.Payload()
	if err != nil {
		return &response{err: fmt.Errorf("payload: %s", err)}
	}

	switch msg := payload.(type) {
	case *proto.AuthCommand:
		return s.handleAuthCommand(msg)
	default:
		if resp := s.handleCoreCommands(payload); resp != nil {
			return resp
		}
		return &response{err: fmt.Errorf("access denied, please authenticate")}
	}
}
Example #10
0
func (c *CIListener) HandleIncoming(r *gobot.Room, p *proto.Packet) (*proto.Packet, error) {
	payload, err := p.Payload()
	if err != nil {
		return nil, err
	}
	switch msg := payload.(type) {
	case proto.SendReply:
		commit, ok := c.packetIDtoCommit[p.ID]
		if !ok {
			return nil, nil
		}
		c.commitToMsgID[commit] = msg.ID.String()
	default:
		return nil, nil
	}
	return nil, nil
}
Example #11
0
func (lm ListenerMap) NotifyUser(ctx scope.Context, userID proto.UserID, event *proto.Packet, exclude ...string) error {
	excludeSet := map[string]struct{}{}
	for _, exc := range exclude {
		excludeSet[exc] = struct{}{}
	}
	payload, err := event.Payload()
	if err != nil {
		return err
	}
	kind, id := userID.Parse()
	for sessionID, listener := range lm {
		// check that the listener is not excluded
		if _, ok := excludeSet[sessionID]; ok {
			continue
		}

		if listener.Identity().ID() == userID || (kind == "agent" && id == listener.AgentID()) {
			listener.Send(ctx, event.Type, payload)
		}
	}
	return nil
}
Example #12
0
// HandleIncoming responds to the given ping-event over the given Connection.
func (h *PingHandler) HandleIncoming(conn mproto.Connection, p *proto.Packet) error {
	if p.Type != proto.PingEventType {
		return nil
	}
	payload, err := p.Payload()
	if err != nil {
		return err
	}
	pingEvent, ok := payload.(*proto.PingEvent)
	if !ok {
		return fmt.Errorf("Error asserting ping-event as such")
	}
	pingReply := &proto.PingReply{
		UnixTime: pingEvent.UnixTime,
	}
	marshalled, err := json.Marshal(pingReply)
	if err != nil {
		return err
	}
	return conn.Send(&proto.Packet{
		Type: proto.PingReplyType,
		Data: marshalled,
	})
}
Example #13
0
func (lm ListenerMap) Broadcast(ctx scope.Context, event *proto.Packet, exclude ...string) error {
	payload, err := event.Payload()
	if err != nil {
		return err
	}

	excludeSet := map[string]struct{}{}
	for _, exc := range exclude {
		excludeSet[exc] = struct{}{}
	}

	// Inspect packet to see if it's a bounce event. If so, we'll deliver it
	// only to the bounced parties.
	bounceAgentID := ""
	bounceIP := ""
	if event.Type == proto.BounceEventType {
		if bounceEvent, ok := payload.(*proto.BounceEvent); ok {
			bounceAgentID = bounceEvent.AgentID
			bounceIP = bounceEvent.IP
		} else {
			logging.Logger(ctx).Printf("wtf? expected *proto.BounceEvent, got %T", payload)
		}
	}

	// Inspect packet to see if it's a join event. If so, we'll enable the excluded
	// listener, and look for aliased sessions to kick into fast-keepalive mode.
	fastKeepaliveAgentID := ""
	if event.Type == proto.JoinEventType {
		if presence, ok := payload.(*proto.PresenceEvent); ok {
			if idx := strings.IndexRune(string(presence.ID), '-'); idx >= 1 {
				fastKeepaliveAgentID = string(presence.ID[:idx])
			}
		}
		for _, sessionID := range exclude {
			listener, ok := lm[sessionID]
			if ok && !listener.enabled {
				listener.enabled = true
				lm[sessionID] = listener
			}
		}
	}

	for sessionID, listener := range lm {
		if _, ok := excludeSet[sessionID]; !ok {
			if bounceAgentID != "" {
				if listener.Session.Identity().ID().String() == bounceAgentID {
					logging.Logger(ctx).Printf("sending disconnect to %s: %#v", listener.ID(), payload)
					discEvent := &proto.DisconnectEvent{Reason: payload.(*proto.BounceEvent).Reason}
					if err := listener.Send(ctx, proto.DisconnectEventType, discEvent); err != nil {
						logging.Logger(ctx).Printf("error sending disconnect event to %s: %s",
							listener.ID(), err)
					}
				}
				continue
			}
			if bounceIP != "" {
				if listener.Client.IP == bounceIP {
					logging.Logger(ctx).Printf("sending disconnect to %s: %#v", listener.ID(), payload)
					discEvent := &proto.DisconnectEvent{Reason: payload.(*proto.BounceEvent).Reason}
					if err := listener.Send(ctx, proto.DisconnectEventType, discEvent); err != nil {
						logging.Logger(ctx).Printf("error sending disconnect event to %s: %s",
							listener.ID(), err)
					}
				}
				continue
			}
			if fastKeepaliveAgentID != "" && strings.HasPrefix(sessionID, fastKeepaliveAgentID) {
				if err := listener.CheckAbandoned(); err != nil {
					fmt.Errorf("fast keepalive to %s: %s", listener.ID(), err)
				}
			}
			if !listener.enabled {
				// The event occurred before the listener joined, so don't deliver it.
				logging.Logger(ctx).Printf("not delivering event %s before %s joined",
					event.Type, listener.ID())
				continue
			}
			if err := listener.Send(ctx, event.Type, payload); err != nil {
				// TODO: accumulate errors
				return fmt.Errorf("send message to %s: %s", listener.ID(), err)
			}
		}
	}

	return nil
}