Class: Metacosm::Simulation

Inherits:
Object
  • Object
show all
Defined in:
lib/metacosm/simulation.rb

Direct Known Subclasses

RemoteSimulation

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.currentObject



133
134
135
# File 'lib/metacosm/simulation.rb', line 133

def self.current
  @current ||= new
end

Instance Method Details

#apply(command) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/metacosm/simulation.rb', line 41

def apply(command)
  mutex.synchronize do
    if command.is_a?(Hash)
      handler_module_name = command.delete(:handler_module)
      handler_class_name = command.delete(:handler_class_name)
      module_name = handler_module_name
      handler = (module_name.constantize).
        const_get(handler_class_name).new
      handler.handle(command)
    else
      handler = handler_for(command)
      handler.handle(command.attrs)
    end
  end
end

#apply_event(event) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/metacosm/simulation.rb', line 57

def apply_event(event)
  if !@on_event_callback.nil?
    event_dto = event.attrs.merge(listener_module: event.listener_module_name, listener_class_name: event.listener_class_name)
    @on_event_callback[event_dto]
  end

  if !@event_publication_channel.nil?
    event_dto = event.attrs.merge(listener_module: event.listener_module_name, listener_class_name: event.listener_class_name)
    redis = redis_connection
    redis.publish(@event_publication_channel, Marshal.dump(event_dto))
  end

  if !local_events_disabled?
    listener = listener_for(event)
    if event.attrs.any?
      listener.receive(event.attrs)
    else
      listener.receive
    end
  end
end

#clear!Object



137
138
139
140
# File 'lib/metacosm/simulation.rb', line 137

def clear!
  @events = []
  @command_queue && @command_queue.clear
end

#command_queueObject



12
13
14
# File 'lib/metacosm/simulation.rb', line 12

def command_queue
  @command_queue ||= Queue.new
end

#conduct!Object



20
21
22
# File 'lib/metacosm/simulation.rb', line 20

def conduct!
  @conductor_thread = Thread.new { execute }
end

#construct_handler_for(command) ⇒ Object (protected)



148
149
150
151
152
153
154
155
# File 'lib/metacosm/simulation.rb', line 148

def construct_handler_for(command)
  module_name = command.handler_module_name
  (module_name.constantize).
    const_get(command.handler_class_name).new
rescue => ex
  binding.pry
  raise ex
end

#construct_listener_for(event) ⇒ Object (protected)



162
163
164
165
166
# File 'lib/metacosm/simulation.rb', line 162

def construct_listener_for(event)
  module_name = event.listener_module_name
  listener = (module_name.constantize).const_get(event.listener_class_name).new(self)
  listener
end

#disable_local_eventsObject



116
117
118
# File 'lib/metacosm/simulation.rb', line 116

def disable_local_events
  @local_events_disabled = true
end

#event_queueObject



16
17
18
# File 'lib/metacosm/simulation.rb', line 16

def event_queue
  @event_queue ||= Queue.new
end

#eventsObject



129
130
131
# File 'lib/metacosm/simulation.rb', line 129

def events
  @events ||= []
end

#executeObject



24
25
26
27
28
29
30
31
# File 'lib/metacosm/simulation.rb', line 24

def execute
  while true
    if (command=command_queue.pop)
      apply(command)
    end
    Thread.pass
  end
end

#fire(command) ⇒ Object



8
9
10
# File 'lib/metacosm/simulation.rb', line 8

def fire(command)
  command_queue.push(command)
end

#halt!Object



33
34
35
# File 'lib/metacosm/simulation.rb', line 33

def halt!
  @conductor_thread.terminate
end

#handler_for(command) ⇒ Object (protected)



143
144
145
146
# File 'lib/metacosm/simulation.rb', line 143

def handler_for(command)
  @handlers ||= {}
  @handlers[command.self_class_name] ||= construct_handler_for(command)
end

#listener_for(event) ⇒ Object (protected)



157
158
159
160
# File 'lib/metacosm/simulation.rb', line 157

def listener_for(event)
  @listeners ||= {}
  @listeners[event.self_class_name] ||= construct_listener_for(event)
end

#local_events_disabled?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/metacosm/simulation.rb', line 120

def local_events_disabled?
  @local_events_disabled ||= false
end

#mutexObject



37
38
39
# File 'lib/metacosm/simulation.rb', line 37

def mutex
  @mutex = Mutex.new
end

#on_event(publish_to: nil, &blk) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'lib/metacosm/simulation.rb', line 79

def on_event(publish_to:nil,&blk)
  unless publish_to.nil?
    @event_publication_channel = publish_to
  end

  if block_given?
    @on_event_callback = blk
  end
end

#receive(event, record: true) ⇒ Object



124
125
126
127
# File 'lib/metacosm/simulation.rb', line 124

def receive(event, record: true)
  events.push(event) if record
  apply_event(event)
end

#redis_connectionObject

TODO protected?



4
5
6
# File 'lib/metacosm/simulation.rb', line 4

def redis_connection
  Redis.new
end

#subscribe_for_commands(channel:) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/metacosm/simulation.rb', line 89

def subscribe_for_commands(channel:)
  p [ :subscribe_to_command_channel, channel: channel ]
  @command_subscription_thread = Thread.new do
    redis = redis_connection
    begin
      redis.subscribe(channel) do |on|
        on.subscribe do |chan, subscriptions|
          puts "Subscribed to ##{chan} (#{subscriptions} subscriptions)"
        end

        on.message do |chan, message|
          puts "##{chan}: #{message}"
          apply(Marshal.load(message))
        end

        on.unsubscribe do |chan, subscriptions|
          puts "Unsubscribed from ##{chan} (#{subscriptions} subscriptions)"
        end
      end
    rescue Redis::BaseConnectionError => error
      puts "#{error}, retrying in 1s"
      sleep 1
      retry
    end
  end
end