module Sinbotra::Messenger module Handler def self.included(base) ensure_repos_connected base.extend ClassMethods end def self.ensure_repos_connected Sinbotra::Bot::ConversationRepo.connect Sinbotra::Bot::UserRepo.connect end module ClassMethods GET_STARTED_ID = "GET_STARTED" def handle_message(msg) user = Sinbotra::Messenger::User.load(msg) bot = Sinbotra::Messenger::Bot.new(user) # Next step in conversation # or match the `#hear` # or get default fallback if user.in_conversation? convo = user.current_conversation convo.perform_current_step(bot) elsif intent = match_intent(bot) intent.callback.(bot) unless intent.nil? else intent = default_intent intent.callback.(bot) unless intent.nil? end end def enable_get_started! @client = MessengerClient::Client.new(ENV.fetch("FACEBOOK_PAGE_TOKEN")) @client.get_started(GET_STARTED_ID) end def get_started(&blk) postback(GET_STARTED_ID, &blk) end def conversation(id, &blk) c = Sinbotra::Bot::Conversation.new(id) Sinbotra::Bot::ConversationRepo.create(id, c) yield c end Listener = Struct.new(:matcher, :callback) do def default?; false end end DefaultListener = Struct.new(:callback) do def default?; true end end Postback = Struct.new(:matcher, :callback) def postback(matcher, &blk) # TODO: THis feels kinda wrong @postbacks ||= [] @postbacks << Postback.new(matcher, blk) end def hear(matcher=nil, &blk) # TODO: THis feels kinda wrong @listeners ||= [] if matcher.nil? return @listeners << DefaultListener.new(blk) end @listeners << Listener.new(matcher, blk) end def action(name, &blk) @actions ||= {} @actions[name] = blk end def get_intent(text) puts "NOOP get_intent" nil end def yes?(str) str =~ yes_matcher end def typing(delay=1) puts "NOOP show typing for #{delay} seconds" end def next_dont_understand_phrase puts "NOOP next_dont_understand_phrase" end private def yes_matcher /^(yes|yeah|ya|ok)/i end def default_intent @listeners.find(&:default?) end def match_intent(bot) msg = bot.current_message # look for postback postback = msg.postback found_pb = @postbacks.find { |pb| postback.match(pb.matcher) } return found_pb unless found_pb.nil? # if you couldn't find a postback, look for text txt = msg.text @listeners.find { |l| !l.default? && txt.match(l.matcher) } end end end end