taler-merchant-demos

Python-based Frontends for the Demonstration Web site
Log | Files | Refs | Submodules | README | LICENSE

cli.py (3774B)


      1 ##
      2 # This file is part of GNU Taler
      3 # (C) 2017,2021 Taler Systems S.A.
      4 #
      5 # GNU Taler is free software; you can redistribute it and/or
      6 # modify it under the terms of the GNU Affero General Public
      7 # License as published by the Free Software Foundation; either
      8 # version 3, or (at your option) any later version.
      9 #
     10 # GNU Taler is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty
     12 # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     13 # See the GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public
     16 # License along with GNU Taler; see the file COPYING.  If not,
     17 # see <http://www.gnu.org/licenses/>
     18 #
     19 #  @author Florian Dold
     20 #  @file Standalone script to run the blog.
     21 
     22 import click
     23 import logging
     24 import sys
     25 import os
     26 from .util.talerconfig import TalerConfig
     27 
     28 import importlib
     29 import gunicorn.app.base
     30 
     31 logger = logging.getLogger(__name__)
     32 
     33 def bindspec(config, which_shop, port):
     34     confsection = f"frontend-demo-{which_shop}"
     35 
     36     # Takes precedence.
     37     if port:
     38         http_serve = "tcp"
     39     else:
     40         http_serve = (
     41             config[confsection]["http_serve"]
     42             .value_string(required=False, default="tcp")
     43             .lower()
     44         )
     45 
     46     if http_serve == "tcp":
     47         port_launch = (
     48             config[confsection]["http_port"].value_int(required=False)
     49             if not port
     50             else port
     51         )
     52         if not port_launch:
     53             print("Port number wasn't found in config and in arguments.", file=sys.stderr)
     54             exit(1)
     55         return dict(bind=f"0.0.0.0:{port_launch}")
     56 
     57     if http_serve == "unix":
     58         path = config[confsection]["http_unixpath"].value_filename(required=True)
     59         mode = config[confsection]["http_unixpath_mode"].value_filename(required=True)
     60         return dict(bind=f"unix:{path}", umask=mode)
     61 
     62 
     63 def number_of_workers(config, which_shop):
     64     confsection = f"frontend-demo-{which_shop}"
     65     nw = config[confsection]["num_workers"].value_int(required=False)
     66     if nw is None:
     67         # Be conservative with number of workers
     68         return 2
     69     else:
     70         return nw
     71 
     72 
     73 class StandaloneApplication(gunicorn.app.base.BaseApplication):
     74 
     75     def __init__(self, app, options=None):
     76         self.options = options or {}
     77         self.application = app
     78         super().__init__()
     79 
     80     def load_config(self):
     81         config = {
     82             key: value
     83             for key, value in self.options.items()
     84             if key in self.cfg.settings and value is not None
     85         }
     86         for key, value in config.items():
     87             self.cfg.set(key.lower(), value)
     88 
     89     def load(self):
     90         return self.application
     91 
     92 
     93 @click.command("Global shop launcher")
     94 @click.option("-c", "--config", 'config_filename', help="Configuration file", required=False)
     95 @click.option(
     96     "--http-port",
     97     help="HTTP port to serve (if not given, serving comes from config)",
     98     required=False,
     99     type=int,
    100 )
    101 @click.argument("which-shop")
    102 def demos(config_filename, http_port, which_shop):
    103     """WHICH_SHOP is one of: blog, donations, or landing."""
    104 
    105     logging.basicConfig(level=logging.INFO)
    106 
    107     if which_shop not in ["blog", "donations", "landing"]:
    108         print("Please use a valid shop name: blog, donations, landing.")
    109         sys.exit(1)
    110     config = TalerConfig.from_file(config_filename)
    111     options = {
    112         "workers": number_of_workers(config, which_shop),
    113         **bindspec(config, which_shop, http_port),
    114     }
    115     mod = f"talermerchantdemos.{which_shop}"
    116     os.environ["TALER_CONFIG_FILENAME"] = config_filename or ""
    117     app = importlib.import_module(mod).app
    118     StandaloneApplication(app, options).run()
    119 
    120 
    121 def run():
    122     demos()
    123 
    124 if __name__ == "__main__":
    125     run()