# 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
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)
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
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
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
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
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)
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
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
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
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
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
super APIRouter
init do
- use("/inheritance/:id", new APIInheritanceGraph(model, mainmodule))
+ use("/inheritance/:id", new APIInheritanceGraph(config))
end
end
# 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
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))
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))
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
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)
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
# 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
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
# 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
# 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
#
# 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
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