http_server.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. # (c) J.Y.Amihud 2023
  2. # GPL-3 or any later version
  3. # This is a http server that will serve files over network, for multiusering
  4. # across the internet.
  5. # Server side
  6. from http.server import BaseHTTPRequestHandler, HTTPServer
  7. from subprocess import *
  8. import json
  9. import os
  10. import zlib
  11. import sys
  12. import time
  13. import random
  14. import mimetypes
  15. import datetime
  16. import hashlib
  17. import urllib.request
  18. import urllib.parse
  19. import subprocess
  20. # Colors are used to make the
  21. clr = {
  22. "norm":"\033[00m", # Reset to normal
  23. "bold":"\033[01m", # Bold Text
  24. "ital":"\033[03m", # Italic Text
  25. "undr":"\033[04m", # Underlined
  26. "blnk":"\033[05m", # Blinking
  27. # Text
  28. "tdbl":"\033[30m", # Dark Black
  29. "tdrd":"\033[31m", # Dark Red
  30. "tdgr":"\033[32m", # Dark Green
  31. "tdyl":"\033[33m", # Dark Yellow
  32. "tdbu":"\033[34m", # Dark Blue
  33. "tdma":"\033[35m", # Dark Magenta
  34. "tdcy":"\033[36m", # Dark Cyan
  35. "tdwh":"\033[37m", # Dark White
  36. "tbbl":"\033[90m", # Bright Black
  37. "tbrd":"\033[91m", # Bright Red
  38. "tbgr":"\033[92m", # Bright Green
  39. "tbyl":"\033[93m", # Bright Yellow
  40. "tbbu":"\033[94m", # Bright Blue
  41. "tbma":"\033[95m", # Bright Magenta
  42. "tbcy":"\033[96m", # Bright Cyan
  43. "tbwh":"\033[97m", # Bright White
  44. # Background
  45. "bdbl":"\033[40m", # Dark Black
  46. "bdrd":"\033[41m", # Dark Red
  47. "bdgr":"\033[42m", # Dark Green
  48. "bdyl":"\033[43m", # Dark Yellow
  49. "bdbu":"\033[44m", # Dark Blue
  50. "bdma":"\033[45m", # Dark Magenta
  51. "bdcy":"\033[46m", # Dark Cyan
  52. "bdwh":"\033[47m", # Dark White
  53. "bbbl":"\033[100m", # Bright Black
  54. "bbrd":"\033[101m", # Bright Red
  55. "bbgr":"\033[102m", # Bright Green
  56. "bbyl":"\033[103m", # Bright Yellow
  57. "bbbu":"\033[104m", # Bright Blue
  58. "bbma":"\033[105m", # Bright Magenta
  59. "bbcy":"\033[106m", # Bright Cyan
  60. "bbwh":"\033[108m" # Bright White
  61. }
  62. # TODO: Make this not stupidly hardcoded.
  63. blender = "/home/vcs/Software/blender-3.3.0-linux-x64/blender"
  64. try:
  65. PROJECT = sys.argv[2]
  66. except:
  67. print("Please specify a port number and then project folder.")
  68. exit()
  69. try:
  70. ORIGINAL_PROJECT = sys.argv[3]
  71. except:
  72. print("Orignal Project Name Was Not Specified.")
  73. ORIGINAL_PROJECT = " not a folder that can exist "
  74. def fileinfo(filename):
  75. fd = {}
  76. fd["md5"] = hashlib.md5(open(filename,'rb').read()).hexdigest()
  77. fd["filesize"] = os.path.getsize(filename)
  78. return fd
  79. class handler(BaseHTTPRequestHandler):
  80. def start_page(self, code):
  81. self.send_response(code)
  82. def do_GET(self):
  83. # Basic security measure
  84. self.path = self.path.replace("/..", "/")
  85. self.path = self.path.replace("//", "/")
  86. if self.path == "/":
  87. self.start_page(200)
  88. self.wfile.write(b"Welcome to Blender-Pipeline Http Server.\nUse /list/[Folder Name] to list contents of a specific folder.\nUse /download/[File Name] to download the file.\nUse /blend/[Blender File Name] to see Blend File Dependencies.")
  89. elif self.path.startswith("/list/"):
  90. foldername = self.path[5:]
  91. folder = PROJECT+foldername
  92. walk = list(os.walk(folder))[0]
  93. # folders
  94. data = {"folders":walk[1],
  95. "files":{}}
  96. for i in walk[2]:
  97. fd = fileinfo(folder+"/"+i)
  98. data["files"][i] = fd
  99. senddata = json.dumps(data).encode("utf-8")
  100. self.start_page(200)
  101. self.send_header('Content-type', 'application/json')
  102. self.end_headers()
  103. self.wfile.write(senddata)
  104. # THIS WAS A GOOD IDEA ON PAPER, BUT WITH A 100 GB PROJECT
  105. # IT TOOK FOREVER TO DO THIS FOR ONE PART OF THIS PROJECT.
  106. # elif self.path.startswith("/tree/"):
  107. # foldername = self.path[5:]
  108. # folder = PROJECT+foldername
  109. # walk = list(os.walk(folder))
  110. # data = {"folders":[],
  111. # "files":{}}
  112. # for i in walk:
  113. # fol = i[0].replace(PROJECT, "")[1:]
  114. # data["folders"].append(fol)
  115. # for fil in i[2]:
  116. # fd = fileinfo(PROJECT+"/"+fol+"/"+fil)
  117. # data["files"][fol+"/"+fil] = fd
  118. # senddata = json.dumps(data).encode("utf-8")
  119. # self.start_page(200)
  120. # self.send_header('Content-type', 'application/json')
  121. # self.end_headers()
  122. # self.wfile.write(senddata)
  123. elif self.path.startswith("/blend/"):
  124. filename = self.path[6:]
  125. fullfilename = PROJECT+filename
  126. if os.path.exists(fullfilename):
  127. try:
  128. linked = subprocess.check_output([blender, "-b", fullfilename, "-P", os.getcwd()+"/network/get_linked_files.py"]).decode("utf-8")
  129. except:
  130. linked = ""
  131. linked = linked[linked.find("!START_DATA!")+13:linked.rfind("!END_DATA!")]
  132. linked = linked.split("\n")
  133. while "" in linked:
  134. linked.remove("")
  135. parsed = []
  136. for i in linked:
  137. # This is a little weird, sometimes the files have the full URL
  138. # to the data.
  139. if i.startswith(PROJECT): # This is good when the server is on the same machine as the orignal project
  140. parsed.append(i[len(PROJECT):])
  141. elif i.startswith(ORIGINAL_PROJECT): # This is when the server is a mirror
  142. parsed.append(i[len(ORIGINAL_PROJECT):])
  143. else:
  144. backward = i.count("/..")
  145. foldername = filename[:filename.rfind("/")]
  146. f = foldername
  147. for g in range(backward):
  148. f = f[:f.rfind("/")]
  149. cleanname = f+i.replace("//..", "").replace("/..", "").replace( "//", "/")
  150. parsed.append(cleanname)
  151. data = {"files":{}}
  152. for f in parsed:
  153. try:
  154. fd = fileinfo(PROJECT+"/"+f)
  155. data["files"][f] = fd
  156. except Exception as e:
  157. print(e)
  158. linked = json.dumps(data)
  159. self.start_page(200)
  160. self.send_header('Content-type', 'application/json')
  161. self.end_headers()
  162. self.wfile.write(linked.encode("utf-8"))
  163. else:
  164. self.start_page(404)
  165. self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist on server.")
  166. elif self.path.startswith("/download/"):
  167. filename = self.path[9:]
  168. fullfilename = PROJECT+filename
  169. if os.path.exists(fullfilename):
  170. self.start_page(200)
  171. self.send_header('Content-type', mimetypes.guess_type(filename))
  172. self.end_headers()
  173. f = open(fullfilename, "rb")
  174. f = f.read()
  175. self.wfile.write(f)
  176. else:
  177. self.start_page(404)
  178. self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist")
  179. elif self.path.startswith("/download_z/"):
  180. filename = self.path[11:]
  181. fullfilename = PROJECT+filename
  182. if os.path.exists(fullfilename):
  183. self.start_page(200)
  184. self.send_header('Content-type', mimetypes.guess_type(filename))
  185. f = open(fullfilename, "rb")
  186. f = f.read()
  187. z = zlib.compress(f)
  188. self.send_header('Content-length', len(z))
  189. self.end_headers()
  190. self.wfile.write(z)
  191. else:
  192. self.start_page(404)
  193. self.wfile.write(b"File: "+filename.encode("utf-8")+b" doesn't exist")
  194. try:
  195. PORT = int(sys.argv[1])
  196. except:
  197. print("Please specify a port number and then project folder.")
  198. exit()
  199. serve = HTTPServer(("", PORT), handler)
  200. serve.serve_forever()