class ReactiveRecord::Broadcast

Attributes

record[R]

private

Public Class Methods

after_commit(operation, model) click to toggle source
# File lib/reactive_record/broadcast.rb, line 4
def self.after_commit(operation, model)
  Hyperloop::InternalPolicy.regulate_broadcast(model) do |data|
    if !Hyperloop.on_server? && Hyperloop::Connection.root_path
      send_to_server(operation, data)
    else
      SendPacket.run(data, operation: operation)
    end
  end
rescue ActiveRecord::StatementInvalid => e
  raise e unless e.message == "Could not find table 'hyperloop_connections'"
end
in_transit() click to toggle source
# File lib/reactive_record/broadcast.rb, line 123
def self.in_transit
  @in_transit ||= Hash.new { |h, k| h[k] = new(k) }
end
new(id) click to toggle source
# File lib/reactive_record/broadcast.rb, line 127
def initialize(id)
  @id = id
  @received = Set.new
  @record = {}
  @previous_changes = {}
end
open_channels() click to toggle source
# File lib/reactive_record/broadcast.rb, line 119
def self.open_channels
  @open_channels ||= Set.new
end
send_to_server(operation, data) click to toggle source
# File lib/reactive_record/broadcast.rb, line 16
def self.send_to_server(operation, data)
  salt = SecureRandom.hex
  authorization = Hyperloop.authorization(salt, data[:channel], data[:broadcast_id])
  raise 'no server running' unless Hyperloop::Connection.root_path
  SendPacket.remote(
    Hyperloop::Connection.root_path,
    data,
    operation: operation,
    salt: salt,
    authorization: authorization
  )
end
to_self(record, data = {}) click to toggle source
# File lib/reactive_record/broadcast.rb, line 64
def self.to_self(record, data = {})
  # simulate incoming packet after a local save
  operation = if record.new?
                :create
              elsif record.destroyed?
                :destroy
              else
                :change
              end
  dummy_broadcast = new.local(operation, record, data)
  record.backing_record.sync! data unless operation == :destroy
  ReactiveRecord::Collection.sync_scopes dummy_broadcast
end

Public Instance Methods

complete!() click to toggle source
# File lib/reactive_record/broadcast.rb, line 164
def complete!
  self.class.in_transit.delete @id
end
destroyed?() click to toggle source
# File lib/reactive_record/broadcast.rb, line 103
def destroyed?
  @destroyed
end
klass() click to toggle source
# File lib/reactive_record/broadcast.rb, line 107
def klass
  Object.const_get(@klass)
end
local(operation, record, data) click to toggle source
# File lib/reactive_record/broadcast.rb, line 134
def local(operation, record, data)
  @destroyed = operation == :destroy
  @is_new = operation == :create
  @klass = record.class.name
  @record = data
  record.backing_record.destroyed = false
  @record.merge!(id: record.id) if record.id
  record.backing_record.destroyed = @destroyed
  @backing_record = record.backing_record
  attributes = record.backing_record.attributes
  data.each do |k, v|
    next if klass.reflect_on_association(k) || attributes[k] == v
    @previous_changes[k] = [attributes[k], v]
  end
  self
end
merge_current_values(br) click to toggle source
# File lib/reactive_record/broadcast.rb, line 168
def merge_current_values(br)
  current_values = Hash[*@previous_changes.collect do |attr, values|
    value = attr == :id ? record[:id] : values.first
    if br.attributes.key?(attr) &&
       br.attributes[attr] != br.convert(attr, value) &&
       br.attributes[attr] != br.convert(attr, values.last)
      puts "warning #{attr} has changed locally - will force a reload.\n"\
           "local value: #{br.attributes[attr]} remote value: #{br.convert(attr, value)}->#{br.convert(attr, values.last)}"
      return nil
    end
    [attr, value]
  end.compact.flatten].merge(br.attributes)
  klass._react_param_conversion(current_values)
end
new?() click to toggle source
# File lib/reactive_record/broadcast.rb, line 99
def new?
  @is_new
end
receive(params) { |complete!| ... } click to toggle source
# File lib/reactive_record/broadcast.rb, line 151
def receive(params)
  @destroyed = params.operation == :destroy
  @is_new = params.operation == :create
  @channels ||= Hyperloop::IncomingBroadcast.open_channels.intersection params.channels
  #raise 'synchromesh security violation' unless @channels.include? params.channels
  @received << params.channel
  @klass ||= params.klass
  @record.merge! params.record
  @previous_changes.merge! params.previous_changes
  @backing_record = ReactiveRecord::Base.exists?(klass, params.record[:id])
  yield complete! if @channels == @received
end
record_with_current_values() click to toggle source
# File lib/reactive_record/broadcast.rb, line 78
def record_with_current_values
  ReactiveRecord::Base.load_data do
    backing_record = @backing_record || klass.find(record[:id]).backing_record
    if destroyed?
      backing_record.ar_instance
    else
      merge_current_values(backing_record)
    end
  end
end
record_with_new_values() click to toggle source
# File lib/reactive_record/broadcast.rb, line 89
def record_with_new_values
  klass._react_param_conversion(record).tap do |ar_instance|
    if destroyed?
      ar_instance.backing_record.destroy_associations
    elsif new?
      ar_instance.backing_record.initialize_collections
    end
  end
end
to_s() click to toggle source
# File lib/reactive_record/broadcast.rb, line 111
def to_s
  "klass: #{klass} record: #{record} new?: #{new?} destroyed?: #{destroyed?}"
end