闭社主体 forked from https://github.com/tootsuite/mastodon
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.

158 lines
4.6 KiB

  1. // @ts-check
  2. import { connectStream } from '../stream';
  3. import {
  4. updateTimeline,
  5. deleteFromTimelines,
  6. expandHomeTimeline,
  7. connectTimeline,
  8. disconnectTimeline,
  9. } from './timelines';
  10. import { updateNotifications, expandNotifications } from './notifications';
  11. import { updateConversations } from './conversations';
  12. import {
  13. fetchAnnouncements,
  14. updateAnnouncements,
  15. updateReaction as updateAnnouncementsReaction,
  16. deleteAnnouncement,
  17. } from './announcements';
  18. import { fetchFilters } from './filters';
  19. import { getLocale } from '../locales';
  20. const { messages } = getLocale();
  21. /**
  22. * @param {number} max
  23. * @return {number}
  24. */
  25. const randomUpTo = max =>
  26. Math.floor(Math.random() * Math.floor(max));
  27. /**
  28. * @param {string} timelineId
  29. * @param {string} channelName
  30. * @param {Object.<string, string>} params
  31. * @param {Object} options
  32. * @param {function(Function, Function): void} [options.fallback]
  33. * @param {function(object): boolean} [options.accept]
  34. * @return {function(): void}
  35. */
  36. export const connectTimelineStream = (timelineId, channelName, params = {}, options = {}) =>
  37. connectStream(channelName, params, (dispatch, getState) => {
  38. const locale = getState().getIn(['meta', 'locale']);
  39. let pollingId;
  40. /**
  41. * @param {function(Function, Function): void} fallback
  42. */
  43. const useFallback = fallback => {
  44. fallback(dispatch, () => {
  45. pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
  46. });
  47. };
  48. return {
  49. onConnect() {
  50. dispatch(connectTimeline(timelineId));
  51. if (pollingId) {
  52. clearTimeout(pollingId);
  53. pollingId = null;
  54. }
  55. },
  56. onDisconnect() {
  57. dispatch(disconnectTimeline(timelineId));
  58. if (options.fallback) {
  59. pollingId = setTimeout(() => useFallback(options.fallback), randomUpTo(40000));
  60. }
  61. },
  62. onReceive (data) {
  63. switch(data.event) {
  64. case 'update':
  65. dispatch(updateTimeline(timelineId, JSON.parse(data.payload), options.accept));
  66. break;
  67. case 'delete':
  68. dispatch(deleteFromTimelines(data.payload));
  69. break;
  70. case 'notification':
  71. dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
  72. break;
  73. case 'conversation':
  74. dispatch(updateConversations(JSON.parse(data.payload)));
  75. break;
  76. case 'filters_changed':
  77. dispatch(fetchFilters());
  78. break;
  79. case 'announcement':
  80. dispatch(updateAnnouncements(JSON.parse(data.payload)));
  81. break;
  82. case 'announcement.reaction':
  83. dispatch(updateAnnouncementsReaction(JSON.parse(data.payload)));
  84. break;
  85. case 'announcement.delete':
  86. dispatch(deleteAnnouncement(data.payload));
  87. break;
  88. }
  89. },
  90. };
  91. });
  92. /**
  93. * @param {Function} dispatch
  94. * @param {function(): void} done
  95. */
  96. const refreshHomeTimelineAndNotification = (dispatch, done) => {
  97. dispatch(expandHomeTimeline({}, () =>
  98. dispatch(expandNotifications({}, () =>
  99. dispatch(fetchAnnouncements(done))))));
  100. };
  101. /**
  102. * @return {function(): void}
  103. */
  104. export const connectUserStream = () =>
  105. connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification });
  106. /**
  107. * @param {Object} options
  108. * @param {boolean} [options.onlyMedia]
  109. * @return {function(): void}
  110. */
  111. export const connectCommunityStream = ({ onlyMedia } = {}) =>
  112. connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
  113. /**
  114. * @param {Object} options
  115. * @param {boolean} [options.onlyMedia]
  116. * @param {boolean} [options.onlyRemote]
  117. * @return {function(): void}
  118. */
  119. export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
  120. connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`);
  121. /**
  122. * @param {string} columnId
  123. * @param {string} tagName
  124. * @param {boolean} onlyLocal
  125. * @param {function(object): boolean} accept
  126. * @return {function(): void}
  127. */
  128. export const connectHashtagStream = (columnId, tagName, onlyLocal, accept) =>
  129. connectTimelineStream(`hashtag:${columnId}${onlyLocal ? ':local' : ''}`, `hashtag${onlyLocal ? ':local' : ''}`, { tag: tagName }, { accept });
  130. /**
  131. * @return {function(): void}
  132. */
  133. export const connectDirectStream = () =>
  134. connectTimelineStream('direct', 'direct');
  135. /**
  136. * @param {string} listId
  137. * @return {function(): void}
  138. */
  139. export const connectListStream = listId =>
  140. connectTimelineStream(`list:${listId}`, 'list', { list: listId });