Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # This extension is used mainly for testing purposes - it is not
  2. # designed to be a simple sample, but instead is a hotch-potch of things
  3. # that attempts to exercise the framework.
  4. import os
  5. import stat
  6. import sys
  7. from isapi import isapicon
  8. from isapi.simple import SimpleExtension
  9. if hasattr(sys, "isapidllhandle"):
  10. import win32traceutil
  11. # We use the same reload support as 'advanced.py' demonstrates.
  12. import threading
  13. import win32con
  14. import win32event
  15. import win32file
  16. import winerror
  17. from isapi import InternalReloadException
  18. # A watcher thread that checks for __file__ changing.
  19. # When it detects it, it simply sets "change_detected" to true.
  20. class ReloadWatcherThread(threading.Thread):
  21. def __init__(self):
  22. self.change_detected = False
  23. self.filename = __file__
  24. if self.filename.endswith("c") or self.filename.endswith("o"):
  25. self.filename = self.filename[:-1]
  26. self.handle = win32file.FindFirstChangeNotification(
  27. os.path.dirname(self.filename),
  28. False, # watch tree?
  29. win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
  30. )
  31. threading.Thread.__init__(self)
  32. def run(self):
  33. last_time = os.stat(self.filename)[stat.ST_MTIME]
  34. while 1:
  35. try:
  36. rc = win32event.WaitForSingleObject(self.handle, win32event.INFINITE)
  37. win32file.FindNextChangeNotification(self.handle)
  38. except win32event.error as details:
  39. # handle closed - thread should terminate.
  40. if details.winerror != winerror.ERROR_INVALID_HANDLE:
  41. raise
  42. break
  43. this_time = os.stat(self.filename)[stat.ST_MTIME]
  44. if this_time != last_time:
  45. print("Detected file change - flagging for reload.")
  46. self.change_detected = True
  47. last_time = this_time
  48. def stop(self):
  49. win32file.FindCloseChangeNotification(self.handle)
  50. def TransmitFileCallback(ecb, hFile, cbIO, errCode):
  51. print("Transmit complete!")
  52. ecb.close()
  53. # The ISAPI extension - handles requests in our virtual dir, and sends the
  54. # response to the client.
  55. class Extension(SimpleExtension):
  56. "Python test Extension"
  57. def __init__(self):
  58. self.reload_watcher = ReloadWatcherThread()
  59. self.reload_watcher.start()
  60. def HttpExtensionProc(self, ecb):
  61. # NOTE: If you use a ThreadPoolExtension, you must still perform
  62. # this check in HttpExtensionProc - raising the exception from
  63. # The "Dispatch" method will just cause the exception to be
  64. # rendered to the browser.
  65. if self.reload_watcher.change_detected:
  66. print("Doing reload")
  67. raise InternalReloadException
  68. if ecb.GetServerVariable("UNICODE_URL").endswith("test.py"):
  69. file_flags = (
  70. win32con.FILE_FLAG_SEQUENTIAL_SCAN | win32con.FILE_FLAG_OVERLAPPED
  71. )
  72. hfile = win32file.CreateFile(
  73. __file__,
  74. win32con.GENERIC_READ,
  75. 0,
  76. None,
  77. win32con.OPEN_EXISTING,
  78. file_flags,
  79. None,
  80. )
  81. flags = (
  82. isapicon.HSE_IO_ASYNC
  83. | isapicon.HSE_IO_DISCONNECT_AFTER_SEND
  84. | isapicon.HSE_IO_SEND_HEADERS
  85. )
  86. # We pass hFile to the callback simply as a way of keeping it alive
  87. # for the duration of the transmission
  88. try:
  89. ecb.TransmitFile(
  90. TransmitFileCallback,
  91. hfile,
  92. int(hfile),
  93. "200 OK",
  94. 0,
  95. 0,
  96. None,
  97. None,
  98. flags,
  99. )
  100. except:
  101. # Errors keep this source file open!
  102. hfile.Close()
  103. raise
  104. else:
  105. # default response
  106. ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)
  107. print("<HTML><BODY>", file=ecb)
  108. print("The root of this site is at", ecb.MapURLToPath("/"), file=ecb)
  109. print("</BODY></HTML>", file=ecb)
  110. ecb.close()
  111. return isapicon.HSE_STATUS_SUCCESS
  112. def TerminateExtension(self, status):
  113. self.reload_watcher.stop()
  114. # The entry points for the ISAPI extension.
  115. def __ExtensionFactory__():
  116. return Extension()
  117. # Our special command line customization.
  118. # Pre-install hook for our virtual directory.
  119. def PreInstallDirectory(params, options):
  120. # If the user used our special '--description' option,
  121. # then we override our default.
  122. if options.description:
  123. params.Description = options.description
  124. # Post install hook for our entire script
  125. def PostInstall(params, options):
  126. print()
  127. print("The sample has been installed.")
  128. print("Point your browser to /PyISAPITest")
  129. # Handler for our custom 'status' argument.
  130. def status_handler(options, log, arg):
  131. "Query the status of something"
  132. print("Everything seems to be fine!")
  133. custom_arg_handlers = {"status": status_handler}
  134. if __name__ == "__main__":
  135. # If run from the command-line, install ourselves.
  136. from isapi.install import *
  137. params = ISAPIParameters(PostInstall=PostInstall)
  138. # Setup the virtual directories - this is a list of directories our
  139. # extension uses - in this case only 1.
  140. # Each extension has a "script map" - this is the mapping of ISAPI
  141. # extensions.
  142. sm = [ScriptMapParams(Extension="*", Flags=0)]
  143. vd = VirtualDirParameters(
  144. Name="PyISAPITest",
  145. Description=Extension.__doc__,
  146. ScriptMaps=sm,
  147. ScriptMapUpdate="replace",
  148. # specify the pre-install hook.
  149. PreInstall=PreInstallDirectory,
  150. )
  151. params.VirtualDirs = [vd]
  152. # Setup our custom option parser.
  153. from optparse import OptionParser
  154. parser = OptionParser("") # blank usage, so isapi sets it.
  155. parser.add_option(
  156. "",
  157. "--description",
  158. action="store",
  159. help="custom description to use for the virtual directory",
  160. )
  161. HandleCommandLine(
  162. params, opt_parser=parser, custom_arg_handlers=custom_arg_handlers
  163. )