app.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # This file is part of DarkFi (https://dark.fi)
  2. #
  3. # Copyright (C) 2020-2025 Dyne.org foundation
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. """
  18. Module: app.py
  19. This module initializes the DarkFi explorer Flask application by registering various blueprints for handling routes
  20. related to blocks, contracts, transactions, search, and the explore section, including the home page. It also defines
  21. error handlers, ensuring appropriate responses for these common HTTP errors.
  22. """
  23. import os
  24. import tomli
  25. from flask import Flask, render_template
  26. from blueprints.explore import explore_bp
  27. from blueprints.block import block_bp
  28. from blueprints.contract import contract_bp
  29. from blueprints.transaction import transaction_bp
  30. import log
  31. def create_app():
  32. """
  33. Creates and configures the DarkFi explorer Flask application.
  34. This function creates and initializes the explorer the Flask app,
  35. registering applicable blueprints for handling explorer-related routes,
  36. and defining error handling for common HTTP errors. It returns a fully
  37. configured Flask application instance.
  38. """
  39. app = Flask(__name__)
  40. # Retrieve and store network
  41. network = os.getenv("FLASK_ENV", "localnet")
  42. app.config['NETWORK'] = network
  43. # Load the app TOML configuration
  44. load_toml_config(app, network)
  45. # Setup logger
  46. log.setup_logger(app, network)
  47. # Register Blueprints
  48. app.register_blueprint(explore_bp)
  49. app.register_blueprint(block_bp)
  50. app.register_blueprint(contract_bp)
  51. app.register_blueprint(transaction_bp)
  52. # Define page not found error handler
  53. @app.errorhandler(404)
  54. def page_not_found(e):
  55. """
  56. Handles 404 errors by rendering a custom 404 error page when a requested page is not found,
  57. returning a rendered template along with a 404 status code.
  58. Args:
  59. e: The error object associated with the 404 error.
  60. """
  61. # Render the custom 404 error page
  62. return render_template('404.html'), 404
  63. # Define internal server error handler
  64. @app.errorhandler(500)
  65. def internal_server_error(e):
  66. """
  67. Handles 500 errors by logging the error and returning the app's 500 error page.
  68. This function logs the error with its stack trace, file name, and line number
  69. to help with debugging. It then renders the '500.html' template and returns it
  70. along with a 500 HTTP status code.
  71. Args:
  72. e: The error object associated with the 500 error.
  73. """
  74. # Log the error
  75. app.error_logger.exception("An unexpected error occurred")
  76. # Render the custom 500 error page
  77. return render_template('500.html'), 500
  78. # Log that we started the site
  79. app.logger.info("=" * 60)
  80. app.logger.info("Started Explorer Site")
  81. app.logger.info("=" * 60)
  82. app.logger.info(f"Network: {network}")
  83. app.logger.info(f"Explorer Node Endpoint: {app.config['explorer_rpc_url']}:{app.config['explorer_rpc_port']}")
  84. app.logger.info(f"Log Path: {app.config['log_path']}")
  85. app.logger.info("=" * 60)
  86. return app
  87. def load_toml_config(app, network="localnet", config_path="site_config.toml"):
  88. """
  89. Loads environment-specific key-value pairs from a TOML configuration file into `app.config`.
  90. Args:
  91. app (Flask): The Flask application.
  92. network (str): The name of the network section to load (default is "localnet").
  93. config_path (str): The path to the TOML configuration file.
  94. Raises:
  95. FileNotFoundError: If the configuration file cannot be found.
  96. KeyError: If the specified environment section does not exist.
  97. """
  98. # Verify that the configuration file exists
  99. if not os.path.isfile(config_path):
  100. raise FileNotFoundError(f"Configuration file '{config_path}' not found.")
  101. # Open and parse the configuration file (TOML)
  102. with open(config_path, "rb") as f:
  103. config = tomli.load(f)
  104. # Ensure the specified network section exists in the configuration
  105. if network not in config:
  106. raise KeyError(f"Network '{network}' not found in {config_path}")
  107. # Load the environment specific configurations into app.config
  108. for key, value in config[network].items():
  109. app.config[key] = value