session.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. package state
  2. import (
  3. "net/netip"
  4. "sync"
  5. "time"
  6. "github.com/mk6i/retro-aim-server/wire"
  7. )
  8. // SessSendStatus is the result of sending a message to a user.
  9. type SessSendStatus int
  10. const (
  11. // SessSendOK indicates message was sent to recipient
  12. SessSendOK SessSendStatus = iota
  13. // SessSendClosed indicates send did not complete because session is closed
  14. SessSendClosed
  15. // SessQueueFull indicates send failed due to full queue -- client is likely
  16. // dead
  17. SessQueueFull
  18. )
  19. // Session represents a user's current session. Unless stated otherwise, all
  20. // methods may be safely accessed by multiple goroutines.
  21. type Session struct {
  22. awayMessage string
  23. caps [][16]byte
  24. chatRoomCookie string
  25. closed bool
  26. displayScreenName DisplayScreenName
  27. identScreenName IdentScreenName
  28. idle bool
  29. idleTime time.Time
  30. msgCh chan wire.SNACMessage
  31. mutex sync.RWMutex
  32. nowFn func() time.Time
  33. signonComplete bool
  34. signonTime time.Time
  35. stopCh chan struct{}
  36. uin uint32
  37. warning uint16
  38. userInfoBitmask uint16
  39. userStatusBitmask uint32
  40. clientID string
  41. remoteAddr *netip.AddrPort
  42. }
  43. // NewSession returns a new instance of Session. By default, the user may have
  44. // up to 1000 pending messages before blocking.
  45. func NewSession() *Session {
  46. return &Session{
  47. msgCh: make(chan wire.SNACMessage, 1000),
  48. nowFn: time.Now,
  49. stopCh: make(chan struct{}),
  50. signonTime: time.Now(),
  51. caps: make([][16]byte, 0),
  52. userInfoBitmask: wire.OServiceUserFlagOSCARFree,
  53. userStatusBitmask: wire.OServiceUserStatusAvailable,
  54. }
  55. }
  56. // SetRemoteAddr sets the user's remote IP address
  57. func (s *Session) SetRemoteAddr(remoteAddr *netip.AddrPort) {
  58. s.mutex.Lock()
  59. defer s.mutex.Unlock()
  60. s.remoteAddr = remoteAddr
  61. }
  62. // RemoteAddrs returns user's remote IP address
  63. func (s *Session) RemoteAddr() (remoteAddr *netip.AddrPort) {
  64. s.mutex.RLock()
  65. defer s.mutex.RUnlock()
  66. return s.remoteAddr
  67. }
  68. // SetUserInfoFlag sets a flag to and returns UserInfoBitmask
  69. func (s *Session) SetUserInfoFlag(flag uint16) (flags uint16) {
  70. s.mutex.Lock()
  71. defer s.mutex.Unlock()
  72. s.userInfoBitmask |= flag
  73. return s.userInfoBitmask
  74. }
  75. // ClearUserInfoFlag clear a flag from and returns UserInfoBitmask
  76. func (s *Session) ClearUserInfoFlag(flag uint16) (flags uint16) {
  77. s.mutex.Lock()
  78. defer s.mutex.Unlock()
  79. s.userInfoBitmask &^= flag
  80. return s.userInfoBitmask
  81. }
  82. // UserInfoBitmask returns UserInfoBitmask
  83. func (s *Session) UserInfoBitmask() (flags uint16) {
  84. s.mutex.RLock()
  85. defer s.mutex.RUnlock()
  86. return s.userInfoBitmask
  87. }
  88. // SetUserStatusBitmask sets the user status bitmask from the client.
  89. func (s *Session) SetUserStatusBitmask(bitmask uint32) {
  90. s.mutex.Lock()
  91. defer s.mutex.Unlock()
  92. s.userStatusBitmask = bitmask
  93. }
  94. // IncrementWarning increments the user's warning level. To decrease, pass a
  95. // negative increment value.
  96. func (s *Session) IncrementWarning(incr uint16) {
  97. s.mutex.Lock()
  98. defer s.mutex.Unlock()
  99. s.warning += incr
  100. }
  101. // Invisible returns true if the user is idle.
  102. func (s *Session) Invisible() bool {
  103. s.mutex.RLock()
  104. defer s.mutex.RUnlock()
  105. return s.userStatusBitmask&wire.OServiceUserStatusInvisible == wire.OServiceUserStatusInvisible
  106. }
  107. // SetIdentScreenName sets the user's screen name.
  108. func (s *Session) SetIdentScreenName(screenName IdentScreenName) {
  109. s.mutex.Lock()
  110. defer s.mutex.Unlock()
  111. s.identScreenName = screenName
  112. }
  113. // IdentScreenName returns the user's screen name.
  114. func (s *Session) IdentScreenName() IdentScreenName {
  115. s.mutex.RLock()
  116. defer s.mutex.RUnlock()
  117. return s.identScreenName
  118. }
  119. // SetDisplayScreenName sets the user's screen name.
  120. func (s *Session) SetDisplayScreenName(displayScreenName DisplayScreenName) {
  121. s.mutex.Lock()
  122. defer s.mutex.Unlock()
  123. s.displayScreenName = displayScreenName
  124. }
  125. // DisplayScreenName returns the user's screen name.
  126. func (s *Session) DisplayScreenName() DisplayScreenName {
  127. s.mutex.RLock()
  128. defer s.mutex.RUnlock()
  129. return s.displayScreenName
  130. }
  131. // SetSignonTime sets the user's sign-ontime.
  132. func (s *Session) SetSignonTime(t time.Time) {
  133. s.mutex.Lock()
  134. defer s.mutex.Unlock()
  135. s.signonTime = t
  136. }
  137. // SignonTime reports when the user signed on
  138. func (s *Session) SignonTime() time.Time {
  139. s.mutex.RLock()
  140. defer s.mutex.RUnlock()
  141. return s.signonTime
  142. }
  143. // Idle reports the user's idle state.
  144. func (s *Session) Idle() bool {
  145. s.mutex.RLock()
  146. defer s.mutex.RUnlock()
  147. return s.idle
  148. }
  149. // IdleTime reports when the user went idle
  150. func (s *Session) IdleTime() time.Time {
  151. s.mutex.RLock()
  152. defer s.mutex.RUnlock()
  153. return s.idleTime
  154. }
  155. // SetIdle sets the user's idle state.
  156. func (s *Session) SetIdle(dur time.Duration) {
  157. s.mutex.Lock()
  158. defer s.mutex.Unlock()
  159. s.idle = true
  160. // set the time the user became idle
  161. s.idleTime = s.nowFn().Add(-dur)
  162. }
  163. // UnsetIdle removes the user's idle state.
  164. func (s *Session) UnsetIdle() {
  165. s.mutex.Lock()
  166. defer s.mutex.Unlock()
  167. s.idle = false
  168. }
  169. // SetAwayMessage sets the user's away message.
  170. func (s *Session) SetAwayMessage(awayMessage string) {
  171. s.mutex.Lock()
  172. defer s.mutex.Unlock()
  173. s.awayMessage = awayMessage
  174. }
  175. // AwayMessage returns the user's away message.
  176. func (s *Session) AwayMessage() string {
  177. s.mutex.RLock()
  178. defer s.mutex.RUnlock()
  179. return s.awayMessage
  180. }
  181. // SetChatRoomCookie sets the chatRoomCookie for the chat room the user is currently in.
  182. func (s *Session) SetChatRoomCookie(cookie string) {
  183. s.mutex.Lock()
  184. defer s.mutex.Unlock()
  185. s.chatRoomCookie = cookie
  186. }
  187. // ChatRoomCookie gets the chatRoomCookie for the chat room the user is currently in.
  188. func (s *Session) ChatRoomCookie() string {
  189. s.mutex.RLock()
  190. defer s.mutex.RUnlock()
  191. return s.chatRoomCookie
  192. }
  193. // SignonComplete indicates whether the client has completed the sign-on sequence.
  194. func (s *Session) SignonComplete() bool {
  195. s.mutex.RLock()
  196. defer s.mutex.RUnlock()
  197. return s.signonComplete
  198. }
  199. // SetSignonComplete indicates that the client has completed the sign-on sequence.
  200. func (s *Session) SetSignonComplete() {
  201. s.mutex.Lock()
  202. defer s.mutex.Unlock()
  203. s.signonComplete = true
  204. }
  205. // UIN returns the user's ICQ number.
  206. func (s *Session) UIN() uint32 {
  207. s.mutex.RLock()
  208. defer s.mutex.RUnlock()
  209. return s.uin
  210. }
  211. // SetUIN sets the user's ICQ number.
  212. func (s *Session) SetUIN(uin uint32) {
  213. s.mutex.Lock()
  214. defer s.mutex.Unlock()
  215. s.uin = uin
  216. }
  217. // TLVUserInfo returns a TLV list containing session information required by
  218. // multiple SNAC message types that convey user information.
  219. func (s *Session) TLVUserInfo() wire.TLVUserInfo {
  220. s.mutex.RLock()
  221. defer s.mutex.RUnlock()
  222. return wire.TLVUserInfo{
  223. ScreenName: string(s.displayScreenName),
  224. WarningLevel: s.warning,
  225. TLVBlock: wire.TLVBlock{
  226. TLVList: s.userInfo(),
  227. },
  228. }
  229. }
  230. func (s *Session) userInfo() wire.TLVList {
  231. tlvs := wire.TLVList{}
  232. // sign-in timestamp
  233. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoSignonTOD, uint32(s.signonTime.Unix())))
  234. // user info flags
  235. uFlags := s.userInfoBitmask
  236. if s.awayMessage != "" {
  237. uFlags |= wire.OServiceUserFlagUnavailable
  238. }
  239. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoUserFlags, uFlags))
  240. // user status flags
  241. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoStatus, s.userStatusBitmask))
  242. // idle status
  243. if s.idle {
  244. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoIdleTime, uint16(s.nowFn().Sub(s.idleTime).Minutes())))
  245. }
  246. // ICQ direct-connect info. The TLV is required for buddy arrival events to
  247. // work in ICQ, even if the values are set to default.
  248. if s.userInfoBitmask&wire.OServiceUserFlagICQ == wire.OServiceUserFlagICQ {
  249. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoICQDC, wire.ICQDCInfo{}))
  250. }
  251. // capabilities (buddy icon, chat, etc...)
  252. if len(s.caps) > 0 {
  253. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoOscarCaps, s.caps))
  254. }
  255. return tlvs
  256. }
  257. // SetCaps sets capability UUIDs that represent the features the client
  258. // supports. If set, capability metadata appears in the user info TLV list.
  259. func (s *Session) SetCaps(caps [][16]byte) {
  260. s.mutex.Lock()
  261. defer s.mutex.Unlock()
  262. s.caps = caps
  263. }
  264. // Caps retrieves user capabilities.
  265. func (s *Session) Caps() [][16]byte {
  266. s.mutex.RLock()
  267. defer s.mutex.RUnlock()
  268. return s.caps
  269. }
  270. func (s *Session) Warning() uint16 {
  271. s.mutex.RLock()
  272. defer s.mutex.RUnlock()
  273. var w uint16
  274. w = s.warning
  275. return w
  276. }
  277. // ReceiveMessage returns a channel of messages relayed via this session. It
  278. // may only be read by one consumer. The channel never closes; call this method
  279. // in a select block along with Closed in order to detect session closure.
  280. func (s *Session) ReceiveMessage() chan wire.SNACMessage {
  281. return s.msgCh
  282. }
  283. // RelayMessage receives a SNAC message from a user and passes it on
  284. // asynchronously to the consumer of this session's messages. It returns
  285. // SessSendStatus to indicate whether the message was successfully sent or
  286. // not. This method is non-blocking.
  287. func (s *Session) RelayMessage(msg wire.SNACMessage) SessSendStatus {
  288. s.mutex.RLock()
  289. defer s.mutex.RUnlock()
  290. if s.closed {
  291. return SessSendClosed
  292. }
  293. select {
  294. case s.msgCh <- msg:
  295. return SessSendOK
  296. case <-s.stopCh:
  297. return SessSendClosed
  298. default:
  299. return SessQueueFull
  300. }
  301. }
  302. // Close shuts down the session's ability to relay messages. Once invoked,
  303. // RelayMessage returns SessQueueFull and Closed returns a closed channel.
  304. // It is not possible to re-open message relaying once closed. It is safe to
  305. // call from multiple go routines.
  306. func (s *Session) Close() {
  307. s.mutex.Lock()
  308. defer s.mutex.Unlock()
  309. if s.closed {
  310. return
  311. }
  312. close(s.stopCh)
  313. s.closed = true
  314. }
  315. // Closed blocks until the session is closed.
  316. func (s *Session) Closed() <-chan struct{} {
  317. return s.stopCh
  318. }
  319. // SetClientID sets the client ID.
  320. func (s *Session) SetClientID(clientID string) {
  321. s.mutex.Lock()
  322. defer s.mutex.Unlock()
  323. s.clientID = clientID
  324. }
  325. // ClientID retrieves the client ID.
  326. func (s *Session) ClientID() string {
  327. s.mutex.RLock()
  328. defer s.mutex.RUnlock()
  329. return s.clientID
  330. }