AltonV/autoremote

View on GitHub
lib/autoremote.rb

Summary

Maintainability
A
45 mins
Test Coverage
require 'autoremote/net'
require 'autoremote/version'
require 'autoremote/exceptions'
require 'sqlite3'
require 'active_record'
require 'socket'

## Establish the database connection
ActiveRecord::Base.establish_connection(
    :adapter  => 'sqlite3',
    :database => ENV['HOME'] + '/.autoremote/devices.db'
)

class Device < ActiveRecord::Base
end

## Create the database table
ActiveRecord::Schema.define do
    break if ActiveRecord::Base.connection.table_exists? 'devices'
    create_table :devices do |table|
        table.column :name, :string
        table.column :key, :string
    end
end

module AutoRemote
    # Add a device
    # @param name [String] The name of the device
    # @param input [String] Can either be the 'goo.gl' url or the personal key of the device
    # @raise [AutoRemote::InvalidKey] if the key or url is invalid
    # @return [Device] the device that was was created
    # @return [nil] if the device already exists
    def AutoRemote::add_device(name, input)
        
        ## Validation if input is a 'goo.gl' url
        if input.match(/^(https?:\/{2})?(goo.gl\/[\S]*)$/i)
            result = AutoRemoteRequest.validate_url(input)
            
            ## Get the key from the resulting url
            begin
                input = CGI.parse(result.request.last_uri.query)['key'][0]
            rescue
                raise self::InvalidKey
            end
            
        ## If not a 'goo.gl' url, check if it is a valid key
        else
            ## Validate key
            result = AutoRemoteRequest.validate_key(input)
            
            ## Check result
            raise self::InvalidKey if result.body != 'OK'
        end
        
        ## Check if the device already exist
        if Device.find_by_name(name)
            return nil
        else
            ## Save the device
            return Device.create(:name => name, :key => input)
        end
    end
    
    # Remove a specific device
    # @param name [String] The name of the device
    # @return [true] if the device was deleted
    # @return [false] if the device wasn't found
    def AutoRemote::remove_device(name)
        if device = Device.find_by_name(name)
            ## Remove the device
            Device.delete(device.id)
            return true
        else
            return false
        end
    end
    
    # Returns a list with all devices
    # @return [Device::ActiveRecord_Relation]
    def AutoRemote::list_devices
        return Device.order('name').all
    end
    
    # Returns one specific device
    # @return [Device] if the device was found
    # @return [nil] if the device wasn't found
    def AutoRemote::get_device(name)
        return Device.find_by_name(name)
    end
    
    # Sends a message to a device
    # @param device [Device, String] A device object or the name of the device
    # @param message [String] The message to send
    # @raise [ArgumentError] if message isn't a string
    # @return [true] if the message was sent
    # @return [false] if the message wasn't sent
    def AutoRemote::send_message(device, message)
        device = self.validate_device(device)
        
        if !device
            return false
        elsif ! message.is_a?(String)
            raise ArgumentError, 'Message must be a string'
        end
        
        ## Send the message
        result = AutoRemoteRequest.message(device.key, `hostname`.strip, CGI.escape(message))
        
        ## Check result
        if result.body == 'OK'
            return true
        else
            return false
        end
    end
    
    # Register on the device
    # @param device [Device, String] A device object or the name of the device
    # @param remotehost [String] The public hostname or ip-address
    # @raise [ArgumentError] if message isn't a string or less than 5 characters
    # @return [true] if the registration was successful
    # @return [false] if the registration failed
    def AutoRemote::register_on_device(device, remotehost)
        device = self.validate_device(device)
        
        if !device
            return false
        elsif ! remotehost.is_a?(String) || remotehost.length < 5
            raise ArgumentError, 'remotehost must be a string of 5 chars or more'
        end
        
        hostname = `hostname`.strip
        ipAddress = AutoRemote::get_ip_address.ip_address
        
        ## Perform the registration
        result = AutoRemoteRequest.register(device.key, hostname, hostname, remotehost, ipAddress)
        
        ## Check result
        if result.body == 'OK'
            return true
        else
            return false
        end
    end
    
    ## Define alases for some methods
    class << AutoRemote
        # Add
        alias :addDevice :add_device
        alias :saveDevice :add_device
        alias :save_device :add_device
        # Remove
        alias :removeDevice :remove_device
        alias :deleteDevice :remove_device
        alias :delete_device :remove_device
        # List
        alias :listDevices :list_devices
        # Get
        alias :getDevice :get_device
        # Message
        alias :sendMessage :send_message
        alias :sendMsg :send_message
        alias :send_msg :send_message
        # Register
        alias :registerOnDevice :register_on_device
        alias :regOnDevice :register_on_device
        alias :reg_on_device :register_on_device
    end
    
    private
    # Validates device
    # @param input the input to validate
    # @return [Device] if the input is valid
    # @return [nil] if the input is not valid
    def AutoRemote::validate_device(input)
        if input.is_a?(Device)
            return input
        else
            device = Device.find_by_name(input)
            if device.kind_of?(Device)
                return device
            else
                return nil
            end
        end
    end
    
    # Gets the ip address of the system
    # @return [String]
    def AutoRemote::get_ip_address
        return Socket.ip_address_list.detect { |ipInfo| ipInfo.ipv4_private? }
    end
end