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.

advanced.py 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # This extension demonstrates some advanced features of the Python ISAPI
  2. # framework.
  3. # We demonstrate:
  4. # * Reloading your Python module without shutting down IIS (eg, when your
  5. # .py implementation file changes.)
  6. # * Custom command-line handling - both additional options and commands.
  7. # * Using a query string - any part of the URL after a '?' is assumed to
  8. # be "variable names" separated by '&' - we will print the values of
  9. # these server variables.
  10. # * If the tail portion of the URL is "ReportUnhealthy", IIS will be
  11. # notified we are unhealthy via a HSE_REQ_REPORT_UNHEALTHY request.
  12. # Whether this is acted upon depends on if the IIS health-checking
  13. # tools are installed, but you should always see the reason written
  14. # to the Windows event log - see the IIS documentation for more.
  15. import os
  16. import stat
  17. import sys
  18. from isapi import isapicon
  19. from isapi.simple import SimpleExtension
  20. if hasattr(sys, "isapidllhandle"):
  21. import win32traceutil
  22. # Notes on reloading
  23. # If your HttpFilterProc or HttpExtensionProc functions raises
  24. # 'isapi.InternalReloadException', the framework will not treat it
  25. # as an error but instead will terminate your extension, reload your
  26. # extension module, re-initialize the instance, and re-issue the request.
  27. # The Initialize functions are called with None as their param. The
  28. # return code from the terminate function is ignored.
  29. #
  30. # This is all the framework does to help you. It is up to your code
  31. # when you raise this exception. This sample uses a Win32 "find
  32. # notification". Whenever windows tells us one of the files in the
  33. # directory has changed, we check if the time of our source-file has
  34. # changed, and set a flag. Next imcoming request, we check the flag and
  35. # raise the special exception if set.
  36. #
  37. # The end result is that the module is automatically reloaded whenever
  38. # the source-file changes - you need take no further action to see your
  39. # changes reflected in the running server.
  40. # The framework only reloads your module - if you have libraries you
  41. # depend on and also want reloaded, you must arrange for this yourself.
  42. # One way of doing this would be to special case the import of these
  43. # modules. Eg:
  44. # --
  45. # try:
  46. # my_module = reload(my_module) # module already imported - reload it
  47. # except NameError:
  48. # import my_module # first time around - import it.
  49. # --
  50. # When your module is imported for the first time, the NameError will
  51. # be raised, and the module imported. When the ISAPI framework reloads
  52. # your module, the existing module will avoid the NameError, and allow
  53. # you to reload that module.
  54. import threading
  55. import win32con
  56. import win32event
  57. import win32file
  58. import winerror
  59. from isapi import InternalReloadException
  60. try:
  61. reload_counter += 1
  62. except NameError:
  63. reload_counter = 0
  64. # A watcher thread that checks for __file__ changing.
  65. # When it detects it, it simply sets "change_detected" to true.
  66. class ReloadWatcherThread(threading.Thread):
  67. def __init__(self):
  68. self.change_detected = False
  69. self.filename = __file__
  70. if self.filename.endswith("c") or self.filename.endswith("o"):
  71. self.filename = self.filename[:-1]
  72. self.handle = win32file.FindFirstChangeNotification(
  73. os.path.dirname(self.filename),
  74. False, # watch tree?
  75. win32con.FILE_NOTIFY_CHANGE_LAST_WRITE,
  76. )
  77. threading.Thread.__init__(self)
  78. def run(self):
  79. last_time = os.stat(self.filename)[stat.ST_MTIME]
  80. while 1:
  81. try:
  82. rc = win32event.WaitForSingleObject(self.handle, win32event.INFINITE)
  83. win32file.FindNextChangeNotification(self.handle)
  84. except win32event.error as details:
  85. # handle closed - thread should terminate.
  86. if details.winerror != winerror.ERROR_INVALID_HANDLE:
  87. raise
  88. break
  89. this_time = os.stat(self.filename)[stat.ST_MTIME]
  90. if this_time != last_time:
  91. print("Detected file change - flagging for reload.")
  92. self.change_detected = True
  93. last_time = this_time
  94. def stop(self):
  95. win32file.FindCloseChangeNotification(self.handle)
  96. # The ISAPI extension - handles requests in our virtual dir, and sends the
  97. # response to the client.
  98. class Extension(SimpleExtension):
  99. "Python advanced sample Extension"
  100. def __init__(self):
  101. self.reload_watcher = ReloadWatcherThread()
  102. self.reload_watcher.start()
  103. def HttpExtensionProc(self, ecb):
  104. # NOTE: If you use a ThreadPoolExtension, you must still perform
  105. # this check in HttpExtensionProc - raising the exception from
  106. # The "Dispatch" method will just cause the exception to be
  107. # rendered to the browser.
  108. if self.reload_watcher.change_detected:
  109. print("Doing reload")
  110. raise InternalReloadException
  111. url = ecb.GetServerVariable("UNICODE_URL")
  112. if url.endswith("ReportUnhealthy"):
  113. ecb.ReportUnhealthy("I'm a little sick")
  114. ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)
  115. print("<HTML><BODY>", file=ecb)
  116. qs = ecb.GetServerVariable("QUERY_STRING")
  117. if qs:
  118. queries = qs.split("&")
  119. print("<PRE>", file=ecb)
  120. for q in queries:
  121. val = ecb.GetServerVariable(q, "&lt;no such variable&gt;")
  122. print("%s=%r" % (q, val), file=ecb)
  123. print("</PRE><P/>", file=ecb)
  124. print("This module has been imported", file=ecb)
  125. print("%d times" % (reload_counter,), file=ecb)
  126. print("</BODY></HTML>", file=ecb)
  127. ecb.close()
  128. return isapicon.HSE_STATUS_SUCCESS
  129. def TerminateExtension(self, status):
  130. self.reload_watcher.stop()
  131. # The entry points for the ISAPI extension.
  132. def __ExtensionFactory__():
  133. return Extension()
  134. # Our special command line customization.
  135. # Pre-install hook for our virtual directory.
  136. def PreInstallDirectory(params, options):
  137. # If the user used our special '--description' option,
  138. # then we override our default.
  139. if options.description:
  140. params.Description = options.description
  141. # Post install hook for our entire script
  142. def PostInstall(params, options):
  143. print()
  144. print("The sample has been installed.")
  145. print("Point your browser to /AdvancedPythonSample")
  146. print("If you modify the source file and reload the page,")
  147. print("you should see the reload counter increment")
  148. # Handler for our custom 'status' argument.
  149. def status_handler(options, log, arg):
  150. "Query the status of something"
  151. print("Everything seems to be fine!")
  152. custom_arg_handlers = {"status": status_handler}
  153. if __name__ == "__main__":
  154. # If run from the command-line, install ourselves.
  155. from isapi.install import *
  156. params = ISAPIParameters(PostInstall=PostInstall)
  157. # Setup the virtual directories - this is a list of directories our
  158. # extension uses - in this case only 1.
  159. # Each extension has a "script map" - this is the mapping of ISAPI
  160. # extensions.
  161. sm = [ScriptMapParams(Extension="*", Flags=0)]
  162. vd = VirtualDirParameters(
  163. Name="AdvancedPythonSample",
  164. Description=Extension.__doc__,
  165. ScriptMaps=sm,
  166. ScriptMapUpdate="replace",
  167. # specify the pre-install hook.
  168. PreInstall=PreInstallDirectory,
  169. )
  170. params.VirtualDirs = [vd]
  171. # Setup our custom option parser.
  172. from optparse import OptionParser
  173. parser = OptionParser("") # blank usage, so isapi sets it.
  174. parser.add_option(
  175. "",
  176. "--description",
  177. action="store",
  178. help="custom description to use for the virtual directory",
  179. )
  180. HandleCommandLine(
  181. params, opt_parser=parser, custom_arg_handlers=custom_arg_handlers
  182. )