// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.Json.Serialization; using EpicGames.Core; using HordeServer.Utilities; using Microsoft.AspNetCore.Mvc; namespace HordeServer.Server { /// /// Controller for the /api/v1/schema endpoint /// [ApiController] [Route("[controller]")] public class SchemaController : ControllerBase { class CatalogItem { public string? Name { get; set; } public string? Description { get; set; } public string[]? FileMatch { get; set; } public Uri? Url { get; set; } } class CatalogRoot { [JsonPropertyName("$schema")] public string Schema { get; set; } = "https://json.schemastore.org/schema-catalog.json"; public int Version { get; set; } = 1; public List Schemas { get; set; } = new List(); } /// /// Array of types included in the schema /// public static Type[] ConfigSchemas { get; } = FindSchemaTypes(); readonly JsonSchemaCache _schemaCache; /// /// Constructor /// public SchemaController(JsonSchemaCache schemaCache) { _schemaCache = schemaCache; } static Type[] FindSchemaTypes() { List schemaTypes = new List(); foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (Type type in assembly.GetTypes()) { if (type.GetCustomAttribute() != null) { schemaTypes.Add(type); } } } return schemaTypes.ToArray(); } /// /// Get the catalog for config schema /// /// Information about all the schedules [HttpGet] [Route("/api/v1/schema/catalog.json")] public ActionResult GetCatalog() { CatalogRoot root = new CatalogRoot(); foreach (Type schemaType in ConfigSchemas) { JsonSchemaAttribute? schemaAttribute = schemaType.GetCustomAttribute(); if (schemaAttribute != null) { JsonSchemaCatalogAttribute? catalogAttribute = schemaType.GetCustomAttribute(); if (catalogAttribute != null) { Uri url = new Uri($"{Request.Scheme}://{Request.Host}/api/v1/schema/types/{schemaType.Name}.json"); root.Schemas.Add(new CatalogItem { Name = catalogAttribute.Name, Description = catalogAttribute.Description, FileMatch = catalogAttribute.FileMatch, Url = url }); } } } return Ok(root); } /// /// Gets a specific schema /// /// The type name /// [HttpGet] [Route("/api/v1/schema/types/{typeName}.json")] public ActionResult GetSchema(string typeName) { foreach (Type schemaType in ConfigSchemas) { if (schemaType.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase)) { JsonSchema schema = _schemaCache.CreateSchema(schemaType); using MemoryStream stream = new MemoryStream(); schema.Write(stream); return new FileContentResult(stream.ToArray(), "application/json"); } } return NotFound(); } } }