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



147
148
149
# File 'lib/metacosm/simulation.rb', line 147

def self.current
  @current ||= new
end

Instance Method Details

#apply(command) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/metacosm/simulation.rb', line 45

def apply(command)
  mutex.synchronize do
    received_commands.push(command)

    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



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/metacosm/simulation.rb', line 67

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_PUB.with do |redis|
      redis.publish(@event_publication_channel, Marshal.dump(event_dto))
    end
  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



151
152
153
154
# File 'lib/metacosm/simulation.rb', line 151

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

#command_queueObject



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

def command_queue
  @command_queue ||= Queue.new
end

#conduct!Object



24
25
26
# File 'lib/metacosm/simulation.rb', line 24

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

#construct_handler_for(command) ⇒ Object (protected)



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

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)



176
177
178
179
180
# File 'lib/metacosm/simulation.rb', line 176

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



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

def disable_local_events
  @local_events_disabled = true
end

#event_queueObject



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

def event_queue
  @event_queue ||= Queue.new
end

#eventsObject



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

def events
  @events ||= []
end

#executeObject



28
29
30
31
32
33
34
35
# File 'lib/metacosm/simulation.rb', line 28

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

#fire(command) ⇒ Object



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

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

#halt!Object



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

def halt!
  @conductor_thread.terminate
end

#handler_for(command) ⇒ Object (protected)



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

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

#listener_for(event) ⇒ Object (protected)



171
172
173
174
# File 'lib/metacosm/simulation.rb', line 171

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

#local_events_disabled?Boolean

Returns:

  • (Boolean)


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

def local_events_disabled?
  @local_events_disabled ||= false
end

#mutexObject



41
42
43
# File 'lib/metacosm/simulation.rb', line 41

def mutex
  @mutex = Mutex.new
end

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



90
91
92
93
94
95
96
97
98
# File 'lib/metacosm/simulation.rb', line 90

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

#paramsObject

TODO protected? def redis_connection Redis.new end



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

def params
  @params ||= {}
end

#receive(event, record: true) ⇒ Object



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

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

#received_commandsObject



63
64
65
# File 'lib/metacosm/simulation.rb', line 63

def received_commands
  @commands_received ||= []
end

#subscribe_for_commands(channel:) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/metacosm/simulation.rb', line 100

def subscribe_for_commands(channel:)
  p [ :subscribe_to_command_channel, channel: channel ]
  @command_subscription_thread = Thread.new do
    REDIS_SUB.with do |redis|
      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}"
            command_data = Marshal.load(message)
            p [ :got_message, command_data: command_data ]
            apply(command_data)
          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
end