{"action":"created","issue":{"url":"https://api.github.com/repos/Rychard/CityWebServer/issues/5","labels_url":"https://api.github.com/repos/Rychard/CityWebServer/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/Rychard/CityWebServer/issues/5/comments","events_url":"https://api.github.com/repos/Rychard/CityWebServer/issues/5/events","html_url":"https://github.com/Rychard/CityWebServer/pull/5","id":67281351,"number":5,"title":"Plugin loader","user":{"login":"nezroy","id":1255873,"avatar_url":"https://avatars.githubusercontent.com/u/1255873?v=3","gravatar_id":"","url":"https://api.github.com/users/nezroy","html_url":"https://github.com/nezroy","followers_url":"https://api.github.com/users/nezroy/followers","following_url":"https://api.github.com/users/nezroy/following{/other_user}","gists_url":"https://api.github.com/users/nezroy/gists{/gist_id}","starred_url":"https://api.github.com/users/nezroy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nezroy/subscriptions","organizations_url":"https://api.github.com/users/nezroy/orgs","repos_url":"https://api.github.com/users/nezroy/repos","events_url":"https://api.github.com/users/nezroy/events{/privacy}","received_events_url":"https://api.github.com/users/nezroy/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-04-09T05:00:46Z","updated_at":"2015-04-17T06:03:54Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/Rychard/CityWebServer/pulls/5","html_url":"https://github.com/Rychard/CityWebServer/pull/5","diff_url":"https://github.com/Rychard/CityWebServer/pull/5.diff","patch_url":"https://github.com/Rychard/CityWebServer/pull/5.patch"},"body":"This is an overhaul of the way the extensibility layer works based on my needs trying to create an extension for the web server.\r\n\r\nRather than using reflection on assemblies, the plugin loader looks through the user mods in the ColossalFramework PluginManager and picks out those implementing the ICityWebPlugin interface (some reflection is still required to do this consistently). Valid plugins are then loaded under unique ID's which make up the base of all of their URL's. Each plugin can implement any number of request handlers under its unique URL path (e.g. the plugin with the unique ID of \"sample\" can only handle requests under an absolute path of \"/sample/*\").\r\n\r\nIn addition to the updated plugin loader arch, several related changes were also made. The default request handler will look for a \"wwwroot\" path under each ICityWebPlugin's mod path. If the request URL is in the plugin's path but is not handled by any of its request handlers, the default handler will attempt to serve a matching static file from the plugin's wwwroot.\r\n\r\nThe template system was cleaned up a bit and made more generic so it can be used by plugins. Additionally, registered plugins can opt to show up in the top menu nav area. The default template for index was also updated slightly to reflect this, and a new matching template added for the log page.\r\n\r\nCore services were moved into three fake/default plugins (Root, Log, and API) in order to leverage this system. In theory, with a simple change to the plugin loader logic (last loaded wins instead of first loaded wins), these default plugins could become replaceable by custom implementations defined in extensions. As a result of this change, the API endpoints have moved from living under the / URL path to the /api/ URL path (as \"api\" is that plugin's unique slug/ID). The sample extension project has likewise been updated to use this system."},"comment":{"url":"https://api.github.com/repos/Rychard/CityWebServer/issues/comments/93900660","html_url":"https://github.com/Rychard/CityWebServer/pull/5#issuecomment-93900660","issue_url":"https://api.github.com/repos/Rychard/CityWebServer/issues/5","id":93900660,"user":{"login":"nezroy","id":1255873,"avatar_url":"https://avatars.githubusercontent.com/u/1255873?v=3","gravatar_id":"","url":"https://api.github.com/users/nezroy","html_url":"https://github.com/nezroy","followers_url":"https://api.github.com/users/nezroy/followers","following_url":"https://api.github.com/users/nezroy/following{/other_user}","gists_url":"https://api.github.com/users/nezroy/gists{/gist_id}","starred_url":"https://api.github.com/users/nezroy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nezroy/subscriptions","organizations_url":"https://api.github.com/users/nezroy/orgs","repos_url":"https://api.github.com/users/nezroy/repos","events_url":"https://api.github.com/users/nezroy/events{/privacy}","received_events_url":"https://api.github.com/users/nezroy/received_events","type":"User","site_admin":false},"created_at":"2015-04-17T06:03:54Z","updated_at":"2015-04-17T06:03:54Z","body":"OK I've pushed some new commits that add support for \"naked\" handlers (essentially the original approach, minus the GUID and adding fetching them via loaded plugins rather than AppDomain). This co-exists alongside the new CityWebMod style; extensions can use either approach. I've split the sample project into two to demonstrate both methods.\r\n\r\nLesser stuff includes cleaned up style throughout, added an API endpoint listing to the default APICWM page, and a new HandlerCWM that not only acts as the container for naked handlers but also provides a listing of them (replacing the list that used to show up on the index page)."}}