Class: ChatSDK::X::Adapter
- Inherits:
-
Adapter::Base
- Object
- Adapter::Base
- ChatSDK::X::Adapter
- Includes:
- Adapter::MediaTypes
- Defined in:
- lib/chat_sdk/x/adapter.rb
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
Instance Method Summary collapse
- #ack_response(rack_request) ⇒ Object
-
#add_reaction(channel_id:, message_id:, emoji:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument.
-
#delete_message(channel_id:, message_id:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument.
-
#fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument.
- #get_user(user_id) ⇒ Object
-
#initialize(access_token: nil, consumer_secret: nil, user_id: nil) ⇒ Adapter
constructor
A new instance of Adapter.
- #mention(user_id) ⇒ Object
- #name ⇒ Object
- #open_dm(user_id) ⇒ Object
- #parse_events(rack_request) ⇒ Object
-
#post_message(channel_id:, message:, thread_id: nil) ⇒ Object
Outbound.
-
#remove_reaction(channel_id:, message_id:, emoji:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument.
- #render(postable_message) ⇒ Object
-
#upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument.
-
#verify_request!(rack_request) ⇒ Object
Inbound.
Constructor Details
#initialize(access_token: nil, consumer_secret: nil, user_id: nil) ⇒ Adapter
Returns a new instance of Adapter.
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/chat_sdk/x/adapter.rb', line 16 def initialize(access_token: nil, consumer_secret: nil, user_id: nil) @access_token = access_token || ENV["X_ACCESS_TOKEN"] @consumer_secret = consumer_secret || ENV["X_CONSUMER_SECRET"] @user_id = user_id || ENV["X_USER_ID"] raise ChatSDK::ConfigurationError, "X access_token required" unless @access_token raise ChatSDK::ConfigurationError, "X consumer_secret required" unless @consumer_secret @client = ApiClient.new(@access_token) end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
14 15 16 |
# File 'lib/chat_sdk/x/adapter.rb', line 14 def client @client end |
Instance Method Details
#ack_response(rack_request) ⇒ Object
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/chat_sdk/x/adapter.rb', line 51 def ack_response(rack_request) return nil unless rack_request.get? crc_token = rack_request.params["crc_token"] return nil unless crc_token response_token = "sha256=#{Base64.strict_encode64(OpenSSL::HMAC.digest("SHA256", @consumer_secret, crc_token))}" [200, {"content-type" => "application/json"}, [JSON.generate({"response_token" => response_token})]] end |
#add_reaction(channel_id:, message_id:, emoji:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument
138 139 140 |
# File 'lib/chat_sdk/x/adapter.rb', line 138 def add_reaction(channel_id:, message_id:, emoji:) # rubocop:disable Lint/UnusedMethodArgument @client.like_tweet(user_id: @user_id, tweet_id: ) end |
#delete_message(channel_id:, message_id:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument
105 106 107 |
# File 'lib/chat_sdk/x/adapter.rb', line 105 def (channel_id:, message_id:) # rubocop:disable Lint/UnusedMethodArgument @client.delete_tweet(tweet_id: ) end |
#fetch_messages(channel_id:, thread_id: nil, cursor: nil, limit: 50) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/chat_sdk/x/adapter.rb', line 109 def (channel_id:, thread_id: nil, cursor: nil, limit: 50) # rubocop:disable Lint/UnusedMethodArgument if thread_id&.start_with?("x:dm:") participant_id = thread_id.delete_prefix("x:dm:") result = @client.get_dm_events(participant_id: participant_id, cursor: cursor, limit: limit) data = result["data"] || [] = data.map do |dm| ChatSDK::Message.new( id: dm["id"]&.to_s, text: dm["text"] || "", author: ChatSDK::Author.new( id: dm["sender_id"] || "unknown", name: dm["sender_id"] || "unknown", platform: :x, bot: false ), thread_id: thread_id, channel_id: channel_id, platform: :x, raw: dm ) end next_cursor = result.dig("meta", "next_token") [, next_cursor] else # X does not provide a robust thread-fetching API for tweets [[], nil] end end |
#get_user(user_id) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/chat_sdk/x/adapter.rb', line 146 def get_user(user_id) data = @client.get_user(user_id) return nil unless data&.dig("data", "id") ChatSDK::Author.new( id: data.dig("data", "id"), name: data.dig("data", "username"), platform: :x, bot: false, raw: data ) end |
#mention(user_id) ⇒ Object
163 164 165 |
# File 'lib/chat_sdk/x/adapter.rb', line 163 def mention(user_id) "@#{user_id}" end |
#name ⇒ Object
27 28 29 |
# File 'lib/chat_sdk/x/adapter.rb', line 27 def name :x end |
#open_dm(user_id) ⇒ Object
159 160 161 |
# File 'lib/chat_sdk/x/adapter.rb', line 159 def open_dm(user_id) user_id end |
#parse_events(rack_request) ⇒ Object
62 63 64 65 66 67 |
# File 'lib/chat_sdk/x/adapter.rb', line 62 def parse_events(rack_request) payload = read_json_body(rack_request) EventParser.parse(payload, bot_user_id: @user_id) rescue JSON::ParserError [] end |
#post_message(channel_id:, message:, thread_id: nil) ⇒ Object
Outbound
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/chat_sdk/x/adapter.rb', line 70 def (channel_id:, message:, thread_id: nil) msg = ChatSDK::PostableMessage.from() text = msg.text || msg.card&.fallback_text || "" if thread_id&.start_with?("x:dm:") result = @client.send_dm(participant_id: channel_id, text: text) = result.dig("dm_event", "id") || result["id"] ChatSDK::Message.new( id: , text: text, author: ChatSDK::Author.new(id: @user_id || "bot", name: "bot", platform: :x, bot: true), thread_id: thread_id, channel_id: channel_id, platform: :x, raw: result ) else reply_to = (channel_id if channel_id && thread_id) result = @client.create_tweet(text: text, reply_to: reply_to) (result, channel_id, thread_id: thread_id) end end |
#remove_reaction(channel_id:, message_id:, emoji:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument
142 143 144 |
# File 'lib/chat_sdk/x/adapter.rb', line 142 def remove_reaction(channel_id:, message_id:, emoji:) # rubocop:disable Lint/UnusedMethodArgument @client.unlike_tweet(user_id: @user_id, tweet_id: ) end |
#render(postable_message) ⇒ Object
167 168 169 |
# File 'lib/chat_sdk/x/adapter.rb', line 167 def render() .text end |
#upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/chat_sdk/x/adapter.rb', line 94 def upload_file(channel_id:, io:, filename:, thread_id: nil, comment: nil) # rubocop:disable Lint/UnusedMethodArgument content_type = detect_content_type(filename) bytes = io.respond_to?(:size) ? io.size : io.read.bytesize.tap { io.rewind } media_id = @client.upload_media(io: io, content_type: content_type, total_bytes: bytes) text = comment || "" result = @client.create_tweet(text: text, media_ids: [media_id]) (result, channel_id) end |
#verify_request!(rack_request) ⇒ Object
Inbound
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/chat_sdk/x/adapter.rb', line 32 def verify_request!(rack_request) body = rack_request.body.read rack_request.body.rewind signature = rack_request.get_header("HTTP_X_TWITTER_WEBHOOKS_SIGNATURE") unless signature raise ChatSDK::SignatureVerificationError, "Missing X signature header" end expected = "sha256=#{Base64.strict_encode64(OpenSSL::HMAC.digest("SHA256", @consumer_secret, body))}" unless Rack::Utils.secure_compare(signature, expected) raise ChatSDK::SignatureVerificationError, "Invalid X signature" end true end |