| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- package server
- import (
- "context"
- "errors"
- "github.com/google/uuid"
- "github.com/mkaminski/goaim/oscar"
- "io"
- "log/slog"
- "time"
- )
- type ChatNavHandler interface {
- CreateRoomHandler(ctx context.Context, sess *Session, cr *ChatRegistry, newChatRoom ChatRoomFactory, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (XMessage, error)
- RequestChatRightsHandler(ctx context.Context) XMessage
- RequestRoomInfoHandler(ctx context.Context, cr *ChatRegistry, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (XMessage, error)
- }
- func NewChatNavRouter(logger *slog.Logger) ChatNavRouter {
- return ChatNavRouter{
- ChatNavHandler: ChatNavService{
- Logger: logger,
- },
- RouteLogger: RouteLogger{
- Logger: logger,
- },
- }
- }
- type ChatNavRouter struct {
- ChatNavHandler
- RouteLogger
- }
- func (rt *ChatNavRouter) RouteChatNav(ctx context.Context, sess *Session, cr *ChatRegistry, SNACFrame oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- switch SNACFrame.SubGroup {
- case oscar.ChatNavRequestChatRights:
- outSNAC := rt.RequestChatRightsHandler(ctx)
- rt.logRequestAndResponse(ctx, SNACFrame, nil, outSNAC.snacFrame, outSNAC.snacOut)
- return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
- case oscar.ChatNavRequestRoomInfo:
- inSNAC := oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{}
- if err := oscar.Unmarshal(&inSNAC, r); err != nil {
- return err
- }
- outSNAC, err := rt.RequestRoomInfoHandler(ctx, cr, inSNAC)
- if err != nil {
- return err
- }
- rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.snacFrame, outSNAC.snacOut)
- return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
- case oscar.ChatNavCreateRoom:
- inSNAC := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{}
- if err := oscar.Unmarshal(&inSNAC, r); err != nil {
- return err
- }
- outSNAC, err := rt.CreateRoomHandler(ctx, sess, cr, NewChatRoom, inSNAC)
- if err != nil {
- return err
- }
- roomName, _ := inSNAC.GetString(oscar.ChatTLVRoomName)
- rt.Logger.InfoContext(ctx, "user started a chat room", slog.String("roomName", roomName))
- rt.logRequestAndResponse(ctx, SNACFrame, inSNAC, outSNAC.snacFrame, outSNAC.snacOut)
- return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
- default:
- return ErrUnsupportedSubGroup
- }
- }
- type ChatNavService struct {
- Logger *slog.Logger
- }
- type ChatCookie struct {
- Cookie []byte `len_prefix:"uint16"`
- SessID string `len_prefix:"uint16"`
- }
- func (s ChatNavService) RequestChatRightsHandler(context.Context) XMessage {
- return XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.CHAT_NAV,
- SubGroup: oscar.ChatNavNavInfo,
- },
- snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- oscar.NewTLV(0x02, uint8(10)),
- oscar.NewTLV(0x03, oscar.SNAC_0x0D_0x09_TLVExchangeInfo{
- Identifier: 4,
- TLVBlock: oscar.TLVBlock{
- TLVList: oscar.TLVList{
- oscar.NewTLV(0x0002, uint16(0x0010)),
- oscar.NewTLV(0x00c9, uint16(15)),
- oscar.NewTLV(0x00d3, "default Exchange"),
- oscar.NewTLV(0x00d5, uint8(2)),
- oscar.NewTLV(0xd6, "us-ascii"),
- oscar.NewTLV(0xd7, "en"),
- oscar.NewTLV(0xd8, "us-ascii"),
- oscar.NewTLV(0xd9, "en"),
- },
- },
- }),
- },
- },
- },
- }
- }
- func NewChatRoom(logger *slog.Logger) ChatRoom {
- return ChatRoom{
- Cookie: uuid.New().String(),
- CreateTime: time.Now(),
- SessionManager: NewSessionManager(logger),
- }
- }
- type ChatRoomFactory func(logger *slog.Logger) ChatRoom
- func (s ChatNavService) CreateRoomHandler(_ context.Context, sess *Session, cr *ChatRegistry, newChatRoom ChatRoomFactory, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (XMessage, error) {
- name, hasName := snacPayloadIn.GetString(oscar.ChatTLVRoomName)
- if !hasName {
- return XMessage{}, errors.New("unable to find chat name")
- }
- room := newChatRoom(s.Logger)
- room.DetailLevel = snacPayloadIn.DetailLevel
- room.Exchange = snacPayloadIn.Exchange
- room.InstanceNumber = snacPayloadIn.InstanceNumber
- room.Name = name
- cr.Register(room)
- // add user to chat room
- room.NewSessionWithSN(sess.ID, sess.ScreenName)
- return XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.CHAT_NAV,
- SubGroup: oscar.ChatNavNavInfo,
- },
- snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- oscar.NewTLV(oscar.ChatNavTLVRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
- Exchange: snacPayloadIn.Exchange,
- Cookie: room.Cookie,
- InstanceNumber: snacPayloadIn.InstanceNumber,
- DetailLevel: snacPayloadIn.DetailLevel,
- TLVBlock: oscar.TLVBlock{
- TLVList: room.TLVList(),
- },
- }),
- },
- },
- },
- }, nil
- }
- func (s ChatNavService) RequestRoomInfoHandler(_ context.Context, cr *ChatRegistry, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (XMessage, error) {
- room, err := cr.Retrieve(string(snacPayloadIn.Cookie))
- if err != nil {
- return XMessage{}, err
- }
- return XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.CHAT_NAV,
- SubGroup: oscar.ChatNavNavInfo,
- },
- snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- oscar.NewTLV(0x04, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
- Exchange: 4,
- Cookie: room.Cookie,
- InstanceNumber: 100,
- DetailLevel: 2,
- TLVBlock: oscar.TLVBlock{
- TLVList: room.TLVList(),
- },
- }),
- },
- },
- },
- }, nil
- }
|