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 IList <RemoteAssemblyState> Parse() { string manifestFile = this.ManifestFilePath; if (!File.Exists(manifestFile)) { return(new RemoteAssemblyState[0]); } int now = CommonUtil.DateTime.Time.UnixTimeNow; List <RemoteAssemblyState> remoteAssemblies = new List <RemoteAssemblyState>(); List <string> invalidLines = new List <string>(); foreach (string line in File.ReadLines(manifestFile)) { string trimmedLine = line.Trim(); if (trimmedLine.Length > 0) { RemoteAssemblyState state = RemoteAssemblyState.ParseFromManifestRow(this, trimmedLine); if (state == null) { invalidLines.Add(line); } else { string outermostPath = Path.Join(this.Directory, state.LocalDirectory); if (FileUtil.DirectoryExists(outermostPath)) { if (FileUtil.FileExists(Path.Join(state.AbsolutePathToLibrary, "manifest.json")) && now - state.LastUsed < DELETE_ASSEMBLIES_THAT_HAVENT_BEEN_USED_IN_THIS_MANY_DAYS * 24 * 3600) { remoteAssemblies.Add(state); } else { FileUtil.DirectoryDelete(outermostPath); } } } } } foreach (string line in invalidLines) { Common.ConsoleWriter.Print(ConsoleMessageType.REMOTE_ASSEMBLY_ERROR, "Invalid assembly in manifest! Ignoring: " + line); } return(remoteAssemblies); }
internal void AddOrReplaceAssemblyState(RemoteAssemblyState assembly) { bool alreadyExists = false; foreach (RemoteAssemblyState existingAssembly in this.remoteAssemblies.Where(a => a.Url == assembly.Url)) { if (existingAssembly.Version == assembly.Version) { alreadyExists = true; existingAssembly.IsLatestStable = assembly.IsLatestStable; existingAssembly.IsStable = assembly.IsStable; } else if (assembly.IsLatestStable) { existingAssembly.IsLatestStable = false; } } if (!alreadyExists) { this.remoteAssemblies.Add(assembly); } }
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)); }
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(); }