Class: GTK::RemoteHotloadClient

Inherits:
Object
  • Object
show all
Defined in:
dragon/remote_hotload_client.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(local_ip_address) ⇒ RemoteHotloadClient

Returns a new instance of RemoteHotloadClient.


18
19
20
# File 'dragon/remote_hotload_client.rb', line 18

def initialize local_ip_address
  local_state.local_ip_address = local_ip_address
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args


8
9
10
# File 'dragon/remote_hotload_client.rb', line 8

def args
  @args
end

Instance Method Details

#game_stateObject


43
44
45
# File 'dragon/remote_hotload_client.rb', line 43

def game_state
  args.state
end

#get_server_ip_addressObject


62
63
64
65
66
# File 'dragon/remote_hotload_client.rb', line 62

def get_server_ip_address
  return local_state.ip_address if local_state.ip_address
  local_state.ip_address ||= ((gtk.read_file 'app/server_ip_address.txt') || "").strip
  local_state.ip_address
end

#gtkObject


10
11
12
# File 'dragon/remote_hotload_client.rb', line 10

def gtk
  args.gtk
end

#local_stateObject


47
48
49
50
51
52
53
54
55
# File 'dragon/remote_hotload_client.rb', line 47

def local_state
  @local_state ||= OpenEntity.new
  @local_state.hotload_client ||= @local_state.new_entity(:hotload_client,
                                                          notes: "This entity is used by DragonRuby Game Toolkit to provide you hotloading on remote machines.",
                                                          changes: { },
                                                          changes_queue: [],
                                                          reloaded_files_times: [])
  @local_state.hotload_client
end

#remote_log(message) ⇒ Object


57
58
59
60
# File 'dragon/remote_hotload_client.rb', line 57

def remote_log message
  log message
  args.gtk.http_post "http://#{get_server_ip_address}:9001/dragon/log/", { message: "=======\n#{message}\n=======\n" }, ["Content-Type: application/x-www-form-urlencoded"]
end

#server_available?Boolean

Returns:

  • (Boolean)

68
69
70
71
# File 'dragon/remote_hotload_client.rb', line 68

def server_available?
  return false if gtk.platform == 'Emscripten'
  get_server_ip_address.length != 0
end

#server_needed?Boolean

Returns:

  • (Boolean)

73
74
75
76
# File 'dragon/remote_hotload_client.rb', line 73

def server_needed?
  return false if gtk.platform == 'Emscripten'
  local_state.local_ip_address != get_server_ip_address
end

#should_tick?Boolean

Returns:

  • (Boolean)

39
40
41
# File 'dragon/remote_hotload_client.rb', line 39

def should_tick?
  (game_state.tick_count.mod_zero? 60) && game_state.tick_count > 5.seconds
end

#stateObject


14
15
16
# File 'dragon/remote_hotload_client.rb', line 14

def state
  local_state
end

#tickObject


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'dragon/remote_hotload_client.rb', line 22

def tick
  return unless server_available?
  return unless server_needed?

  if should_tick? && server_needed? && !local_state.notified
    if server_available?
      remote_log "* REMOTE CLIENT INFO: Hotload server found at #{get_server_ip_address}:9001."
    end
    local_state.notified = true
  end

  tick_process_file_retrieval
  tick_process_queue
  tick_changes
  tick_http_boot
end

#tick_changesObject


78
79
80
81
82
83
84
85
# File 'dragon/remote_hotload_client.rb', line 78

def tick_changes
  return unless should_tick?

  local_state.greatest_tick ||= 0
  local_state.last_greatest_tick ||= 0

  tick_http_changes
end

#tick_http_bootObject


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'dragon/remote_hotload_client.rb', line 87

def tick_http_boot
  return if local_state.booted_at


  if !local_state.http_boot
    # first retrieve changes.txt which has the following format
    # file with latest change,
    # latest file                              update_time  key
    # tmp/src_backup/src_backup_app_main.rb, 1597926596,  app/main.rb
    local_state.http_boot    = args.gtk.http_get "http://#{get_server_ip_address}:9001/dragon/boot/"
  elsif local_state.http_boot && local_state.http_boot[:http_response_code] == 200
    local_state.last_greatest_tick = local_state.http_boot[:response_data].strip.to_i
    local_state.greatest_tick = local_state.http_boot[:response_data].strip.to_i
    local_state.booted_at = local_state.greatest_tick
    remote_log '* REMOTE CLIENT INFO: HTTP GET for local_state. boot.txt succeeded.'
    remote_log "* REMOTE CLIENT INFO: Looking for changes after: #{local_state.greatest_tick}."
  elsif local_state.http_boot && local_state.http_boot[:http_response_code] == -1 && local_state.http_boot[:complete]
    remote_log '* REMOTE CLIENT INFO: HTTP GET for boot.txt failed. Retrying.'
    local_state.http_boot = nil
  end
