Coverage for src/unit_cooler/actuator/web_server.py: 92%

60 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-07-23 14:35 +0000

1#!/usr/bin/env python3 

2""" 

3室外機冷却システムの WebUI サーバーを提供します。 

4 

5Usage: 

6 web_server.py [-c CONFIG] [-p PORT] [-D] 

7 

8Options: 

9 -c CONFIG : CONFIG を設定ファイルとして読み込んで実行します。[default: config.yaml] 

10 -p PORT : Web サーバーを動作させるポートを指定します。[default: 5000] 

11 -D : デバッグモードで動作します。 

12""" 

13 

14import logging 

15import threading 

16 

17import flask 

18import flask_cors 

19import my_lib.webapp.base 

20import my_lib.webapp.config 

21import my_lib.webapp.event 

22import my_lib.webapp.log 

23import my_lib.webapp.util 

24import werkzeug.serving 

25 

26import unit_cooler.actuator.webapi.flow_status 

27import unit_cooler.actuator.webapi.valve_status 

28import unit_cooler.metrics.webapi.page 

29from unit_cooler.metrics import get_metrics_collector 

30 

31 

32def create_app(config, event_queue): 

33 my_lib.webapp.config.URL_PREFIX = "/unit-cooler" 

34 my_lib.webapp.config.init(config["actuator"]["web_server"]) 

35 

36 # NOTE: アクセスログは無効にする 

37 logging.getLogger("werkzeug").setLevel(logging.ERROR) 

38 

39 app = flask.Flask("unit-cooler-web") 

40 

41 flask_cors.CORS(app) 

42 

43 app.config["CONFIG"] = config 

44 app.config["CONFIG_FILE_NORMAL"] = "config.yaml" # メトリクス用設定 

45 

46 app.json.compat = True 

47 

48 app.register_blueprint(my_lib.webapp.log.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX) 

49 app.register_blueprint(my_lib.webapp.event.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX) 

50 app.register_blueprint(my_lib.webapp.util.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX) 

51 app.register_blueprint( 

52 unit_cooler.actuator.webapi.valve_status.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX 

53 ) 

54 app.register_blueprint( 

55 unit_cooler.actuator.webapi.flow_status.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX 

56 ) 

57 app.register_blueprint( 

58 unit_cooler.metrics.webapi.page.blueprint, url_prefix=my_lib.webapp.config.URL_PREFIX 

59 ) 

60 

61 my_lib.webapp.config.show_handler_list(app, True) 

62 

63 my_lib.webapp.log.init(config) 

64 my_lib.webapp.event.start(event_queue) 

65 

66 # メトリクスデータベースの初期化 

67 metrics_db_path = config["actuator"].get("metrics", {}).get("data", "data/metrics.db") 

68 try: 

69 metrics_collector = get_metrics_collector(metrics_db_path) 

70 logging.info("Metrics database initialized at: %s", metrics_db_path) 

71 app.config["METRICS_COLLECTOR"] = metrics_collector 

72 except Exception: 

73 logging.exception("Failed to initialize metrics database") 

74 

75 # app.debug = True 

76 

77 return app 

78 

79 

80def start(config, event_queue, port): 

81 # NOTE: Flask は別のプロセスで実行 

82 try: 

83 app = create_app(config, event_queue) 

84 logging.info("Web app created successfully") 

85 except Exception: 

86 logging.exception("Failed to create web app") 

87 raise 

88 

89 server = werkzeug.serving.make_server( 

90 "0.0.0.0", # noqa: S104 

91 port, 

92 app, 

93 threaded=True, 

94 ) 

95 thread = threading.Thread(target=server.serve_forever) 

96 

97 logging.info("Start web server") 

98 

99 thread.start() 

100 

101 return { 

102 "server": server, 

103 "thread": thread, 

104 } 

105 

106 

107def term(handle): 

108 import my_lib.webapp.event 

109 

110 logging.warning("Stop web server") 

111 

112 my_lib.webapp.event.term() 

113 

114 handle["server"].shutdown() 

115 handle["server"].server_close() 

116 handle["thread"].join() 

117 

118 my_lib.webapp.log.term() 

119 

120 

121if __name__ == "__main__": 

122 # TEST Code 

123 import multiprocessing 

124 

125 import docopt 

126 import my_lib.config 

127 import my_lib.logger 

128 import my_lib.pretty 

129 

130 args = docopt.docopt(__doc__) 

131 

132 config_file = args["-c"] 

133 port = int(args["-p"]) 

134 debug_mode = args["-D"] 

135 

136 my_lib.logger.init("test", level=logging.DEBUG if debug_mode else logging.INFO) 

137 

138 config = my_lib.config.load(config_file) 

139 event_queue = multiprocessing.Queue() 

140 

141 log_server_handle = start(config, event_queue, port)