func (s *session) Send(ctx scope.Context, cmdType proto.PacketType, payload interface{}) error { var err error payload, err = proto.DecryptPayload(payload, &s.client.Authorization) if err != nil { return err } encoded, err := json.Marshal(payload) if err != nil { return err } cmd := &proto.Packet{ Type: cmdType, Data: encoded, } // Add to outgoing channel. If channel is full, defer to goroutine so as not to block // the caller (this may result in deliveries coming out of order). select { case s.outgoing <- cmd: default: go func() { s.outgoing <- cmd }() } return nil }
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 (s *session) handleSendCommand(cmd *proto.SendCommand) *response { if s.Identity().Name() == "" { return &response{err: fmt.Errorf("you must choose a name before you may begin chatting")} } if len(cmd.Content) > proto.MaxMessageLength { return &response{err: proto.ErrMessageTooLong} } msgID, err := snowflake.New() if err != nil { return &response{err: err} } var isValidParent bool if s.managedRoom != nil { isValidParent, err = s.managedRoom.IsValidParent(cmd.Parent) } else { isValidParent, err = s.room.IsValidParent(cmd.Parent) } if err != nil { return &response{err: err} } if !isValidParent { return &response{err: proto.ErrInvalidParent} } msg := proto.Message{ ID: msgID, Content: cmd.Content, Parent: cmd.Parent, Sender: s.View(proto.Host), } if s.keyID != "" { key := s.client.Authorization.MessageKeys[s.keyID] if err := proto.EncryptMessage(&msg, s.keyID, key); err != nil { return &response{err: err} } } sent, err := s.room.Send(s.ctx, s, msg) if err != nil { return &response{err: err} } if s.privilegeLevel() == proto.General { sent.Sender.ClientAddress = "" } packet, err := proto.DecryptPayload(proto.SendReply(sent), &s.client.Authorization, s.privilegeLevel()) return &response{ packet: packet, err: err, cost: 10, } }
func (s *session) Send(ctx scope.Context, cmdType proto.PacketType, payload interface{}) error { // Special case: certain events have privileged info that may need to be stripped from them switch event := payload.(type) { case *proto.PresenceEvent: switch s.privilegeLevel() { case proto.Staff: case proto.Host: event.RealClientAddress = "" default: event.RealClientAddress = "" event.ClientAddress = "" } case *proto.Message: if s.privilegeLevel() == proto.General { event.Sender.ClientAddress = "" } case *proto.EditMessageEvent: if s.privilegeLevel() == proto.General { event.Sender.ClientAddress = "" } } var err error payload, err = proto.DecryptPayload(payload, &s.client.Authorization, s.privilegeLevel()) if err != nil { return err } encoded, err := json.Marshal(payload) if err != nil { return err } cmd := &proto.Packet{ Type: cmdType, Data: encoded, } // Add to outgoing channel. If channel is full, defer to goroutine so as not to block // the caller (this may result in deliveries coming out of order). select { case <-ctx.Done(): // Session is closed, return error. return ctx.Err() case s.outgoing <- cmd: // Packet delivered to queue. default: // Queue is full. logging.Logger(s.ctx).Printf("outgoing channel full, ordering cannot be guaranteed") go func() { s.outgoing <- cmd }() } return nil }
func (s *session) handleSendCommand(cmd *proto.SendCommand) *response { if s.Identity().Name() == "" { return &response{err: fmt.Errorf("you must choose a name before you may begin chatting")} } msgID, err := snowflake.New() if err != nil { return &response{err: err} } isValidParent, err := s.room.IsValidParent(cmd.Parent) if err != nil { return &response{err: err} } if !isValidParent { return &response{err: proto.ErrInvalidParent} } msg := proto.Message{ ID: msgID, Content: cmd.Content, Parent: cmd.Parent, Sender: s.View(), } if s.keyID != "" { key := s.client.Authorization.MessageKeys[s.keyID] if err := proto.EncryptMessage(&msg, s.keyID, key); err != nil { return &response{err: err} } } sent, err := s.room.Send(s.ctx, s, msg) if err != nil { return &response{err: err} } packet, err := proto.DecryptPayload(proto.SendReply(sent), &s.client.Authorization) return &response{ packet: packet, err: err, cost: 10, } }
func (s *session) Send(ctx scope.Context, cmdType proto.PacketType, payload interface{}) error { var err error payload, err = proto.DecryptPayload(payload, &s.client.Authorization) if err != nil { return err } encoded, err := json.Marshal(payload) if err != nil { return err } cmd := &proto.Packet{ Type: cmdType, Data: encoded, } go func() { s.outgoing <- cmd }() return nil }