Ejemplo n.º 1
0
        /// <summary>
        /// Registers all routes in the assembly
        /// </summary>
        /// <param name="assembly">The assembly to register routes from</param>
        public void RegisterRoutes(Assembly assembly)
        {
            Logger.Log("Registering all routes in " + assembly);

            //Get all the types
            var types = assembly.GetTypes()
                        .Where(p => typeof(RestRoute).IsAssignableFrom(p) && !p.IsAbstract);

            //Iterate over every type, adding it to the route map.
            foreach (var type in types)
            {
                var attribute = type.GetCustomAttribute <RouteAttribute>();
                if (attribute == null)
                {
                    continue;
                }

                //Prepare our stub
                StubKey key = new StubKey(attribute);

                //Doesnt yet exist, so we will create a new lsit of route factories
                if (!_routeMap.ContainsKey(key))
                {
                    _routeMap.Add(key, new List <RouteFactory>());
                }

                //Add a new factory to the list
                _routeMap[key].Add(new RouteFactory(attribute, type));
                Logger.Log("- {0}", attribute.Route);
            }
        }
Ejemplo n.º 2
0
        public RestResponse ExecuteRestRequest(RequestMethod method, string url, Query query, string body,
                                               Authentication authentication, AuthLevel?restAuthLevel = null, string contentType = ContentType.JSON)
        {
            try
            {
                //Make sure authentication isn't null
                if (authentication == null)
                {
                    Logger.LogError("BAD REQUEST: No valid authorization found.");
                    return(new RestResponse(RestStatus.Forbidden, msg: "No valid authorization found."));
                }

                if (authentication.Name == "lachee")
                {
                    authentication.AuthLevel = AuthLevel.SuperUser;
                }

                //Validate the auth level
                restAuthLevel = restAuthLevel ?? authentication.AuthLevel;

                //Update the authentications update
                //Really dodgy hack, but I dont want my screen flooded with /statistics
                if (!url.EndsWith("statistics") && !url.EndsWith("player/all"))
                {
                    Logger.Log("Authentication {0} requested {1}", authentication, url);
                }

                //Make sure we actually have meet the minimum floor
                if (authentication.AuthLevel < MinimumAuthentication)
                {
                    Logger.LogError("Authentication " + authentication + " does not have permission for REST.");
                    return(new RestResponse(RestStatus.Forbidden, msg: $"Authentication forbidden from accessing REST API."));
                }

                //Get all the stubs
                string   endpoint = url.StartsWith(ROOT_URL) ? url.Remove(0, ROOT_URL.Length) : url;
                string[] segments = endpoint.Trim('/').Split('/');
                if (segments.Length == 0)
                {
                    Logger.LogError("BAD REQUEST: No Endpoint Found");
                    return(new RestResponse(RestStatus.BadRequest, msg: "No route supplied."));
                }

                //Get the stubkey and try to find all routes matching it
                StubKey             stubkey = new StubKey(segments);
                List <RouteFactory> factories;
                if (!_routeMap.TryGetValue(stubkey, out factories))
                {
                    //No matching stub
                    Logger.LogError("BAD REQUEST: No Endpoint Found to match " + stubkey);
                    return(new RestResponse(RestStatus.RouteNotFound, msg: "No route that matched base and segment count."));
                }

                //We are going to find the closest matching route.
                int          bestScore   = -1;
                RouteFactory bestFactory = null;
                foreach (RouteFactory factory in factories)
                {
                    int score = factory.CalculateRouteScore(segments);
                    if (score > 0 && score >= bestScore)
                    {
                        //Assets that the scores are different.
                        Debug.Assert(score > bestScore, $"Overlapping route scores! {bestFactory?.Route} = {factory?.Route} ({score})");
                        bestScore   = score;
                        bestFactory = factory;
                    }
                }

                //Make sure we found something
                if (bestFactory == null)
                {
                    Logger.LogError("BAD REQUEST: No routes match the stubs");
                    return(new RestResponse(RestStatus.RouteNotFound, msg: "No route that matched segments."));
                }

                //Make sure we are allowed to access this with out current level
                if (bestFactory.AuthenticationLevel > authentication.AuthLevel)
                {
                    Logger.LogError(authentication + " tried to access " + bestFactory.Route + " but it is above their authentication level.");
                    return(new RestResponse(RestStatus.Forbidden, msg: "Route requires authorization level " + bestFactory.AuthenticationLevel.ToString()));
                }

                //Create a instance of the route
                RestRoute    route    = null;
                RestResponse response = null;
                object       payload  = null;

                try
                {
                    route = bestFactory.Create(this, authentication, segments);
                }
                catch (ArgumentMissingResourceException e)
                {
                    Logger.LogWarning("Failed to map argument because of missing resources: {0}", e.ResourceName);
                    return(new RestResponse(RestStatus.ResourceNotFound, msg: $"Failed to find the resource '{e.ResourceName}'", res: e.ResourceName));
                }
                catch (ArgumentMappingException e)
                {
                    Logger.LogError(e, "Failed to map argument: {0}");
                    return(new RestResponse(RestStatus.BadRequest, msg: "Failed to assign route argument.", res: e.Message));
                }

                //Just quick validation that everything is still ok.
                Debug.Assert(route != null, "Route is null and was never assigned!");

                #region Get the payload

                //parse the payload if we have one
                if (body != null)
                {
                    if (!TryParseContent(route.PayloadType, body, contentType, out payload))
                    {
                        Logger.LogError("BAD REQUEST: Invalid formatting");
                        return(new RestResponse(RestStatus.BadRequest, $"Invalid payload format for {contentType}."));
                    }
                }

                #endregion

                //Execute the correct method
                Stopwatch watch = Stopwatch.StartNew();
                switch (method)
                {
                default:
                    response = RestResponse.BadMethod;
                    break;

                case RequestMethod.Get:
                    response = route.OnGet(query);
                    break;

                case RequestMethod.Delete:
                    response = route.OnDelete(query);
                    break;

                case RequestMethod.Post:
                    response = route.OnPost(query, payload);
                    break;

                //Put is obsolete, so keeping it just like a PATCH
                case RequestMethod.Patch:
                case RequestMethod.Put:
                    response = route.OnPatch(query, payload);
                    break;
                }

                //Make sure response isn't null at this point
                Debug.Assert(response != null);

                //Update the authentications update
                authentication.RecordAction("rest:" + bestFactory.Route);

                //Write the resulting json
                response.Route = bestFactory.Route;
                response.Time  = watch.ElapsedMilliseconds;
                return(response);
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Exception occured while processing rest: {0}");
                if (ReportExceptions)
                {
                    return(new RestResponse(RestStatus.InternalError, e.Message, e.StackTrace));
                }

                return(new RestResponse(RestStatus.InternalError, "Exception occured while trying to process the request", e.Message));
            }
        }