You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

chat.service.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import PubNub from 'pubnub'
  2. import { ChatMessage } from '../entities/index.js'
  3. const MAIN_CHANNEL = 'Channel-Siimee'
  4. /**
  5. * Provider method holder
  6. * We always reference this object so
  7. * we don't have to hardcode provider specific
  8. * methods for doing chat things.
  9. *
  10. * This gets overloaded later in the program
  11. */
  12. const _providerMethods = {
  13. publish: () => console.error('no provider publish method set'),
  14. subscribe: () => console.error('no provider subscribe method set'),
  15. listen: () => console.error('no provider listen method set'),
  16. }
  17. /**
  18. * Breaking out as much pubnub specific flavor
  19. */
  20. const _setPubnubKeys = testing => {
  21. let keys = {}
  22. if (testing) {
  23. keys = testing
  24. } else {
  25. ;(keys.publishKey = import.meta.env.VITE_PUBNUB_PUBLISH_KEY),
  26. (keys.subscribeKey = import.meta.env.VITE_PUBNUB_SUBSCRIBE_KEY)
  27. }
  28. return keys
  29. }
  30. const _setupPubnub = async (uuid, testing) => {
  31. if (!uuid) return console.error('no pubnub uuid set')
  32. const keys = _setPubnubKeys(testing)
  33. const pubnubClient = await new PubNub({
  34. publishKey: keys.publishKey,
  35. subscribeKey: keys.subscribeKey,
  36. logVerbosity: false,
  37. uuid,
  38. })
  39. // Pass pubnub specific methods to our placeholder obj
  40. _providerMethods['publish'] = pubnubClient.publish
  41. _providerMethods['subscribe'] = pubnubClient.subscribe
  42. _providerMethods['listen'] = pubnubClient.addListener
  43. return pubnubClient
  44. }
  45. /** Singleton that holds all our chat information */
  46. class Chatter {
  47. /**
  48. * Create our chatter instance
  49. * @return {Chatter} our chatter instance object
  50. */
  51. constructor() {
  52. // Our pubnub instance
  53. this.provider = null
  54. this.uuid = null
  55. this._subscriptions = [MAIN_CHANNEL]
  56. this.listeners = {
  57. status: async e => {
  58. if (e.category !== 'PNConnectedCategory') return
  59. },
  60. message: null, // Set manually in chat view
  61. presence: this._onPresence,
  62. }
  63. }
  64. get subscriptions() {
  65. let truncated = this._subscriptions
  66. // Do NOT include the main channel as part of subscriptions
  67. const mainChanIndex = truncated.indexOf(MAIN_CHANNEL)
  68. if (mainChanIndex > -1) {
  69. truncated.splice(mainChanIndex, 1)
  70. }
  71. return truncated
  72. }
  73. async _onPresence(e) {
  74. console.log('presence :', e)
  75. return
  76. }
  77. setOnMessage(cb) {
  78. this.listeners.message = cb
  79. }
  80. async setup(uuid, groupings, testing = false) {
  81. this.uuid = `${uuid}`
  82. // Pass api keys in ugle fasion for testing purposes
  83. // TODO: refactor this with a mock
  84. this.provider = await _setupPubnub(this.uuid, testing)
  85. // step_1: build the this.groupings object from the backend
  86. // await for the groupings to be fetched before subscribing to channels
  87. await this._setupAllChannels(groupings)
  88. this._listenFor({ listeners: this.listeners })
  89. this.subscribe({ channels: this._subscriptions })
  90. return this.subscriptions
  91. }
  92. async getHistory(channel, count = 10) {
  93. console.warn('[chatter] grabbing history for channel:', channel)
  94. let pastMessages = null
  95. try {
  96. pastMessages = await this.provider.fetchMessages({
  97. channels: [channel],
  98. count: count,
  99. includeMessageType: true,
  100. includeUUID: true,
  101. includeMeta: true,
  102. includeMessageActions: false,
  103. })
  104. } catch (error) {
  105. console.error('[chatter]', error)
  106. }
  107. const channelHistory =
  108. pastMessages && pastMessages.channels
  109. ? pastMessages.channels[channel]
  110. : null
  111. console.log('channelHistory :>> ', channelHistory)
  112. return channelHistory
  113. ? channelHistory.map(msg => ({
  114. publisher: msg.uuid,
  115. message: new ChatMessage(msg.message.description),
  116. timetoken: msg.timetoken,
  117. }))
  118. : []
  119. }
  120. /**
  121. * Send a message to a channel
  122. * example = new ChatMessage({ title: 'example', description: 'ni' })
  123. * Facade so we can hide provider specific methods
  124. * @param {string} channel
  125. * @param {ChatMessage} message
  126. * @return {object} timestamp
  127. */
  128. async publish(channel, message) {
  129. return _providerMethods.publish({
  130. channel,
  131. message: new ChatMessage(message),
  132. })
  133. }
  134. /**
  135. * Subscribe to a channels
  136. * Facade so we can hide provider specific methods
  137. * @param {array} channels grouping name
  138. */
  139. subscribe({ channels }) {
  140. _providerMethods.subscribe({ channels })
  141. }
  142. /**
  143. * Listen to events and set callbacks
  144. * Facade so we can hide provider specific methods
  145. */
  146. _listenFor({ listeners }) {
  147. _providerMethods.listen(listeners)
  148. }
  149. /**
  150. * Get all groupings for this profile and
  151. * then store them as subscriptions
  152. */
  153. async _setupAllChannels(groupings) {
  154. groupings.forEach(grouping => {
  155. this._subscriptions.push(grouping.grouping_name)
  156. })
  157. }
  158. stop() {
  159. this._subscriptions = [MAIN_CHANNEL]
  160. console.warn('chatter stop not implemented')
  161. }
  162. }
  163. export { Chatter, MAIN_CHANNEL }