svoop/rodbot

View on GitHub
lib/rodbot/plugins/slack/relay.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'slack-ruby-client'

using Rodbot::Refinements

module Rodbot
  class Plugins
    class Slack
      class Relay < Rodbot::Relay
        include Rodbot::Memoize

        def loops
          ::Slack.configure do |config|
            config.token = access_token
          end
          [method(:read_loop), method(:write_loop)]
        end

        private

        def access_token
          Rodbot.config(:plugin, :slack, :access_token)
        rescue => error
          raise Rodbot::PluginError.new("invalid access_token", error.message)
        end

        memoize def client
          ::Slack::RealTime::Client.new
        end

        def channel_id
          Rodbot.config(:plugin, :slack, :channel_id)
        rescue => error
          raise Rodbot::PluginError.new("invalid channel_id", error.message)
        end

        def write_loop
          server = TCPServer.new(*bind)
          loop do
            Thread.start(server.accept) do |remote|
              message = Rodbot::Message.new(remote.gets("\x04").chop)
              remote.close
              client.web_client.chat_postMessage(
                channel: message.room || channel_id,
                text: md_to_slack_text(message.text.psub(placeholders)),
                as_user: true
              )
            end
          end
        end

        def read_loop
          client.on :message do |message|
            on_message(message) if message.channel == channel_id
          end
          client.start!
        end

        def on_message(message)
          if message.text.start_with?('!')
            client.web_client.chat_postMessage(
              channel: message.channel,
              text: reply_to(message),
              as_user: true
            )
          end
        end

        def reply_to(message)
          command(*message.text[1..].split(/\s+/, 2)).
            psub(placeholders(sender: message.user)).
            then { md_to_slack_text(_1) }
        end

        # @see https://api.slack.com/reference/surfaces/formatting
        def placeholders(locals={})
          {
            sender: ("<@#{locals[:sender]}>" if locals[:sender]),
            everybody: "<!channel>"
          }
        end

        # @see https://api.slack.com/reference/surfaces/formatting
        def md_to_slack_text(md)
          md.
            gsub(/\[(.+?)\]\((.+?)\)/, '<\2|\1>').   # convert links
            gsub(/^\s*[*-]\s+/, '• ')                # convert bullet lists
        end

      end
    end
  end
end