From fa7868675d0952f8e4e1aa2f6b77586bb56de2c1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 24 Feb 2016 12:57:29 +0100 Subject: Send Salmon interactions --- app/services/base_service.rb | 3 +++ app/services/fetch_entry_service.rb | 16 +++++++++++++++ app/services/fetch_feed_service.rb | 6 ++++-- app/services/follow_remote_account_service.rb | 10 ++++++--- app/services/follow_service.rb | 17 +++++++++++++--- app/services/process_feed_service.rb | 9 +++++---- app/services/process_interaction_service.rb | 13 ++++++------ app/services/send_interaction_service.rb | 29 +++++++++++++++++++++++++++ app/services/setup_local_account_service.rb | 6 +++++- app/services/unfollow_service.rb | 15 ++++++++++++++ 10 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 app/services/base_service.rb create mode 100644 app/services/fetch_entry_service.rb create mode 100644 app/services/send_interaction_service.rb create mode 100644 app/services/unfollow_service.rb (limited to 'app/services') diff --git a/app/services/base_service.rb b/app/services/base_service.rb new file mode 100644 index 000000000..0816b3503 --- /dev/null +++ b/app/services/base_service.rb @@ -0,0 +1,3 @@ +class BaseService + include ApplicationHelper +end diff --git a/app/services/fetch_entry_service.rb b/app/services/fetch_entry_service.rb new file mode 100644 index 000000000..c4a5460e9 --- /dev/null +++ b/app/services/fetch_entry_service.rb @@ -0,0 +1,16 @@ +class FetchEntryService < BaseService + # Knowing nothing but the URL of a remote status, create a local representation of it and return it + # @param [String] url Atom URL + # @return [Status] + def call(url) + body = http_client.get(url) + xml = Nokogiri::XML(body) + # todo + end + + private + + def http_client + HTTP + end +end diff --git a/app/services/fetch_feed_service.rb b/app/services/fetch_feed_service.rb index 059d65925..f18e9fc06 100644 --- a/app/services/fetch_feed_service.rb +++ b/app/services/fetch_feed_service.rb @@ -1,4 +1,6 @@ -class FetchFeedService +class FetchFeedService < BaseService + # Fetch an account's feed and process it + # @param [Account] account def call(account) process_service.(http_client.get(account.remote_url), account) end @@ -6,7 +8,7 @@ class FetchFeedService private def process_service - ProcessFeedService.new + @process_service ||= ProcessFeedService.new end def http_client diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb index bb55362a6..de2ca6e75 100644 --- a/app/services/follow_remote_account_service.rb +++ b/app/services/follow_remote_account_service.rb @@ -1,6 +1,10 @@ -class FollowRemoteAccountService - include ApplicationHelper - +class FollowRemoteAccountService < BaseService + # Find or create a local account for a remote user. + # When creating, look up the user's webfinger and fetch all + # important information from their feed + # @param [String] uri User URI in the form of username@domain + # @param [Boolean] subscribe Whether to initiate a PubSubHubbub subscription + # @return [Account] def call(uri, subscribe = true) username, domain = uri.split('@') account = Account.where(username: username, domain: domain).first diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index ea868b544..623d52b74 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -1,12 +1,23 @@ -class FollowService +class FollowService < BaseService + # Follow a remote user, notify remote user about the follow + # @param [Account] source_account From which to follow + # @param [String] uri User URI to follow in the form of username@domain def call(source_account, uri) target_account = follow_remote_account_service.(uri) - source_account.follow!(target_account) unless target_account.nil? + + return if target_account.nil? + + follow = source_account.follow!(target_account) + send_interaction_service.(follow.stream_entry, target_account) end private def follow_remote_account_service - FollowRemoteAccountService.new + @follow_remote_account_service ||= FollowRemoteAccountService.new + end + + def send_interaction_service + @send_interaction_service ||= SendInteractionService.new end end diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb index b7952035b..1aaf85d94 100644 --- a/app/services/process_feed_service.rb +++ b/app/services/process_feed_service.rb @@ -1,6 +1,7 @@ -class ProcessFeedService - include ApplicationHelper - +class ProcessFeedService < BaseService + # Create local statuses from an Atom feed + # @param [String] body Atom feed + # @param [Account] account Account this feed belongs to def call(body, account) xml = Nokogiri::XML(body) @@ -105,6 +106,6 @@ class ProcessFeedService end def follow_remote_account_service - FollowRemoteAccountService.new + @follow_remote_account_service ||= FollowRemoteAccountService.new end end diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb index ee04f01af..3a8332118 100644 --- a/app/services/process_interaction_service.rb +++ b/app/services/process_interaction_service.rb @@ -1,6 +1,7 @@ -class ProcessInteractionService - include ApplicationHelper - +class ProcessInteractionService < BaseService + # Record locally the remote interaction with our user + # @param [String] envelope Salmon envelope + # @param [Account] target_account Account the Salmon was addressed to def call(envelope, target_account) body = salmon.unpack(envelope) xml = Nokogiri::XML(body) @@ -75,14 +76,14 @@ class ProcessInteractionService end def salmon - OStatus2::Salmon.new + @salmon ||= OStatus2::Salmon.new end def follow_remote_account_service - FollowRemoteAccountService.new + @follow_remote_account_service ||= FollowRemoteAccountService.new end def process_feed_service - ProcessFeedService.new + @process_feed_service ||= ProcessFeedService.new end end diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb new file mode 100644 index 000000000..42b273ed6 --- /dev/null +++ b/app/services/send_interaction_service.rb @@ -0,0 +1,29 @@ +class SendInteractionService < BaseService + include AtomHelper + + # Send an Atom representation of an interaction to a remote Salmon endpoint + # @param [StreamEntry] stream_entry + # @param [Account] target_account + def call(stream_entry, target_account) + envelope = salmon.pack(entry_xml(stream_entry), target_account.keypair) + salmon.post(target_account.salmon_url, envelope) + end + + private + + def entry_xml(stream_entry) + Nokogiri::XML::Builder.new do |xml| + entry(xml, true) do + author(xml) do + include_author xml, stream_entry.account + end + + include_entry xml, stream_entry + end + end.to_xml + end + + def salmon + @salmon ||= OStatus2::Salmon.new + end +end diff --git a/app/services/setup_local_account_service.rb b/app/services/setup_local_account_service.rb index c40e51855..a5ef68996 100644 --- a/app/services/setup_local_account_service.rb +++ b/app/services/setup_local_account_service.rb @@ -1,4 +1,8 @@ -class SetupLocalAccountService +class SetupLocalAccountService < BaseService + # Setup an account for a new user instance by generating + # an RSA key pair and a profile + # @param [User] user Unsaved user instance + # @param [String] username def call(user, username) user.build_account diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb new file mode 100644 index 000000000..039838d32 --- /dev/null +++ b/app/services/unfollow_service.rb @@ -0,0 +1,15 @@ +class UnfollowService < BaseService + # Unfollow and notify the remote user + # @param [Account] source_account Where to unfollow from + # @param [Account] target_account Which to unfollow + def call(source_account, target_account) + follow = source_account.unfollow!(target_account) + send_interaction_service.(follow.stream_entry, target_account) unless target_account.local? + end + + private + + def send_interaction_service + @send_interaction_service ||= SendInteractionService.new + end +end -- cgit