nitweb: use config file
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 9 Aug 2016 01:49:55 +0000 (21:49 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Wed, 10 Aug 2016 19:46:25 +0000 (15:46 -0400)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/nitweb.nit
src/web/api_catalog.nit
src/web/api_docdown.nit
src/web/api_feedback.nit
src/web/api_graph.nit
src/web/api_metrics.nit
src/web/api_model.nit
src/web/web_base.nit

index 3f3b7f5..9376172 100644 (file)
 # Runs a webserver based on nitcorn that render things from model.
 module nitweb
 
+import popcorn::pop_config
 import frontend
 import web
 
 redef class ToolContext
 
-       # Host name to bind on.
+       # Path to app config file.
+       var opt_config = new OptionString("Path to app config file", "--config")
+
+       # Host name to bind on (will overwrite the config one).
        var opt_host = new OptionString("Host to bind the server on", "--host")
 
-       # Port number to bind on.
-       var opt_port = new OptionInt("Port number to use", 3000, "--port")
+       # Port number to bind on (will overwrite the config one).
+       var opt_port = new OptionInt("Port number to use", -1, "--port")
 
        # Web rendering phase.
        var webphase: Phase = new NitwebPhase(self, null)
 
        init do
                super
-               option_context.add_option(opt_host, opt_port)
+               option_context.add_option(opt_config, opt_host, opt_port)
        end
 end
 
@@ -39,6 +43,22 @@ end
 private class NitwebPhase
        super Phase
 
+       # Build the nitweb config from `toolcontext` options.
+       fun build_config(toolcontext: ToolContext, mainmodule: MModule): NitwebConfig do
+               var config_file = toolcontext.opt_config.value
+               if config_file == null then config_file = "nitweb.ini"
+               var config = new NitwebConfig(
+                       config_file,
+                       toolcontext.modelbuilder.model,
+                       mainmodule,
+                       toolcontext.modelbuilder)
+               var opt_host = toolcontext.opt_host.value
+               if opt_host != null then config["app.host"] = opt_host
+               var opt_port = toolcontext.opt_port.value
+               if opt_port >= 0 then config["app.port"] = opt_port.to_s
+               return config
+       end
+
        # Build the nit catalog used in homepage.
        fun build_catalog(model: Model, modelbuilder: ModelBuilder): Catalog do
                var catalog = new Catalog(modelbuilder)
@@ -63,25 +83,17 @@ private class NitwebPhase
        do
                var model = mainmodule.model
                var modelbuilder = toolcontext.modelbuilder
+               var config = build_config(toolcontext, mainmodule)
                var catalog = build_catalog(model, modelbuilder)
 
-               # Prepare mongo connection
-               var mongo = new MongoClient("mongodb://localhost:27017/")
-               var db = mongo.database("nitweb")
-               var collection = db.collection("stars")
-
-               # Run the server
-               var host = toolcontext.opt_host.value or else "localhost"
-               var port = toolcontext.opt_port.value
-
                var app = new App
 
                app.use_before("/*", new RequestClock)
-               app.use("/api", new NitwebAPIRouter(model, mainmodule, modelbuilder, catalog, stars))
+               app.use("/api", new NitwebAPIRouter(config, catalog))
                app.use("/*", new StaticHandler(toolcontext.share_dir / "nitweb", "index.html"))
                app.use_after("/*", new ConsoleLog)
 
-               app.listen(host, port.to_i)
+               app.listen(config.app_host, config.app_port)
        end
 end
 
@@ -89,30 +101,24 @@ end
 class NitwebAPIRouter
        super APIRouter
 
-       # ModelBuilder to pass to handlers.
-       var modelbuilder: ModelBuilder
-
        # Catalog to pass to handlers.
        var catalog: Catalog
 
-       # Mongo collection used to store ratings.
-       var collection: MongoCollection
-
        init do
-               use("/catalog", new APICatalogRouter(model, mainmodule, catalog))
-               use("/list", new APIList(model, mainmodule))
-               use("/search", new APISearch(model, mainmodule))
-               use("/random", new APIRandom(model, mainmodule))
-               use("/entity/:id", new APIEntity(model, mainmodule))
-               use("/code/:id", new APIEntityCode(model, mainmodule, modelbuilder))
-               use("/uml/:id", new APIEntityUML(model, mainmodule))
-               use("/linearization/:id", new APIEntityLinearization(model, mainmodule))
-               use("/defs/:id", new APIEntityDefs(model, mainmodule))
-               use("/feedback/", new APIFeedbackRouter(model, mainmodule, collection))
-               use("/inheritance/:id", new APIEntityInheritance(model, mainmodule))
-               use("/graph/", new APIGraphRouter(model, mainmodule))
-               use("/docdown/", new APIDocdown(model, mainmodule, modelbuilder))
-               use("/metrics/", new APIMetricsRouter(model, mainmodule))
+               use("/catalog", new APICatalogRouter(config, catalog))
+               use("/list", new APIList(config))
+               use("/search", new APISearch(config))
+               use("/random", new APIRandom(config))
+               use("/entity/:id", new APIEntity(config))
+               use("/code/:id", new APIEntityCode(config))
+               use("/uml/:id", new APIEntityUML(config))
+               use("/linearization/:id", new APIEntityLinearization(config))
+               use("/defs/:id", new APIEntityDefs(config))
+               use("/feedback/", new APIFeedbackRouter(config))
+               use("/inheritance/:id", new APIEntityInheritance(config))
+               use("/graph/", new APIGraphRouter(config))
+               use("/docdown/", new APIDocdown(config))
+               use("/metrics/", new APIMetricsRouter(config))
        end
 end
 
index 2535898..f0c70c6 100644 (file)
@@ -25,11 +25,11 @@ class APICatalogRouter
        var catalog: Catalog
 
        init do
-               use("/highlighted", new APICatalogHighLighted(model, mainmodule, catalog))
-               use("/required", new APICatalogMostRequired(model, mainmodule, catalog))
-               use("/bytags", new APICatalogByTags(model, mainmodule, catalog))
-               use("/contributors", new APICatalogContributors(model, mainmodule, catalog))
-               use("/stats", new APICatalogStats(model, mainmodule, catalog))
+               use("/highlighted", new APICatalogHighLighted(config, catalog))
+               use("/required", new APICatalogMostRequired(config, catalog))
+               use("/bytags", new APICatalogByTags(config, catalog))
+               use("/contributors", new APICatalogContributors(config, catalog))
+               use("/stats", new APICatalogStats(config, catalog))
        end
 end
 
@@ -68,7 +68,7 @@ class APICatalogStats
 
        redef fun get(req, res) do
                var obj = new JsonObject
-               obj["packages"] = model.mpackages.length
+               obj["packages"] = config.model.mpackages.length
                obj["maintainers"] = catalog.maint2proj.length
                obj["contributors"] = catalog.contrib2proj.length
                obj["modules"] = catalog.mmodules.sum
@@ -91,7 +91,7 @@ class APICatalogMostRequired
        redef fun get(req, res) do
                if catalog.deps.not_empty then
                        var reqs = new Counter[MPackage]
-                       for p in model.mpackages do
+                       for p in config.model.mpackages do
                                reqs[p] = catalog.deps[p].smallers.length - 1
                        end
                        res.json list_best(reqs)
index 3510b64..bf4c80f 100644 (file)
@@ -24,13 +24,10 @@ import doc_commands
 class APIDocdown
        super APIHandler
 
-       # Modelbuilder used by the commands
-       var modelbuilder: ModelBuilder
-
        # Specific Markdown processor to use within Nitweb
        var md_processor: MarkdownProcessor is lazy do
                var proc = new MarkdownProcessor
-               proc.emitter.decorator = new NitwebDecorator(view, modelbuilder)
+               proc.emitter.decorator = new NitwebDecorator(view, config.modelbuilder)
                return proc
        end
 
index e994bf6..76e9d67 100644 (file)
@@ -18,15 +18,38 @@ module api_feedback
 import web_base
 import mongodb
 
+redef class NitwebConfig
+
+       # MongoDB uri used for data persistence.
+       #
+       # * key: `mongo.uri`
+       # * default: `mongodb://localhost:27017/`
+       var mongo_uri: String is lazy do
+               return value_or_default("mongo.uri", "mongodb://localhost:27017/")
+       end
+
+       # MongoDB DB used for data persistence.
+       #
+       # * key: `mongo.db`
+       # * default: `nitweb`
+       var mongo_db: String is lazy do return value_or_default("mongo.db", "nitweb")
+
+       # Mongo instance
+       var mongo: MongoClient is lazy do return new MongoClient(mongo_uri)
+
+       # Database instance
+       var db: MongoDb is lazy do return mongo.database(mongo_db)
+
+       # MongoDB collection used to store stars.
+       var stars: MongoCollection is lazy do return db.collection("stars")
+end
+
 # Group all api handlers in one router
 class APIFeedbackRouter
        super APIRouter
 
-       # Mongo collection used to store ratings
-       var collection: MongoCollection
-
        init do
-               use("/stars/:id", new APIStars(model, mainmodule, collection))
+               use("/stars/:id", new APIStars(config))
        end
 end
 
@@ -34,9 +57,6 @@ end
 class APIStars
        super APIHandler
 
-       # Collection used to store ratings
-       var collection: MongoCollection
-
        redef fun get(req, res) do
                var mentity = mentity_from_uri(req, res)
                if mentity == null then
@@ -65,7 +85,7 @@ class APIStars
                end
 
                var val = new MEntityRating(mentity.full_name, rating, get_time)
-               collection.insert(val.json)
+               config.stars.insert(val.json)
 
                res.json mentity_ratings(mentity)
        end
@@ -76,7 +96,7 @@ class APIStars
 
                var req = new JsonObject
                req["mentity"] = mentity.full_name
-               var rs = collection.find_all(req)
+               var rs = config.stars.find_all(req)
                for r in rs do ratings.ratings.add new MEntityRating.from_json(r)
                return ratings
        end
index 06e6bf2..d58031d 100644 (file)
@@ -24,7 +24,7 @@ class APIGraphRouter
        super APIRouter
 
        init do
-               use("/inheritance/:id", new APIInheritanceGraph(model, mainmodule))
+               use("/inheritance/:id", new APIInheritanceGraph(config))
        end
 end
 
index 30a53f1..8d64c04 100644 (file)
@@ -19,16 +19,10 @@ import metrics
 
 # Group all api handlers in one router.
 class APIMetricsRouter
-       super Router
-
-       # Model to pass to handlers.
-       var model: Model
-
-       # Mainmodule to pass to handlers.
-       var mainmodule: MModule
+       super APIRouter
 
        init do
-               use("/structural/:id", new APIStructuralMetrics(model, mainmodule))
+               use("/structural/:id", new APIStructuralMetrics(config))
        end
 end
 
@@ -36,6 +30,7 @@ class APIStructuralMetrics
        super APIHandler
 
        private fun mclasses_metrics: MetricSet do
+               var mainmodule = config.mainmodule
                var metrics = new MetricSet
                metrics.register(new CNOA(mainmodule, view))
                metrics.register(new CNOP(mainmodule, view))
@@ -58,6 +53,7 @@ class APIStructuralMetrics
        end
 
        private fun mmodules_metrics: MetricSet do
+               var mainmodule = config.mainmodule
                var metrics = new MetricSet
                metrics.register(new MNOA(mainmodule, view))
                metrics.register(new MNOP(mainmodule, view))
index f8c6eeb..63fd636 100644 (file)
@@ -148,7 +148,7 @@ class APIEntityLinearization
                        res.error 404
                        return
                end
-               var lin = mentity.collect_linearization(mainmodule)
+               var lin = mentity.collect_linearization(config.mainmodule)
                if lin == null then
                        res.error 404
                        return
@@ -206,7 +206,7 @@ class APIEntityUML
                var dot
                if mentity isa MClassDef then mentity = mentity.mclass
                if mentity isa MClass then
-                       var uml = new UMLModel(view, mainmodule)
+                       var uml = new UMLModel(view, config.mainmodule)
                        dot = uml.generate_class_uml.write_to_string
                else if mentity isa MModule then
                        var uml = new UMLModel(view, mentity)
@@ -225,9 +225,6 @@ end
 class APIEntityCode
        super APIHandler
 
-       # Modelbuilder used to access sources.
-       var modelbuilder: ModelBuilder
-
        redef fun get(req, res) do
                var mentity = mentity_from_uri(req, res)
                if mentity == null then return
@@ -241,7 +238,7 @@ class APIEntityCode
 
        # Highlight `mentity` source code.
        private fun render_source(mentity: MEntity): nullable HTMLTag do
-               var node = modelbuilder.mentity2node(mentity)
+               var node = config.modelbuilder.mentity2node(mentity)
                if node == null then return null
                var hl = new HighlightVisitor
                hl.enter_visit node
index f48da04..c535936 100644 (file)
@@ -19,10 +19,11 @@ import model::model_views
 import model::model_json
 import doc_down
 import popcorn
+import popcorn::pop_config
 
-# Specific nitcorn Action that uses a Model
-class ModelHandler
-       super Handler
+# Nitweb config file.
+class NitwebConfig
+       super AppConfig
 
        # Model to use.
        var model: Model
@@ -30,6 +31,17 @@ class ModelHandler
        # MModule used to flatten model.
        var mainmodule: MModule
 
+       # Modelbuilder used to access sources.
+       var modelbuilder: ModelBuilder
+end
+
+# Specific nitcorn Action that uses a Model
+class ModelHandler
+       super Handler
+
+       # App config.
+       var config: NitwebConfig
+
        # Find the MEntity ` with `full_name`.
        fun find_mentity(model: ModelView, full_name: nullable String): nullable MEntity do
                if full_name == null then return null
@@ -38,7 +50,7 @@ class ModelHandler
 
        # Init the model view from the `req` uri parameters.
        fun init_model_view(req: HttpRequest): ModelView do
-               var view = new ModelView(model)
+               var view = new ModelView(config.model)
                var show_private = req.bool_arg("private") or else false
                if not show_private then view.min_visibility = protected_visibility
 
@@ -59,7 +71,7 @@ abstract class APIHandler
        #
        # So we can cache the model view.
        var view: ModelView is lazy do
-               var view = new ModelView(model)
+               var view = new ModelView(config.model)
                view.min_visibility = private_visibility
                view.include_fictive = true
                view.include_empty_doc = true
@@ -91,11 +103,8 @@ end
 class APIRouter
        super Router
 
-       # Model to use.
-       var model: Model
-
-       # MModule used to flatten model.
-       var mainmodule: MModule
+       # App config.
+       var config: NitwebConfig
 end
 
 redef class MEntity