You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.8 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using IPA.JsonConverters;
  5. using IPA.Utilities;
  6. using Newtonsoft.Json;
  7. using Newtonsoft.Json.Linq;
  8. using SemVer;
  9. using Version = SemVer.Version;
  10. namespace IPA.Updating.BeatMods
  11. {
  12. class ApiEndpoint
  13. {
  14. public const string BeatModBase = "https://beatmods.com";
  15. public const string ApiBase = BeatModBase + "/api/v1/mod";
  16. public const string GetModInfoEndpoint = "?name={0}&version={1}";
  17. public const string GetModsByName = "?name={0}";
  18. class HexArrayConverter : JsonConverter
  19. {
  20. public override bool CanConvert(Type objectType)
  21. {
  22. return objectType == typeof(byte[]);
  23. }
  24. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  25. {
  26. if (reader.TokenType == JsonToken.Null)
  27. {
  28. return null;
  29. }
  30. if (reader.TokenType == JsonToken.String)
  31. {
  32. try
  33. {
  34. return Utils.StringToByteArray((string)reader.Value);
  35. }
  36. catch (Exception ex)
  37. {
  38. throw new Exception($"Error parsing version string: {reader.Value}", ex);
  39. }
  40. }
  41. throw new Exception(
  42. $"Unexpected token or value when parsing hex string. Token: {reader.TokenType}, Value: {reader.Value}");
  43. }
  44. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  45. {
  46. if (value == null)
  47. {
  48. writer.WriteNull();
  49. }
  50. else
  51. {
  52. if (!(value is byte[]))
  53. {
  54. throw new JsonSerializationException("Expected byte[] object value");
  55. }
  56. writer.WriteValue(Utils.ByteArrayToString((byte[]) value));
  57. }
  58. }
  59. }
  60. class ModMultiformatJsonConverter : JsonConverter<Mod>
  61. {
  62. public override Mod ReadJson(JsonReader reader, Type objectType, Mod existingValue, bool hasExistingValue, JsonSerializer serializer)
  63. {
  64. if (reader.TokenType == JsonToken.String)
  65. return new Mod { Id = reader.Value as string, IsIdReference = true };
  66. else
  67. {
  68. if (reader.TokenType != JsonToken.StartObject)
  69. return null;
  70. return serializer.Deserialize<Mod>(reader);
  71. }
  72. }
  73. public override void WriteJson(JsonWriter writer, Mod value, JsonSerializer serializer) => serializer.Serialize(writer, value);
  74. }
  75. [Serializable]
  76. public class Mod
  77. {
  78. #pragma warning disable CS0649
  79. /// <summary>
  80. /// Will be a useless string of characters. Do not use.
  81. /// </summary>
  82. [JsonProperty("_id")]
  83. public string Id;
  84. [JsonIgnore]
  85. public bool IsIdReference = false;
  86. [JsonProperty("required")]
  87. public bool Required;
  88. [JsonProperty("name")]
  89. public string Name;
  90. [JsonProperty("version"),
  91. JsonConverter(typeof(SemverVersionConverter))]
  92. public Version Version;
  93. [JsonProperty("gameVersion"),
  94. JsonConverter(typeof(AlmostVersionConverter))]
  95. public AlmostVersion GameVersion;
  96. [Serializable]
  97. public class AuthorType
  98. {
  99. [JsonProperty("username")]
  100. public string Name;
  101. [JsonProperty("_id")]
  102. public string Id;
  103. public override string ToString() => Name;
  104. }
  105. [JsonProperty("author")]
  106. public AuthorType Author;
  107. [JsonProperty("status")]
  108. public string Status;
  109. public const string ApprovedStatus = "approved";
  110. [JsonProperty("description")]
  111. public string Description;
  112. [JsonProperty("category")]
  113. public string Category;
  114. [JsonProperty("link")]
  115. public Uri Link;
  116. #pragma warning restore CS0649
  117. [Serializable]
  118. public class DownloadsObject
  119. {
  120. public const string TypeUniversal = "universal";
  121. public const string TypeSteam = "steam";
  122. public const string TypeOculus = "oculus";
  123. [JsonProperty("type")]
  124. public string Type;
  125. [JsonProperty("url")]
  126. public string Path;
  127. [Serializable]
  128. public class HashObject
  129. {
  130. [JsonProperty("hash"), JsonConverter(typeof(HexArrayConverter))]
  131. public byte[] Hash;
  132. [JsonProperty("file")]
  133. public string File;
  134. }
  135. /// <summary>
  136. /// Hashes stored are MD5
  137. /// </summary>
  138. [JsonProperty("hashMd5")]
  139. public HashObject[] Hashes;
  140. }
  141. [JsonProperty("downloads")]
  142. public DownloadsObject[] Downloads;
  143. [JsonProperty("dependencies", ItemConverterType = typeof(ModMultiformatJsonConverter))]
  144. public Mod[] Dependencies;
  145. public override string ToString()
  146. {
  147. return $"{{\"{Name}\"v{Version} by {Author} files for {string.Join(", ", Downloads.Select(d => d.Type))}}}";
  148. }
  149. }
  150. }
  151. }