Add streaming updates for profiles in web UI

This commit is contained in:
Eugen Rochko 2024-12-10 11:49:15 +01:00
parent 801cd731be
commit ede37ed835
4 changed files with 42 additions and 19 deletions

View file

@ -195,3 +195,10 @@ export const connectDirectStream = () =>
*/ */
export const connectListStream = listId => export const connectListStream = listId =>
connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) }); connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
/**
* @param {string} accountId
* @returns {function(): void}
*/
export const connectProfileStream = accountId =>
connectTimelineStream(`account:${accountId}`, 'profile', { account_id: accountId });

View file

@ -7,21 +7,20 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { lookupAccount, fetchAccount } from 'mastodon/actions/accounts';
import { fetchFeaturedTags } from 'mastodon/actions/featured_tags';
import { connectProfileStream } from 'mastodon/actions/streaming';
import { expandAccountFeaturedTimeline, expandAccountTimeline } from 'mastodon/actions/timelines';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import StatusList from 'mastodon/components/status_list';
import { TimelineHint } from 'mastodon/components/timeline_hint'; import { TimelineHint } from 'mastodon/components/timeline_hint';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
import { me } from 'mastodon/initial_state'; import Column from 'mastodon/features/ui/components/column';
import { normalizeForLookup } from 'mastodon/reducers/accounts_map'; import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
import { getAccountHidden } from 'mastodon/selectors'; import { getAccountHidden } from 'mastodon/selectors';
import { useAppSelector } from 'mastodon/store'; import { useAppSelector } from 'mastodon/store';
import { lookupAccount, fetchAccount } from '../../actions/accounts';
import { fetchFeaturedTags } from '../../actions/featured_tags';
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
import { ColumnBackButton } from '../../components/column_back_button';
import { LoadingIndicator } from '../../components/loading_indicator';
import StatusList from '../../components/status_list';
import Column from '../ui/components/column';
import { LimitedAccountHint } from './components/limited_account_hint'; import { LimitedAccountHint } from './components/limited_account_hint';
import HeaderContainer from './containers/header_container'; import HeaderContainer from './containers/header_container';
@ -114,9 +113,12 @@ class AccountTimeline extends ImmutablePureComponent {
dispatch(fetchFeaturedTags(accountId)); dispatch(fetchFeaturedTags(accountId));
dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); dispatch(expandAccountTimeline(accountId, { withReplies, tagged }));
if (accountId === me) { if (this.disconnect) {
dispatch(connectTimeline(`account:${me}`)); this.disconnect();
this.disconnect = null;
} }
this.disconnect = dispatch(connectProfileStream(accountId));
} }
componentDidMount () { componentDidMount () {
@ -142,17 +144,12 @@ class AccountTimeline extends ImmutablePureComponent {
} }
dispatch(expandAccountTimeline(accountId, { withReplies, tagged })); dispatch(expandAccountTimeline(accountId, { withReplies, tagged }));
} }
if (prevProps.accountId === me && accountId !== me) {
dispatch(disconnectTimeline({ timeline: `account:${me}` }));
}
} }
componentWillUnmount () { componentWillUnmount () {
const { dispatch, accountId } = this.props; if (this.disconnect) {
this.disconnect();
if (accountId === me) { this.disconnect = null;
dispatch(disconnectTimeline({ timeline: `account:${me}` }));
} }
} }

View file

@ -63,6 +63,7 @@ class FanOutOnWriteService < BaseService
def fan_out_to_public_streams! def fan_out_to_public_streams!
broadcast_to_hashtag_streams! broadcast_to_hashtag_streams!
broadcast_to_public_streams! broadcast_to_public_streams!
broadcast_to_profile_streams!
end end
def deliver_to_self! def deliver_to_self!
@ -145,6 +146,10 @@ class FanOutOnWriteService < BaseService
end end
end end
def broadcast_to_profile_streams!
redis.publish("timeline:profile:#{@status.account_id}:public", anonymous_payload)
end
def deliver_to_conversation! def deliver_to_conversation!
AccountConversation.add_status(@account, @status) unless update? AccountConversation.add_status(@account, @status) unless update?
end end

View file

@ -420,6 +420,8 @@ const startServer = async () => {
return 'direct'; return 'direct';
case '/api/v1/streaming/list': case '/api/v1/streaming/list':
return 'list'; return 'list';
case '/api/v1/streaming/profile':
return 'profile';
default: default:
return undefined; return undefined;
} }
@ -972,6 +974,7 @@ const startServer = async () => {
* @property {string} [tag] * @property {string} [tag]
* @property {string} [list] * @property {string} [list]
* @property {string} [only_media] * @property {string} [only_media]
* @property {string} [account_id]
*/ */
/** /**
@ -1096,6 +1099,17 @@ const startServer = async () => {
reject(new AuthenticationError('Not authorized to stream this list')); reject(new AuthenticationError('Not authorized to stream this list'));
}); });
break;
case 'profile':
if (!params.account_id) {
reject(new RequestError('Missing account id parameter'));
return;
}
resolve({
channelIds: [`timeline:profile:${params.account_id}:public`],
options: { needsFiltering: true },
});
break; break;
default: default:
reject(new RequestError('Unknown stream type')); reject(new RequestError('Unknown stream type'));