// 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 }
// 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, }) }
// 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 }
// 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 }
// 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 }
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() } }
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)} } }
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 }
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")} } }
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 }
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 }
// 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, }) }
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 }