session.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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. // RateClassState tracks the rate limiting state for a specific rate class
  11. // within a user's session.
  12. //
  13. // It embeds the static wire.RateClass configuration and maintains dynamic,
  14. // per-session state used to evaluate rate limits in real time.
  15. type RateClassState struct {
  16. // static rate limit configuration for this class
  17. wire.RateClass
  18. // CurrentLevel is the current exponential moving average for this rate
  19. // class.
  20. CurrentLevel int32
  21. // LastTime represents the last time a SNAC message was sent for this rate
  22. // class.
  23. LastTime time.Time
  24. // CurrentStatus is the last recorded rate limit status for this rate class.
  25. CurrentStatus wire.RateLimitStatus
  26. // Subscribed indicates whether the user wants to receive rate limit
  27. // parameter updates for this rate class.
  28. Subscribed bool
  29. // LimitedNow indicates whether the user is currently rate limited for this
  30. // rate class; the user is blocked from sending SNACs in this rate class
  31. // until the clear threshold is met.
  32. LimitedNow bool
  33. }
  34. const (
  35. // SessSendOK indicates message was sent to recipient
  36. SessSendOK SessSendStatus = iota
  37. // SessSendClosed indicates send did not complete because session is closed
  38. SessSendClosed
  39. // SessQueueFull indicates send failed due to full queue -- client is likely
  40. // dead
  41. SessQueueFull
  42. )
  43. // Session represents a user's current session. Unless stated otherwise, all
  44. // methods may be safely accessed by multiple goroutines.
  45. type Session struct {
  46. awayMessage string
  47. caps [][16]byte
  48. chatRoomCookie string
  49. clientID string
  50. closed bool
  51. displayScreenName DisplayScreenName
  52. foodGroupVersions [wire.MDir + 1]uint16
  53. identScreenName IdentScreenName
  54. idle bool
  55. idleTime time.Time
  56. lastObservedStates [5]RateClassState
  57. msgCh chan wire.SNACMessage
  58. multiConnFlag wire.MultiConnFlag
  59. mutex sync.RWMutex
  60. nowFn func() time.Time
  61. rateLimitStates [5]RateClassState
  62. rateLimitStatesOriginal [5]RateClassState
  63. remoteAddr *netip.AddrPort
  64. signonComplete bool
  65. signonTime time.Time
  66. stopCh chan struct{}
  67. typingEventsEnabled bool
  68. uin uint32
  69. userInfoBitmask uint16
  70. userStatusBitmask uint32
  71. warning uint16
  72. warningCh chan uint16
  73. lastWarnUpdate time.Time
  74. }
  75. // NewSession returns a new instance of Session. By default, the user may have
  76. // up to 1000 pending messages before blocking.
  77. func NewSession() *Session {
  78. now := time.Now()
  79. return &Session{
  80. msgCh: make(chan wire.SNACMessage, 1000),
  81. nowFn: time.Now,
  82. stopCh: make(chan struct{}),
  83. signonTime: now,
  84. caps: make([][16]byte, 0),
  85. userInfoBitmask: wire.OServiceUserFlagOSCARFree,
  86. userStatusBitmask: wire.OServiceUserStatusAvailable,
  87. foodGroupVersions: func() [wire.MDir + 1]uint16 {
  88. // initialize default food groups versions to 1.0
  89. vals := [wire.MDir + 1]uint16{}
  90. vals[wire.OService] = 1
  91. vals[wire.Locate] = 1
  92. vals[wire.Buddy] = 1
  93. vals[wire.ICBM] = 1
  94. vals[wire.Advert] = 1
  95. vals[wire.Invite] = 1
  96. vals[wire.Admin] = 1
  97. vals[wire.Popup] = 1
  98. vals[wire.PermitDeny] = 1
  99. vals[wire.UserLookup] = 1
  100. vals[wire.Stats] = 1
  101. vals[wire.Translate] = 1
  102. vals[wire.ChatNav] = 1
  103. vals[wire.Chat] = 1
  104. vals[wire.ODir] = 1
  105. vals[wire.BART] = 1
  106. vals[wire.Feedbag] = 1
  107. vals[wire.ICQ] = 1
  108. vals[wire.BUCP] = 1
  109. vals[wire.Alert] = 1
  110. vals[wire.Plugin] = 1
  111. vals[wire.UnnamedFG24] = 1
  112. vals[wire.MDir] = 1
  113. return vals
  114. }(),
  115. warningCh: make(chan uint16, 1),
  116. }
  117. }
  118. func (s *Session) SetRateClasses(now time.Time, classes wire.RateLimitClasses) {
  119. s.mutex.Lock()
  120. defer s.mutex.Unlock()
  121. var newStates [5]RateClassState
  122. for i, class := range classes.All() {
  123. newStates[i] = RateClassState{
  124. CurrentLevel: class.MaxLevel,
  125. CurrentStatus: wire.RateLimitStatusClear,
  126. LastTime: now,
  127. RateClass: class,
  128. Subscribed: s.lastObservedStates[i].Subscribed,
  129. }
  130. }
  131. if s.lastObservedStates[0].ID == 0 {
  132. s.lastObservedStates = newStates
  133. } else {
  134. s.lastObservedStates = s.rateLimitStates
  135. }
  136. s.rateLimitStates = newStates
  137. s.rateLimitStatesOriginal = newStates
  138. }
  139. // SetRemoteAddr sets the user's remote IP address
  140. func (s *Session) SetRemoteAddr(remoteAddr *netip.AddrPort) {
  141. s.mutex.Lock()
  142. defer s.mutex.Unlock()
  143. s.remoteAddr = remoteAddr
  144. }
  145. // RemoteAddrs returns user's remote IP address
  146. func (s *Session) RemoteAddr() (remoteAddr *netip.AddrPort) {
  147. s.mutex.RLock()
  148. defer s.mutex.RUnlock()
  149. return s.remoteAddr
  150. }
  151. // SetUserInfoFlag sets a flag to and returns UserInfoBitmask
  152. func (s *Session) SetUserInfoFlag(flag uint16) (flags uint16) {
  153. s.mutex.Lock()
  154. defer s.mutex.Unlock()
  155. s.userInfoBitmask |= flag
  156. return s.userInfoBitmask
  157. }
  158. // ClearUserInfoFlag clear a flag from and returns UserInfoBitmask
  159. func (s *Session) ClearUserInfoFlag(flag uint16) (flags uint16) {
  160. s.mutex.Lock()
  161. defer s.mutex.Unlock()
  162. s.userInfoBitmask &^= flag
  163. return s.userInfoBitmask
  164. }
  165. // UserInfoBitmask returns UserInfoBitmask
  166. func (s *Session) UserInfoBitmask() (flags uint16) {
  167. s.mutex.RLock()
  168. defer s.mutex.RUnlock()
  169. return s.userInfoBitmask
  170. }
  171. // RateLimitStates returns the current session rate limits
  172. func (s *Session) RateLimitStates() [5]RateClassState {
  173. return s.rateLimitStates
  174. }
  175. // SetUserStatusBitmask sets the user status bitmask from the client.
  176. func (s *Session) SetUserStatusBitmask(bitmask uint32) {
  177. s.mutex.Lock()
  178. defer s.mutex.Unlock()
  179. s.userStatusBitmask = bitmask
  180. }
  181. // UserStatusBitmask returns the user status bitmask.
  182. func (s *Session) UserStatusBitmask() uint32 {
  183. s.mutex.RLock()
  184. defer s.mutex.RUnlock()
  185. return s.userStatusBitmask
  186. }
  187. // ScaleWarningAndRateLimit increments the user's warning level and scales a rate limit accordingly.
  188. // The incr parameter is the warning increment (negative to decrease), and classID specifies
  189. // which rate limit class to scale. The incr param is a percentage represented as an integer
  190. // where 30 = 3.0%, 100 = 10.0%, etc.
  191. func (s *Session) ScaleWarningAndRateLimit(incr int16, classID wire.RateLimitClassID) (bool, uint16) {
  192. s.mutex.Lock()
  193. defer s.mutex.Unlock()
  194. // Handle warning level increment
  195. newWarning := int32(s.warning) + int32(incr)
  196. if newWarning > 1000 {
  197. return false, 0
  198. }
  199. if newWarning < 0 {
  200. s.warning = 0 // clamp min at 0
  201. } else {
  202. s.warning = uint16(newWarning)
  203. }
  204. pct := float32(incr) / 1000.0
  205. // create reference variables for better readability
  206. rateClass := &s.rateLimitStates[classID-1]
  207. originalRateClass := &s.rateLimitStatesOriginal[classID-1]
  208. // clamp function to constrain values between min and max
  209. clamp := func(value, min, max int32) int32 {
  210. if value < min {
  211. return min
  212. }
  213. if value > max {
  214. return max
  215. }
  216. return value
  217. }
  218. // Apply a buffer to limit/clear/alert levels so that they never approach
  219. // too close to the maximum level. Otherwise, AIM 4.8 exhibits instability
  220. // (client crashes, IM window glitches) when the warning level reaches 90-100%.
  221. maxLevel := originalRateClass.MaxLevel - 150
  222. // scale the rate limit parameters
  223. newLimitLevel := rateClass.LimitLevel + int32(float32(maxLevel-originalRateClass.LimitLevel)*pct)
  224. rateClass.LimitLevel = clamp(newLimitLevel, originalRateClass.LimitLevel, originalRateClass.MaxLevel)
  225. newLimitLevel = rateClass.ClearLevel + int32(float32(maxLevel-originalRateClass.ClearLevel)*pct)
  226. rateClass.ClearLevel = clamp(newLimitLevel, originalRateClass.ClearLevel, originalRateClass.MaxLevel)
  227. newLimitLevel = rateClass.AlertLevel + int32(float32(maxLevel-originalRateClass.AlertLevel)*pct)
  228. rateClass.AlertLevel = clamp(newLimitLevel, originalRateClass.AlertLevel, originalRateClass.MaxLevel)
  229. s.warningCh <- s.warning
  230. return true, s.warning
  231. }
  232. // SetWarning sets the user's last warning level.
  233. func (s *Session) SetWarning(warning uint16) {
  234. s.mutex.Lock()
  235. defer s.mutex.Unlock()
  236. s.warning = warning
  237. }
  238. // Warning returns the user's current warning level as a percentage.
  239. // The warning level is stored as an integer representation of a percentage
  240. // where 30 = 3.0%, 100 = 10.0%, 1000 = 100.0%, etc.
  241. // This is how the OSCAR protocol represents warning percentages.
  242. func (s *Session) Warning() uint16 {
  243. s.mutex.RLock()
  244. defer s.mutex.RUnlock()
  245. return s.warning
  246. }
  247. // WarningCh returns the warning notification channel.
  248. // Listeners can receive from this channel to be notified when warnings occur.
  249. func (s *Session) WarningCh() chan uint16 {
  250. return s.warningCh
  251. }
  252. // Invisible returns true if the user is idle.
  253. func (s *Session) Invisible() bool {
  254. s.mutex.RLock()
  255. defer s.mutex.RUnlock()
  256. return s.userStatusBitmask&wire.OServiceUserStatusInvisible == wire.OServiceUserStatusInvisible
  257. }
  258. // SetIdentScreenName sets the user's screen name.
  259. func (s *Session) SetIdentScreenName(screenName IdentScreenName) {
  260. s.mutex.Lock()
  261. defer s.mutex.Unlock()
  262. s.identScreenName = screenName
  263. }
  264. // IdentScreenName returns the user's screen name.
  265. func (s *Session) IdentScreenName() IdentScreenName {
  266. s.mutex.RLock()
  267. defer s.mutex.RUnlock()
  268. return s.identScreenName
  269. }
  270. // SetDisplayScreenName sets the user's screen name.
  271. func (s *Session) SetDisplayScreenName(displayScreenName DisplayScreenName) {
  272. s.mutex.Lock()
  273. defer s.mutex.Unlock()
  274. s.displayScreenName = displayScreenName
  275. }
  276. // DisplayScreenName returns the user's screen name.
  277. func (s *Session) DisplayScreenName() DisplayScreenName {
  278. s.mutex.RLock()
  279. defer s.mutex.RUnlock()
  280. return s.displayScreenName
  281. }
  282. // SetSignonTime sets the user's sign-ontime.
  283. func (s *Session) SetSignonTime(t time.Time) {
  284. s.mutex.Lock()
  285. defer s.mutex.Unlock()
  286. s.signonTime = t
  287. }
  288. // SignonTime reports when the user signed on
  289. func (s *Session) SignonTime() time.Time {
  290. s.mutex.RLock()
  291. defer s.mutex.RUnlock()
  292. return s.signonTime
  293. }
  294. // Idle reports the user's idle state.
  295. func (s *Session) Idle() bool {
  296. s.mutex.RLock()
  297. defer s.mutex.RUnlock()
  298. return s.idle
  299. }
  300. // IdleTime reports when the user went idle
  301. func (s *Session) IdleTime() time.Time {
  302. s.mutex.RLock()
  303. defer s.mutex.RUnlock()
  304. return s.idleTime
  305. }
  306. // SetIdle sets the user's idle state.
  307. func (s *Session) SetIdle(dur time.Duration) {
  308. s.mutex.Lock()
  309. defer s.mutex.Unlock()
  310. s.idle = true
  311. // set the time the user became idle
  312. s.idleTime = s.nowFn().Add(-dur)
  313. }
  314. // UnsetIdle removes the user's idle state.
  315. func (s *Session) UnsetIdle() {
  316. s.mutex.Lock()
  317. defer s.mutex.Unlock()
  318. s.idle = false
  319. }
  320. // SetAwayMessage sets the user's away message.
  321. func (s *Session) SetAwayMessage(awayMessage string) {
  322. s.mutex.Lock()
  323. defer s.mutex.Unlock()
  324. s.awayMessage = awayMessage
  325. }
  326. // AwayMessage returns the user's away message.
  327. func (s *Session) AwayMessage() string {
  328. s.mutex.RLock()
  329. defer s.mutex.RUnlock()
  330. return s.awayMessage
  331. }
  332. // SetChatRoomCookie sets the chatRoomCookie for the chat room the user is currently in.
  333. func (s *Session) SetChatRoomCookie(cookie string) {
  334. s.mutex.Lock()
  335. defer s.mutex.Unlock()
  336. s.chatRoomCookie = cookie
  337. }
  338. // ChatRoomCookie gets the chatRoomCookie for the chat room the user is currently in.
  339. func (s *Session) ChatRoomCookie() string {
  340. s.mutex.RLock()
  341. defer s.mutex.RUnlock()
  342. return s.chatRoomCookie
  343. }
  344. // SignonComplete indicates whether the client has completed the sign-on sequence.
  345. func (s *Session) SignonComplete() bool {
  346. s.mutex.RLock()
  347. defer s.mutex.RUnlock()
  348. return s.signonComplete
  349. }
  350. // SetSignonComplete indicates that the client has completed the sign-on sequence.
  351. func (s *Session) SetSignonComplete() {
  352. s.mutex.Lock()
  353. defer s.mutex.Unlock()
  354. s.signonComplete = true
  355. }
  356. // UIN returns the user's ICQ number.
  357. func (s *Session) UIN() uint32 {
  358. s.mutex.RLock()
  359. defer s.mutex.RUnlock()
  360. return s.uin
  361. }
  362. // SetUIN sets the user's ICQ number.
  363. func (s *Session) SetUIN(uin uint32) {
  364. s.mutex.Lock()
  365. defer s.mutex.Unlock()
  366. s.uin = uin
  367. }
  368. // TLVUserInfo returns a TLV list containing session information required by
  369. // multiple SNAC message types that convey user information.
  370. func (s *Session) TLVUserInfo() wire.TLVUserInfo {
  371. s.mutex.RLock()
  372. defer s.mutex.RUnlock()
  373. return wire.TLVUserInfo{
  374. ScreenName: string(s.displayScreenName),
  375. WarningLevel: uint16(s.warning),
  376. TLVBlock: wire.TLVBlock{
  377. TLVList: s.userInfo(),
  378. },
  379. }
  380. }
  381. func (s *Session) userInfo() wire.TLVList {
  382. tlvs := wire.TLVList{}
  383. // sign-in timestamp
  384. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoSignonTOD, uint32(s.signonTime.Unix())))
  385. // user info flags
  386. uFlags := s.userInfoBitmask
  387. if s.awayMessage != "" {
  388. uFlags |= wire.OServiceUserFlagUnavailable
  389. }
  390. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoUserFlags, uFlags))
  391. // user status flags
  392. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoStatus, s.userStatusBitmask))
  393. // idle status
  394. if s.idle {
  395. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoIdleTime, uint16(s.nowFn().Sub(s.idleTime).Minutes())))
  396. }
  397. // ICQ direct-connect info. The TLV is required for buddy arrival events to
  398. // work in ICQ, even if the values are set to default.
  399. if s.userInfoBitmask&wire.OServiceUserFlagICQ == wire.OServiceUserFlagICQ {
  400. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoICQDC, wire.ICQDCInfo{}))
  401. }
  402. // capabilities (buddy icon, chat, etc...)
  403. if len(s.caps) > 0 {
  404. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoOscarCaps, s.caps))
  405. }
  406. tlvs.Append(wire.NewTLVBE(wire.OServiceUserInfoMySubscriptions, uint32(0)))
  407. return tlvs
  408. }
  409. // SetCaps sets capability UUIDs that represent the features the client
  410. // supports. If set, capability metadata appears in the user info TLV list.
  411. func (s *Session) SetCaps(caps [][16]byte) {
  412. s.mutex.Lock()
  413. defer s.mutex.Unlock()
  414. s.caps = caps
  415. }
  416. // Caps retrieves user capabilities.
  417. func (s *Session) Caps() [][16]byte {
  418. s.mutex.RLock()
  419. defer s.mutex.RUnlock()
  420. return s.caps
  421. }
  422. // ReceiveMessage returns a channel of messages relayed via this session. It
  423. // may only be read by one consumer. The channel never closes; call this method
  424. // in a select block along with Closed in order to detect session closure.
  425. func (s *Session) ReceiveMessage() chan wire.SNACMessage {
  426. return s.msgCh
  427. }
  428. // RelayMessage receives a SNAC message from a user and passes it on
  429. // asynchronously to the consumer of this session's messages. It returns
  430. // SessSendStatus to indicate whether the message was successfully sent or
  431. // not. This method is non-blocking.
  432. func (s *Session) RelayMessage(msg wire.SNACMessage) SessSendStatus {
  433. s.mutex.RLock()
  434. defer s.mutex.RUnlock()
  435. if s.closed {
  436. return SessSendClosed
  437. }
  438. select {
  439. case s.msgCh <- msg:
  440. return SessSendOK
  441. case <-s.stopCh:
  442. return SessSendClosed
  443. default:
  444. return SessQueueFull
  445. }
  446. }
  447. // Close shuts down the session's ability to relay messages. Once invoked,
  448. // RelayMessage returns SessQueueFull and Closed returns a closed channel.
  449. // It is not possible to re-open message relaying once closed. It is safe to
  450. // call from multiple go routines.
  451. func (s *Session) Close() {
  452. s.mutex.Lock()
  453. defer s.mutex.Unlock()
  454. s.close()
  455. }
  456. func (s *Session) close() {
  457. if s.closed {
  458. return
  459. }
  460. close(s.stopCh)
  461. s.closed = true
  462. }
  463. // Closed blocks until the session is closed.
  464. func (s *Session) Closed() <-chan struct{} {
  465. return s.stopCh
  466. }
  467. // SetClientID sets the client ID.
  468. func (s *Session) SetClientID(clientID string) {
  469. s.mutex.Lock()
  470. defer s.mutex.Unlock()
  471. s.clientID = clientID
  472. }
  473. // ClientID retrieves the client ID.
  474. func (s *Session) ClientID() string {
  475. s.mutex.RLock()
  476. defer s.mutex.RUnlock()
  477. return s.clientID
  478. }
  479. // SubscribeRateLimits subscribes the Session to updates for the specified
  480. // rate limit classes. Future calls to ObserveRateChanges will report changes
  481. // for these classes.
  482. func (s *Session) SubscribeRateLimits(classes []wire.RateLimitClassID) {
  483. s.mutex.Lock()
  484. defer s.mutex.Unlock()
  485. for _, classID := range classes {
  486. s.rateLimitStates[classID-1].Subscribed = true
  487. }
  488. }
  489. // ObserveRateChanges updates rate limit states for all known classes and returns
  490. // any classes and class states that have changed since the previous observation.
  491. func (s *Session) ObserveRateChanges(now time.Time) (classDelta []RateClassState, stateDelta []RateClassState) {
  492. s.mutex.Lock()
  493. defer s.mutex.Unlock()
  494. for i, params := range s.rateLimitStates {
  495. if !params.Subscribed {
  496. continue
  497. }
  498. state, level := wire.CheckRateLimit(params.LastTime, now, params.RateClass, params.CurrentLevel, params.LimitedNow)
  499. s.rateLimitStates[i].CurrentStatus = state
  500. // clear limited now flag if passing from limited state to clear state
  501. if s.rateLimitStates[i].LimitedNow && state == wire.RateLimitStatusClear {
  502. s.rateLimitStates[i].LimitedNow = false
  503. s.rateLimitStates[i].CurrentLevel = level
  504. }
  505. // did rate class change?
  506. if params.RateClass != s.lastObservedStates[i].RateClass {
  507. classDelta = append(classDelta, s.rateLimitStates[i])
  508. }
  509. // did rate limit status change?
  510. if s.lastObservedStates[i].CurrentStatus != s.rateLimitStates[i].CurrentStatus {
  511. stateDelta = append(stateDelta, s.rateLimitStates[i])
  512. }
  513. // save it for next time
  514. s.lastObservedStates[i] = s.rateLimitStates[i]
  515. }
  516. return classDelta, stateDelta
  517. }
  518. // EvaluateRateLimit checks and updates the session’s rate limit state
  519. // for the given rate class ID. If the rate status reaches 'disconnect',
  520. // the session is closed. Rate limits are not enforced if the user is a bot
  521. // (has wire.OServiceUserFlagBot set in their user info bitmask).
  522. func (s *Session) EvaluateRateLimit(now time.Time, rateClassID wire.RateLimitClassID) wire.RateLimitStatus {
  523. s.mutex.Lock()
  524. defer s.mutex.Unlock()
  525. if s.userInfoBitmask&wire.OServiceUserFlagBot == wire.OServiceUserFlagBot {
  526. return wire.RateLimitStatusClear // don't rate limit bots
  527. }
  528. rateClass := &s.rateLimitStates[rateClassID-1]
  529. status, newLevel := wire.CheckRateLimit(rateClass.LastTime, now, rateClass.RateClass, rateClass.CurrentLevel, rateClass.LimitedNow)
  530. rateClass.CurrentLevel = newLevel
  531. rateClass.CurrentStatus = status
  532. rateClass.LastTime = now
  533. rateClass.LimitedNow = status == wire.RateLimitStatusLimited
  534. if status == wire.RateLimitStatusDisconnect {
  535. s.close()
  536. }
  537. return status
  538. }
  539. // SetFoodGroupVersions sets the client's supported food group versions
  540. func (s *Session) SetFoodGroupVersions(versions [wire.MDir + 1]uint16) {
  541. s.mutex.Lock()
  542. defer s.mutex.Unlock()
  543. s.foodGroupVersions = versions
  544. }
  545. // FoodGroupVersions retrieves the client's supported food group versions.
  546. func (s *Session) FoodGroupVersions() [wire.MDir + 1]uint16 {
  547. s.mutex.RLock()
  548. defer s.mutex.RUnlock()
  549. return s.foodGroupVersions
  550. }
  551. // TypingEventsEnabled indicates whether the client wants to send and receive
  552. // typing events.
  553. func (s *Session) TypingEventsEnabled() bool {
  554. s.mutex.RLock()
  555. defer s.mutex.RUnlock()
  556. return s.typingEventsEnabled
  557. }
  558. // SetTypingEventsEnabled sets whether the client wants to send and receive
  559. // typing events.
  560. func (s *Session) SetTypingEventsEnabled(enabled bool) {
  561. s.mutex.Lock()
  562. defer s.mutex.Unlock()
  563. s.typingEventsEnabled = enabled
  564. }
  565. // SetMultiConnFlag sets the multi-connection flag for this session.
  566. func (s *Session) SetMultiConnFlag(flag wire.MultiConnFlag) {
  567. s.mutex.Lock()
  568. defer s.mutex.Unlock()
  569. s.multiConnFlag = flag
  570. }
  571. // MultiConnFlag retrieves the multi-connection flag for this session.
  572. func (s *Session) MultiConnFlag() wire.MultiConnFlag {
  573. s.mutex.RLock()
  574. defer s.mutex.RUnlock()
  575. return s.multiConnFlag
  576. }