internal static RemoteAssemblyState ParseFromManifestRow(RemoteAssemblyManifest manifest, string line) { string[] columns = line.Split(','); if (columns.Length < 11) { return(null); } string id = columns[0].Trim(); string url = columns[1].Trim(); string directoryName = columns[2].Trim(); string isStable = columns[3].Trim(); string wasExplicitVersionRequest = columns[4].Trim(); string lastUsedTimestampRaw = columns[5].Trim(); string lastLatestCheckRaw = columns[6].Trim(); string hasCni = columns[7].Trim(); string isDllDownloaded = columns[8].Trim(); string[] platformsRaw = columns[9].Split('|').Select(s => s.Trim()).Where(s => s.Length > 0).ToArray(); string[] platforms = platformsRaw.Select(s => s[0] == '*' ? s.Substring(1) : s).ToArray(); bool[] platformIsDownloaded = platformsRaw.Select(s => s[0] == '*').ToArray(); string version = columns[10]; for (int i = 11; i < columns.Length; ++i) { version += "," + columns[i]; } version = version.Trim(); int lastUsedTimestamp; int lastLatestCheck; if (!int.TryParse(lastUsedTimestampRaw, out lastUsedTimestamp) || !int.TryParse(lastLatestCheckRaw, out lastLatestCheck)) { return(null); } RemoteAssemblyState ras = new RemoteAssemblyState(manifest) { Id = id, LastUsed = lastUsedTimestamp, LastLatestCheck = lastLatestCheck, LocalDirectory = directoryName, Url = url, Version = version, IsLatestStable = wasExplicitVersionRequest == "1", IsStable = isStable == "1", HasCni = hasCni == "1", RuntimeIsDownloaded = isDllDownloaded == "1", }; for (int i = 0; i < platforms.Length; ++i) { ras.platformsSupportedAndCurrentSyncState[platforms[i]] = platformIsDownloaded[i]; } return(ras); }
private RemoteAssemblyState PerformSyncImpl(RemoteAssemblyManifest manifest, string libraryUrl, string libraryVersionOrNullForLatest, bool isRequired) { string fullStructuredUrl = libraryVersionOrNullForLatest == null ? libraryUrl : (libraryUrl + ":" + libraryVersionOrNullForLatest); Pair<FetchAssemblyStatus, RemoteAssemblyState> t = new RemoteAssemblyFetcher().FetchNewAssembly(manifest, fullStructuredUrl); switch (t.First) { case FetchAssemblyStatus.NO_CONNECTION: case FetchAssemblyStatus.SERVER_NOT_RESPONDING: case FetchAssemblyStatus.UNKNOWN_RESPONSE: if (isRequired) { throw new System.InvalidOperationException("Could not sync required dependency: " + libraryUrl); } return null; case FetchAssemblyStatus.INVALID_URL: throw new System.InvalidOperationException("Invalid remote library URL: " + libraryUrl); case FetchAssemblyStatus.LIBRARY_NOT_FOUND: throw new System.InvalidOperationException("Remote Library not found: " + libraryUrl); case FetchAssemblyStatus.VERSION_NOT_FOUND: if (isRequired) { throw new System.InvalidOperationException("Remote Library version not found: " + libraryUrl); } else { // This could happen if the library was taken down by the provider } return null; case FetchAssemblyStatus.SUCCESS: manifest.AddOrReplaceAssemblyState(t.Second); return t.Second; default: throw new System.NotImplementedException(); // this should not happen. } }
public Pair <FetchAssemblyStatus, RemoteAssemblyState> FetchNewAssembly(RemoteAssemblyManifest manifest, string urlAndVersion) { RemoteAssemblyUrl structuredUrl = RemoteAssemblyUrl.FromUrl(urlAndVersion); if (!structuredUrl.IsValid) { return(new Pair <FetchAssemblyStatus, RemoteAssemblyState>(FetchAssemblyStatus.INVALID_URL, null)); } HttpRequest requestSender = new HttpRequest("GET", structuredUrl.Url) .SetHeader("CrayonLib-Component-Type", "source") .SetHeader("User-Agent", Common.VersionInfo.UserAgent); if (!structuredUrl.IsLatestStableVersionRequested) { requestSender.SetHeader("CrayonLib-Version-Info", structuredUrl.VersionInfo); } HttpResponse response = requestSender.Send(); Pair <FetchAssemblyStatus, RemoteAssemblyState> error = CheckForBasicErrors(response, structuredUrl.LibraryName); if (error != null) { return(error); } string versionInfo = response.GetHeader("CrayonLib-Version-Info"); // Not used. Not sure why this is returned. // string componentType = response.GetHeader("CrayonLib-Component-Type"); bool hasNativeInterface = response.GetHeaderAsBoolean("CrayonLib-Has-Native-Interface"); string[] platformsSupported = response.GetHeaderAsList("CrayonLib-Platforms-Supported"); string libraryName = response.GetHeader("CrayonLib-Library-Name"); bool isStable = response.GetHeaderAsBoolean(("CrayonLib-Is-Stable")); string directoryName = this.CreateNewDirectoryForLibrary(manifest.Directory, libraryName, versionInfo); byte[] crypkg = response.Content; CryPkgDecoder crypkgDecoder = new CryPkgDecoder(response.Content); // TODO: crypkgDecoder.IsValid this.ExpandCryPkgToDirectory(crypkgDecoder, Path.Join(manifest.Directory, directoryName, libraryName)); int now = CommonUtil.DateTime.Time.UnixTimeNow; RemoteAssemblyState ras = new RemoteAssemblyState(manifest) { HasCni = hasNativeInterface, Id = libraryName, IsStable = isStable, IsLatestStable = structuredUrl.IsLatestStableVersionRequested, LastUsed = now, LastLatestCheck = now, LocalDirectory = directoryName, RuntimeIsDownloaded = false, Url = structuredUrl.Url, Version = versionInfo, }; foreach (string platformSupported in platformsSupported) { ras.IndicatePlatformSupport(platformSupported); } return(new Pair <FetchAssemblyStatus, RemoteAssemblyState>(FetchAssemblyStatus.SUCCESS, ras)); }
private RemoteAssemblyState PerformSyncForOptionalRefresh(RemoteAssemblyManifest manifest, string libraryUrl) { return PerformSyncImpl(manifest, libraryUrl, null, false); }
private RemoteAssemblyState PerformSyncForMissingAssembly(RemoteAssemblyManifest manifest, string libraryUrl, string libraryVersionOrNullForLatest) { return PerformSyncImpl(manifest, libraryUrl, libraryVersionOrNullForLatest, true); }
public IList<AssemblyMetadata> GetRemoteAssemblies(string[] urlsAndVersionInfo) { Dictionary<string, AssemblyMetadata> assemblies = new Dictionary<string, AssemblyMetadata>(); if (urlsAndVersionInfo == null || urlsAndVersionInfo.Length == 0) return new AssemblyMetadata[0]; RemoteAssemblyManifest manifest = new RemoteAssemblyManifest(); List<string[]> librariesMissing = new List<string[]>(); List<RemoteAssemblyState> librariesThatMightNeedRefresh = new List<RemoteAssemblyState>(); bool anyLibrariesWereMissing = false; List<RemoteAssemblyState> usedAssemblies = new List<RemoteAssemblyState>(); foreach (string info in urlsAndVersionInfo) { string[] parts = StringUtil.SplitOnce(info, ","); string url = parts[0]; string version = null; if (parts.Length == 2) { version = parts[1] == "LATEST" ? null : parts[1]; } bool isLatestStableRequested = version == null; RemoteAssemblyState currentState = manifest.GetAssemblyState(url, version); if (currentState == null) { currentState = PerformSyncForMissingAssembly(manifest, url, version); if (currentState == null) throw new System.Exception(); // all code paths that return null from the above function should have thrown a proper error message exception. anyLibrariesWereMissing = true; usedAssemblies.Add(currentState); } else if (isLatestStableRequested) { librariesThatMightNeedRefresh.Add(currentState); } else { usedAssemblies.Add(currentState); } } int now = CommonUtil.DateTime.Time.UnixTimeNow; int ageToDefinitelySync = 7 * 24 * 3600; int expiration = now - ageToDefinitelySync; bool refreshNeeded = anyLibrariesWereMissing || librariesThatMightNeedRefresh.Where(lib => lib.LastLatestCheck < expiration).FirstOrDefault() != null; if (refreshNeeded) { foreach (RemoteAssemblyState lib in librariesThatMightNeedRefresh) { RemoteAssemblyState nullableNewLib = PerformSyncForOptionalRefresh(manifest, lib.Url); usedAssemblies.Add(nullableNewLib ?? lib); } } else { usedAssemblies.AddRange(librariesThatMightNeedRefresh); } foreach (RemoteAssemblyState ras in usedAssemblies) { ras.LastUsed = now; } manifest.ReserializeFile(); foreach (RemoteAssemblyState ras in usedAssemblies) { assemblies.Add(ras.Id, new AssemblyMetadata(ras.AbsolutePathToLibrary, ras.Id)); } return assemblies.Values.ToArray(); }
internal RemoteAssemblyState(RemoteAssemblyManifest remoteAssemblyManifest) { this.remoteAssemblyManifest = remoteAssemblyManifest; }