chat_nav.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package handler
  2. import (
  3. "context"
  4. "errors"
  5. "log/slog"
  6. "github.com/mk6i/retro-aim-server/oscar"
  7. "github.com/mk6i/retro-aim-server/state"
  8. )
  9. // NewChatNavService creates a new instance of NewChatNavService.
  10. func NewChatNavService(logger *slog.Logger, chatRegistry *state.ChatRegistry, newChatRoom func() state.ChatRoom, newChatSessMgr func() SessionManager) *ChatNavService {
  11. return &ChatNavService{
  12. logger: logger,
  13. chatRegistry: chatRegistry,
  14. newChatRoom: newChatRoom,
  15. newChatSessMgr: newChatSessMgr,
  16. }
  17. }
  18. // ChatNavService provides handlers for the ChatNav food group.
  19. type ChatNavService struct {
  20. logger *slog.Logger
  21. chatRegistry *state.ChatRegistry
  22. newChatRoom func() state.ChatRoom
  23. newChatSessMgr func() SessionManager
  24. }
  25. // RequestChatRightsHandler returns SNAC oscar.ChatNavNavInfo, which contains
  26. // chat navigation service parameters and limits.
  27. func (s ChatNavService) RequestChatRightsHandler(_ context.Context, inFrame oscar.SNACFrame) oscar.SNACMessage {
  28. return oscar.SNACMessage{
  29. Frame: oscar.SNACFrame{
  30. FoodGroup: oscar.ChatNav,
  31. SubGroup: oscar.ChatNavNavInfo,
  32. RequestID: inFrame.RequestID,
  33. },
  34. Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  35. TLVRestBlock: oscar.TLVRestBlock{
  36. TLVList: oscar.TLVList{
  37. oscar.NewTLV(oscar.ChatNavTLVMaxConcurrentRooms, uint8(10)),
  38. oscar.NewTLV(oscar.ChatNavTLVExchangeInfo, oscar.SNAC_0x0D_0x09_TLVExchangeInfo{
  39. Identifier: 4,
  40. TLVBlock: oscar.TLVBlock{
  41. TLVList: oscar.TLVList{
  42. oscar.NewTLV(oscar.ChatNavTLVClassPerms, uint16(0x0010)),
  43. oscar.NewTLV(oscar.ChatNavTLVFlags, uint16(15)),
  44. oscar.NewTLV(oscar.ChatNavTLVRoomName, "default exchange"),
  45. oscar.NewTLV(oscar.ChatNavTLVCreatePerms, uint8(2)),
  46. oscar.NewTLV(oscar.ChatNavTLVCharSet1, "us-ascii"),
  47. oscar.NewTLV(oscar.ChatNavTLVLang1, "en"),
  48. oscar.NewTLV(oscar.ChatNavTLVCharSet2, "us-ascii"),
  49. oscar.NewTLV(oscar.ChatNavTLVLang2, "en"),
  50. },
  51. },
  52. }),
  53. },
  54. },
  55. },
  56. }
  57. }
  58. // CreateRoomHandler creates a chat room with the current user as the first
  59. // participant. It returns SNAC oscar.ChatNavNavInfo, which contains metadata
  60. // for the chat room.
  61. func (s ChatNavService) CreateRoomHandler(_ context.Context, sess *state.Session, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (oscar.SNACMessage, error) {
  62. name, hasName := inBody.String(oscar.ChatTLVRoomName)
  63. if !hasName {
  64. return oscar.SNACMessage{}, errors.New("unable to find chat name")
  65. }
  66. room := s.newChatRoom()
  67. room.DetailLevel = inBody.DetailLevel
  68. room.Exchange = inBody.Exchange
  69. room.InstanceNumber = inBody.InstanceNumber
  70. room.Name = name
  71. chatSessMgr := s.newChatSessMgr()
  72. s.chatRegistry.Register(room, chatSessMgr)
  73. // add user to chat room
  74. chatSessMgr.AddSession(sess.ID(), sess.ScreenName())
  75. return oscar.SNACMessage{
  76. Frame: oscar.SNACFrame{
  77. FoodGroup: oscar.ChatNav,
  78. SubGroup: oscar.ChatNavNavInfo,
  79. RequestID: inFrame.RequestID,
  80. },
  81. Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  82. TLVRestBlock: oscar.TLVRestBlock{
  83. TLVList: oscar.TLVList{
  84. oscar.NewTLV(oscar.ChatNavRequestRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  85. Exchange: inBody.Exchange,
  86. Cookie: room.Cookie,
  87. InstanceNumber: inBody.InstanceNumber,
  88. DetailLevel: inBody.DetailLevel,
  89. TLVBlock: oscar.TLVBlock{
  90. TLVList: room.TLVList(),
  91. },
  92. }),
  93. },
  94. },
  95. },
  96. }, nil
  97. }
  98. // RequestRoomInfoHandler returns oscar.ChatNavNavInfo, which contains metadata
  99. // for the chat room specified in the inFrame.Cookie.
  100. func (s ChatNavService) RequestRoomInfoHandler(_ context.Context, inFrame oscar.SNACFrame, inBody oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (oscar.SNACMessage, error) {
  101. room, _, err := s.chatRegistry.Retrieve(string(inBody.Cookie))
  102. if err != nil {
  103. return oscar.SNACMessage{}, err
  104. }
  105. return oscar.SNACMessage{
  106. Frame: oscar.SNACFrame{
  107. FoodGroup: oscar.ChatNav,
  108. SubGroup: oscar.ChatNavNavInfo,
  109. RequestID: inFrame.RequestID,
  110. },
  111. Body: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  112. TLVRestBlock: oscar.TLVRestBlock{
  113. TLVList: oscar.TLVList{
  114. oscar.NewTLV(oscar.ChatNavRequestRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  115. Exchange: room.Exchange,
  116. Cookie: room.Cookie,
  117. InstanceNumber: room.InstanceNumber,
  118. DetailLevel: room.DetailLevel,
  119. TLVBlock: oscar.TLVBlock{
  120. TLVList: room.TLVList(),
  121. },
  122. }),
  123. },
  124. },
  125. },
  126. }, nil
  127. }