end

#tick_http_changesObject


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'dragon/remote_hotload_client.rb', line 109

def tick_http_changes
  return unless local_state.booted_at

  if !local_state.http_changes
    local_state.http_changes = args.gtk.http_get "http://#{get_server_ip_address}:9001/dragon/changes/"
  end

  if local_state.http_changes && local_state.http_changes[:http_response_code] == 200 && local_state.booted_at
    local_state.last_greatest_tick = local_state.greatest_tick
    # if the retrieval of changes.txt was successful
    local_state.http_changes[:response_data].each_line do |l|
      if l.strip.length != 0
        # within reload state for that specific changes hash
        # set the last time the file was updated
        file_name, updated_at, key = l.strip.split(',')
        file_name.strip!
        updated_at.strip!
        key.strip!
        updated_at = updated_at.to_i
        file_name = file_name.gsub("tmp/src_backup/", "")

        # keep an internal clock that denotes that current time on the
        # dev machine
        if updated_at > local_state.greatest_tick
          local_state.greatest_tick = updated_at

          # create a new entry in change tracking for the file
          # for every file where the file was last updated, find all the ones where the time is not the same
          # and queue those to be retrieved and required
          # if the last time the dev machine time was retrieved is less than the file time changed
          # then queue the file for reload
          current_updated_at = (local_state.changes[key] || { updated_at: 0 })[:updated_at]
          if updated_at > current_updated_at
            remote_log "* REMOTE CLIENT INFO: Queueing file #{file_name} for update."
            local_state.changes[key] = { key: key,
                                         latest_file: file_name,
                                         updated_at: updated_at }
            local_state.changes_queue << local_state.changes[key]
          end
        end
      end
    end

    # set the greatest tick/current time of the machine
    local_state.http_changes = nil
  elsif local_state.http_changes && local_state.http_changes[:http_response_code] == -1 && local_state.http_change[:complete] && local_state.booted_at
    local_state.http_changes = nil
  end
end

#tick_process_file_retrievalObject


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'dragon/remote_hotload_client.rb', line 173

def tick_process_file_retrieval
  return if !local_state.http_file_changes

  # if the http request has finished successfully
  if local_state.http_file_changes[:http_response_code] == 200
    file_key = local_state.processing_file_changes[:key]
    # notify that a file will be reloaded
    remote_log "* REMOTE CLIENT INFO: Loading #{file_key}: #{local_state.processing_file_changes[:latest_file]}"
    remote_log "#{local_state.http_file_changes[:response_data]}"

    # write the latest file with what came back from the response data
    gtk.write_file "#{file_key}", local_state.http_file_changes[:response_data]

    # nil out the currently processing file so a new item can be processed from the queue
    # local_state.reloaded_files_times << local_state.processing_file_changes[:key]
    local_state.http_file_changes = nil
    local_state.processing_file_changes = nil
  end
end

#tick_process_queueObject


159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'dragon/remote_hotload_client.rb', line 159

def tick_process_queue
  return if local_state.http_file_changes # don't pop a file off the queue if there is an http request in flight
  return if local_state.processing_file_changes # don't pop a file if there is a file currently being processed
  return unless local_state.changes_queue.length > 0 # return if the queue is empty

  # if it isn't empty, pop the first file off the queue (FIFO)
  local_state.processing_file_changes = local_state.changes_queue.shift

  # create an http request for the file
  url = "http://#{get_server_ip_address}:9001/dragon/#{local_state.processing_file_changes[:latest_file]}"
  remote_log "* REMOTE CLIENT INFO: Getting new version of #{local_state.processing_file_changes[:latest_file]} (#{url})."
  local_state.http_file_changes = args.gtk.http_get url
end