Sharparam/chatrix

View on GitHub
lib/chatrix/components/state.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: utf-8
# frozen_string_literal: true

require 'chatrix/events'

require 'chatrix/components/permissions'

require 'set'
require 'wisper'

module Chatrix
  module Components
    # Manages state for a room.
    class State
      include Wisper::Publisher

      # @return [String,nil] The canonical alias, or `nil` if none has
      #   been set.
      attr_reader :canonical_alias

      # @return [String,nil] The name, or `nil` if none has been set.
      attr_reader :name

      # @return [String,nil] The topic, or `nil` if none has been set.
      attr_reader :topic

      # @return [User] The user who created the room.
      attr_reader :creator

      # @return [Boolean] `true` if guests are allowed in the room,
      #   otherwise `false`.
      attr_reader :guest_access

      # @return [String] Join rules for the room.
      attr_reader :join_rule

      # @return [String] The room's history visibility.
      attr_reader :history_visibility

      # @return [Permissions] Check room permissions.
      attr_reader :permissions

      # Initializes a new State instance.
      #
      # @param room [Room] The room the state belongs to.
      # @param users [Users] The user manager.
      def initialize(room, users)
        @room = room
        @users = users

        @permissions = Permissions.new @room

        @aliases = []
        @members = Set.new
      end

      # Returns whether the specified user is a member of the room.
      #
      # @param user [User] The user to check.
      # @return [Boolean] `true` if the user is a member of the room,
      #   otherwise `false`.
      def member?(user)
        @members.member? user
      end

      # Updates the state with new event data.
      # @param data [Hash] Event data.
      def update(data)
        data['events'].each { |e| process_event e } if data.key? 'events'
      end

      private

      # Processes a state event.
      # @param event [Hash] Event data.
      def process_event(event)
        return if Events.processed? event

        name = 'handle_' + event['type'].match(/\w+$/).to_s
        send(name, event) if respond_to? name, true

        Events.processed event
      end

      # Handle the `m.room.create` event.
      # @param event [Hash] Event data.
      def handle_create(event)
        @creator = @users.send(:get_user, event['content']['creator'])
        broadcast :creator, @room, @creator
      end

      # Handle the `m.room.canonical_alias` event.
      # @param (see #handle_create)
      def handle_canonical_alias(event)
        @canonical_alias = event['content']['alias']
        broadcast :canonical_alias, @room, @canonical_alias
      end

      # Handle the `m.room.aliases` event.
      # @param (see #handle_create)
      def handle_aliases(event)
        @aliases.replace event['content']['aliases']
        broadcast :aliases, @room, @aliases
      end

      # Handle the `m.room.name` event.
      # @param (see #handle_create)
      def handle_name(event)
        broadcast :name, @room, @name = event['content']['name']
      end

      # Handle the `m.room.topic` event.
      # @param (see #handle_create)
      def handle_topic(event)
        broadcast :topic, @room, @topic = event['content']['topic']
      end

      # Handle the `m.room.guest_access` event.
      # @param (see #handle_create)
      def handle_guest_access(event)
        @guest_access = event['content']['guest_access'] == 'can_join'
        broadcast :guest_access, @room, @guest_access
      end

      # Handle the `m.room.history_visibility` event.
      # @param (see #handle_create)
      def handle_history_visibility(event)
        @history_visibility = event['content']['history_visibility']
        broadcast :history_visibility, @room, @history_visibility
      end

      # Handle the `m.room.join_rules` event.
      # @param (see #handle_create)
      def handle_join_rules(event)
        @join_rule = event['content']['join_rule']
        broadcast :join_rule, @room, @join_rule
      end

      # Process a member event.
      # @param event [Hash] The member event.
      def handle_member(event)
        @users.process_member_event self, event
        user = @users[event['state_key']]
        membership = event['content']['membership'].to_sym

        # Don't process invite state change if the user is already a
        # member in the room.
        return if membership == :invite && member?(user)

        if membership == :join
          @members.add user
        else
          @members.delete user
        end

        broadcast(membership, @room, user)
      end

      # Process a power level event.
      # @param event [Hash] Event data.
      def handle_power_levels(event)
        content = event['content']
        @permissions.update content
        @users.process_power_levels @room, content['users']
      end
    end
  end
end