session.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package server
  2. import (
  3. "github.com/google/uuid"
  4. "github.com/mkaminski/goaim/oscar"
  5. "sync"
  6. "time"
  7. )
  8. var CapChat, _ = uuid.MustParse("748F2420-6287-11D1-8222-444553540000").MarshalBinary()
  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. type Session struct {
  20. awayMessage string
  21. closed bool
  22. id string
  23. idle bool
  24. idleTime time.Time
  25. invisible bool
  26. msgCh chan oscar.XMessage
  27. mutex sync.RWMutex
  28. screenName string
  29. signonTime time.Time
  30. stopCh chan struct{}
  31. warning uint16
  32. }
  33. func (s *Session) IncreaseWarning(incr uint16) {
  34. s.mutex.Lock()
  35. defer s.mutex.Unlock()
  36. s.warning += incr
  37. }
  38. func (s *Session) SetInvisible(invisible bool) {
  39. s.mutex.Lock()
  40. defer s.mutex.Unlock()
  41. s.invisible = invisible
  42. }
  43. func (s *Session) SetScreenName(screenName string) {
  44. s.mutex.Lock()
  45. defer s.mutex.Unlock()
  46. s.screenName = screenName
  47. }
  48. func (s *Session) ScreenName() string {
  49. s.mutex.RLock()
  50. defer s.mutex.RUnlock()
  51. return s.screenName
  52. }
  53. func (s *Session) SetID(ID string) {
  54. s.mutex.Lock()
  55. defer s.mutex.Unlock()
  56. s.id = ID
  57. }
  58. func (s *Session) SetSignonTime(t time.Time) {
  59. s.mutex.Lock()
  60. defer s.mutex.Unlock()
  61. s.signonTime = t
  62. }
  63. func (s *Session) ID() string {
  64. s.mutex.RLock()
  65. defer s.mutex.RUnlock()
  66. return s.id
  67. }
  68. func (s *Session) Invisible() bool {
  69. s.mutex.RLock()
  70. defer s.mutex.RUnlock()
  71. return s.invisible
  72. }
  73. func (s *Session) SetIdle(dur time.Duration) {
  74. s.mutex.Lock()
  75. defer s.mutex.Unlock()
  76. s.idle = true
  77. // set the time the user became idle
  78. s.idleTime = time.Now().Add(-dur)
  79. }
  80. func (s *Session) SetActive() {
  81. s.mutex.Lock()
  82. defer s.mutex.Unlock()
  83. s.idle = false
  84. }
  85. func (s *Session) Idle() bool {
  86. s.mutex.RLock()
  87. defer s.mutex.RUnlock()
  88. return s.idle
  89. }
  90. func (s *Session) SetAwayMessage(awayMessage string) {
  91. s.mutex.Lock()
  92. defer s.mutex.Unlock()
  93. s.awayMessage = awayMessage
  94. }
  95. func (s *Session) AwayMessage() string {
  96. s.mutex.RLock()
  97. defer s.mutex.RUnlock()
  98. return s.awayMessage
  99. }
  100. func (s *Session) TLVUserInfo() oscar.TLVUserInfo {
  101. s.mutex.RLock()
  102. defer s.mutex.RUnlock()
  103. return oscar.TLVUserInfo{
  104. ScreenName: s.screenName,
  105. WarningLevel: s.warning,
  106. TLVBlock: oscar.TLVBlock{
  107. TLVList: s.UserInfo(),
  108. },
  109. }
  110. }
  111. func (s *Session) UserInfo() oscar.TLVList {
  112. s.mutex.RLock()
  113. defer s.mutex.RUnlock()
  114. // sign-in timestamp
  115. tlvs := oscar.TLVList{}
  116. tlvs.AddTLV(oscar.NewTLV(0x03, uint32(s.signonTime.Unix())))
  117. // away message status
  118. if s.awayMessage != "" {
  119. tlvs.AddTLV(oscar.NewTLV(0x01, uint16(0x0010)|uint16(0x0020)))
  120. } else {
  121. tlvs.AddTLV(oscar.NewTLV(0x01, uint16(0x0010)))
  122. }
  123. // invisibility status
  124. if s.invisible {
  125. tlvs.AddTLV(oscar.NewTLV(0x06, uint16(0x0100)))
  126. } else {
  127. tlvs.AddTLV(oscar.NewTLV(0x06, uint16(0x0000)))
  128. }
  129. // idle status
  130. if s.idle {
  131. tlvs.AddTLV(oscar.NewTLV(0x04, uint16(time.Now().Sub(s.idleTime).Seconds())))
  132. } else {
  133. tlvs.AddTLV(oscar.NewTLV(0x04, uint16(0)))
  134. }
  135. // capabilities
  136. var caps []byte
  137. // chat capability
  138. caps = append(caps, CapChat...)
  139. tlvs.AddTLV(oscar.NewTLV(0x0D, caps))
  140. return tlvs
  141. }
  142. func (s *Session) Warning() uint16 {
  143. var w uint16
  144. s.mutex.RLock()
  145. w = s.warning
  146. s.mutex.RUnlock()
  147. return w
  148. }
  149. func (s *Session) RecvMessage() chan oscar.XMessage {
  150. return s.msgCh
  151. }
  152. func (s *Session) SendMessage(msg oscar.XMessage) SessSendStatus {
  153. s.mutex.Lock()
  154. if s.closed {
  155. return SessSendClosed
  156. }
  157. s.mutex.Unlock()
  158. select {
  159. case s.msgCh <- msg:
  160. return SessSendOK
  161. case <-s.stopCh:
  162. return SessSendClosed
  163. default:
  164. return SessQueueFull
  165. }
  166. }
  167. func (s *Session) Close() {
  168. s.mutex.Lock()
  169. defer s.mutex.Unlock()
  170. if s.closed {
  171. return
  172. }
  173. close(s.stopCh)
  174. s.closed = true
  175. }
  176. func (s *Session) Closed() <-chan struct{} {
  177. return s.stopCh
  178. }
  179. func NewSession() *Session {
  180. return &Session{
  181. msgCh: make(chan oscar.XMessage, 1000),
  182. stopCh: make(chan struct{}),
  183. signonTime: time.Now(),
  184. }
  185. }