downloader.gd 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. extends HTTPRequest
  2. var kinds = {
  3. "topo": "http://imbrium.mit.edu/DATA/SLDEM2015/TILES/FLOAT_IMG/%s",
  4. "color": "https://nextcloud.alfi.li/nextcloud/index.php/s/dMELm8P8sPxbC5f/download?path=%2F&files=%s"
  5. }
  6. var downloads = {}
  7. var downloading = false
  8. onready var UI = get_node("/root/Main/UI/Downloader")
  9. signal file_downloaded
  10. signal downloads_finished
  11. signal stats_updated
  12. signal downloads_started
  13. export(bool) var blind_mode : bool = false
  14. var _headers : Array = []
  15. var _last_method : int
  16. var _ssl : bool = false
  17. var _file := File.new()
  18. var _timer : float = 0.0
  19. var currentDownload : Download
  20. class Download:
  21. var _file_name : String
  22. var _file_size : float
  23. var _current_url : String
  24. var _kind : String
  25. var _downloaded_percent : float = 0
  26. var _downloaded_size : float = 0
  27. func _init() -> void:
  28. set_process(false)
  29. connect("request_completed", self, "_on_request_completed")
  30. func _ready():
  31. connect("stats_updated", Messenger, "_on_statusUpdate")
  32. func get_stats() -> Download:
  33. return currentDownload
  34. func _reset() -> void:
  35. currentDownload = Download.new()
  36. func _downloads_done() -> void:
  37. set_process(false)
  38. _update_stats()
  39. _file.close()
  40. emit_signal("downloads_finished", currentDownload)
  41. _reset()
  42. downloading = false
  43. UI.hide()
  44. func _update_stats() -> void:
  45. if blind_mode == false:
  46. _calculate_percentage()
  47. emit_signal("stats_updated",currentDownload)
  48. func _process(delta):
  49. if not downloading:
  50. if len(downloads) == 0:
  51. set_process(false)
  52. return
  53. for kind in downloads:
  54. for file in downloads[kind]:
  55. var dl = downloads[kind][file]
  56. currentDownload = dl
  57. _download()
  58. _timer += delta
  59. if _timer > 1:
  60. _update_stats()
  61. _timer = 0.0
  62. func _download():
  63. ensureFolder(currentDownload._kind)
  64. download_file = currentDownload._file_name
  65. _send_head_request()
  66. print("downloading %s" %currentDownload._current_url)
  67. downloading = true
  68. UI.show()
  69. func ensureFolder(kind):
  70. var dir = Directory.new()
  71. dir.open("user://")
  72. if not dir.dir_exists(kind):
  73. dir.make_dir(kind)
  74. func download(file, kind):
  75. set_process(true)
  76. if not kinds.has(kind):
  77. print("don't know kind %s"%kind)
  78. return
  79. if not downloads.has(kind):
  80. downloads[kind] = {}
  81. if downloads[kind].has(file):
  82. return
  83. var download = Download.new()
  84. download._file_name = "user://%s/%s"%[kind, file]
  85. download._current_url = make_filename(kind, file)
  86. download._kind = kind
  87. downloads[kind][download._file_name] = download
  88. func make_filename(kind, file):
  89. return kinds[kind]%file
  90. func _send_head_request() -> void:
  91. # The HEAD method only gets the head and not the body. Therefore, doesn't
  92. # download the file.
  93. request(currentDownload._current_url, _headers, _ssl, HTTPClient.METHOD_HEAD)
  94. _last_method = HTTPClient.METHOD_HEAD
  95. func _send_get_request() -> void:
  96. var error = request(currentDownload._current_url, _headers, _ssl, HTTPClient.METHOD_GET)
  97. if error == OK:
  98. emit_signal("downloads_started")
  99. _last_method = HTTPClient.METHOD_GET
  100. set_process(true)
  101. elif error == ERR_INVALID_PARAMETER:
  102. print("Given string isn't a valid url ")
  103. elif error == ERR_CANT_CONNECT:
  104. print("Can't connect to host")
  105. func _on_request_completed(p_result,
  106. _p_response_code,
  107. p_headers,
  108. _p_body) -> void:
  109. if p_result == RESULT_SUCCESS:
  110. if _p_response_code != 200:
  111. push_error("Download HTTP Error %s:%s" %[_p_response_code,_p_body])
  112. return
  113. if _last_method == HTTPClient.METHOD_HEAD and blind_mode == false:
  114. var regex = "(?i)content-length: [0-9]*"
  115. var size = _extract_regex_from_header(regex, p_headers.join(' '))
  116. size = size.replace("Content-Length: ", "")
  117. currentDownload._file_size = size.to_float()
  118. _send_get_request()
  119. elif _last_method == HTTPClient.METHOD_HEAD and blind_mode == true:
  120. _send_get_request()
  121. elif _last_method == HTTPClient.METHOD_GET:
  122. print("file download complete %s"%currentDownload._current_url)
  123. _file.close()
  124. emit_signal("file_downloaded", currentDownload)
  125. Messenger._on_file_downloaded(currentDownload)
  126. downloading = false
  127. remove_download()
  128. elif p_result == RESULT_DOWNLOAD_FILE_CANT_OPEN:
  129. push_error("Download cannot open file %s" %currentDownload._file_name)
  130. else:
  131. print("HTTP Request error: ", p_result)
  132. func remove_download():
  133. downloads[currentDownload._kind].erase(currentDownload._file_name)
  134. if len(downloads[currentDownload._kind]) == 0:
  135. downloads.erase(currentDownload._kind)
  136. if len(downloads) == 0:
  137. _downloads_done()
  138. func _calculate_percentage() -> void:
  139. var error : int
  140. error = _file.open(download_file, File.READ)
  141. if error == OK and currentDownload._file_size > 0:
  142. currentDownload._downloaded_size = _file.get_len()
  143. currentDownload._downloaded_percent = (currentDownload._downloaded_size / currentDownload._file_size) *100
  144. func _extract_regex_from_header(p_regex : String,
  145. p_header : String) -> String:
  146. var regex = RegEx.new()
  147. regex.compile(p_regex)
  148. var result = regex.search(p_header)
  149. return result.get_string()