internal static ulong GetManifestIDForDepot(uint DepotID) { lock (Lock) { ManualResetEvent Event = new ManualResetEvent(false); if (Depots is null) { Client.AppInfoReceived = (VDFStruct AppInfo) => { try { Depots = AppInfo["depots"]; } catch { } Event.Set(); }; Client.RequestAppInfo(); Event.WaitOne(5000); Event.Close(); if (Depots is null) { Client.Disconnect(); return(0UL); } } try { ulong ManifestID = ulong.Parse(Depots[DepotID.ToString()]["manifests"]["public"].Value); Log($"Resolved latest manifest ID for depot {DepotID}: {ManifestID}"); return(ManifestID); } catch { throw new ValidatorException("Failed to parse app info"); } } }
private async void VerificationJob() { try { string ACFFile = ACFPath; bool ACFExists = Exists(ACFFile); if (ACF is null && ACFExists) { using (StreamReader Reader = new StreamReader(ACFFile)) ACF = new VDFStruct(Reader); } for (; ModIndex < Mods.Length; ModIndex++) { Dispatcher.Invoke(() => ModStatus.Text = string.Format(LocString(LocCode.MFVerifying), ModIndex + 1, Mods.Length, Mods[ModIndex].Name)); ulong ID = Mods[ModIndex].ID, ManifestID = Downloader.UpdateMod(true, ID, ID); if (Finished) { return; } if (await TryDeployAsync()) { await SteamAPI.SubscribeModAsync(ID); } if (!ACFExists) { continue; } VDFStruct ItemsInstalled = ACF["WorkshopItemsInstalled"], ItemDetails = ACF["WorkshopItemDetails"], IIEntry = ItemsInstalled?[ID.ToString()], IDEntry = ItemDetails?[ID.ToString()]; ItemDetails Details = null; void GetItemDetails() { if (!(Details is null)) { return; } if (Connect()) { List <ItemDetails> Response = GetDetails(ID); if ((Response?.Count ?? 0) > 0) { Details = Response[0]; } } if (Details is null || Details.Result != 1) { throw new ValidatorException(LocString(LocCode.MIRequestFailed)); } } if (IIEntry is null) { ACFChanged = true; GetItemDetails(); IIEntry = new VDFStruct { Key = ID.ToString(), Children = new List <VDFStruct> { new VDFStruct { Key = "size", Value = Details.Size.ToString() }, new VDFStruct { Key = "timeupdated", Value = Details.LastUpdated.ToString() }, new VDFStruct { Key = "manifest", Value = ManifestID.ToString() } } }; if (ItemsInstalled != null) { ItemsInstalled.Children.Add(IIEntry); } } else if (!ulong.TryParse(IIEntry["manifest"].Value, out ulong MID) || MID != ManifestID) { ACFChanged = true; GetItemDetails(); IIEntry["size"].Value = Details.Size.ToString(); IIEntry["timeupdated"].Value = Details.LastUpdated.ToString(); IIEntry["manifest"].Value = ManifestID.ToString(); } if (IDEntry is null) { ACFChanged = true; GetItemDetails(); IDEntry = new VDFStruct { Key = ID.ToString(), Children = new List <VDFStruct> { new VDFStruct { Key = "manifest", Value = ManifestID.ToString() }, new VDFStruct { Key = "timeupdated", Value = Details.LastUpdated.ToString() }, new VDFStruct { Key = "timetouched", Value = Now.ToUnixTimeSeconds().ToString() }, new VDFStruct { Key = "subscribedby", Value = Steam.ActiveUserID.ToString() }, } }; if (ItemDetails != null) { ItemDetails.Children.Add(IDEntry); } } else if (!ulong.TryParse(IDEntry["manifest"].Value, out ulong MID) || MID != ManifestID) { ACFChanged = true; GetItemDetails(); IDEntry["manifest"].Value = ManifestID.ToString(); IDEntry["timeupdated"].Value = Details.LastUpdated.ToString(); IDEntry["timetouched"].Value = Steam.ActiveUserID.ToString(); } } await Dispatcher.Invoke(async() => { Finished = true; TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; ModStatus.Text = LocString(LocCode.MFVerificationComplete); if (ACFChanged) { SetStatus(LocString(LocCode.MFApplyingModifications), YellowBrush); if (!Steam.IsRunning) { using (StreamWriter Writer = new StreamWriter(ACFPath)) ACF.Write(Writer); } else if (ShowOptions("Info", LocString(LocCode.MFSteamRestartRequired))) { SetStatus(LocString(LocCode.WaitingForSteamShutdown), YellowBrush); Retract(); Start($@"{Steam.Path}\Steam.exe", "-shutdown").WaitForExit(); while (Steam.IsRunning) { await Delay(1000); } using (StreamWriter Writer = new StreamWriter(ACFPath)) ACF.Write(Writer); Start($@"{Steam.Path}\Steam.exe"); } } SetStatus(LocString(LocCode.MFSuccess), DarkGreen); Button.IsEnabled = false; }); } catch (Exception Exception) { Downloader.ReleaseLock(); if (Exception is AggregateException) { Exception = Exception.InnerException; } if (Exception is ValidatorException) { Dispatcher.Invoke(() => { SetStatus(string.Format(LocString(LocCode.ValidatorExc), Exception.Message), DarkRed); FinishHandler(); }); } else { WriteAllText($@"{AppDataFolder}\LastCrash.txt", $"{Exception.Message}\n{Exception.StackTrace}"); Dispatcher.Invoke(() => { new CrashWindow(Exception).ShowDialog(); Current.Shutdown(); }); } return; } }
private bool ClientMessageReceivedHandler(byte[] Data, List <Action> Callbacks = null) { MessageType Type = GetMessageType(Data); if (Type == MessageType.Invalid) { Disconnect(false); return(false); } switch (Type) { case MessageType.Multi: { Message <Multi> Message = new Message <Multi>(Data); byte[] Payload = Message.Body.MessageBody; if ((Message.Body.UncompressedSize ?? 0) > 0) { byte[] DecompressedPayload; int UncompressedSize = Message.Body.UncompressedSize.Value; try { using (MemoryStream Stream = new MemoryStream(Payload)) using (GZipStream Decompressor = new GZipStream(Stream, CompressionMode.Decompress)) Decompressor.Read(DecompressedPayload = new byte[UncompressedSize], 0, UncompressedSize); Payload = DecompressedPayload; } catch { break; } } List <Action> CallbacksList = new List <Action>(); using (MemoryStream Stream = new MemoryStream(Payload)) using (BinaryReader Reader = new BinaryReader(Stream)) while (Stream.Position != Stream.Length) { byte[] Buffer = new byte[4]; Stream.Read(Buffer, 0, 4); int PacketSize = ToInt32(Buffer, 0); Buffer = new byte[PacketSize]; Stream.Read(Buffer, 0, PacketSize); if (!ClientMessageReceivedHandler(Buffer, CallbacksList)) { break; } } foreach (Action Callback in CallbacksList) { Callback(); } break; } case MessageType.LogOnResponse: { Message <LogOn> Message = new Message <LogOn>(Data); int Result = Message.Body.Result; Log($"Received log on response, result code: {Result}"); if (Result == 1) { IsLogged = true; SessionID = Message.Header.SessionID; SteamID = Message.Header.SteamID; HeartbeatTimer.Change(0, Message.Body.HeartbeatDelay * 1000); Log($"Log on succeeded, initiating heartbeat with {Message.Body.HeartbeatDelay} seconds delay"); } if (Callbacks is null) { LoggedOn?.Invoke(); } else { Callbacks.Add(() => LoggedOn?.Invoke()); } break; } case MessageType.ServiceMethodResponse: { byte[] SerializedMethod = new Message <ServiceMethod>(Data).Body.SerializedMethod; switch (ExpectedServiceMethod) { case 0: { ItemInfo Info = new ItemInfo(); Info.Deserialize(SerializedMethod); WorkshopItem Item = Info.Item; ulong ManifestID = Item.ManifestID; Log($"Received latest manifest ID for mod {Item.ItemID}: {ManifestID}"); if (Callbacks is null) { ModInfoReceived(ManifestID); } else { Callbacks.Add(() => ModInfoReceived(ManifestID)); } break; } case 1: { GetDetails Details = new GetDetails(); Details.Deserialize(SerializedMethod); Log("Received mods details"); if (Callbacks is null) { ModsDetailsReceived(Details.Details); } else { Callbacks.Add(() => ModsDetailsReceived(Details.Details)); } break; } case 2: { QueryFiles Query = new QueryFiles(); Query.Deserialize(SerializedMethod); Log($"Received {Query.Details.Count} queried items details"); if (Callbacks is null) { QueryReceived(Query.Details, Query.Total); } else { Callbacks.Add(() => QueryReceived(Query.Details, Query.Total)); } break; } } break; } case MessageType.ProductInfoResponse: { Message <ProductInfo> Message = new Message <ProductInfo>(Data); if (Message.Body.App is null) { break; } Log("Received product info for app 346110"); VDFStruct AppInfo; using (MemoryStream Stream = new MemoryStream(Message.Body.App.Buffer)) using (StreamReader Reader = new StreamReader(Stream)) AppInfo = new VDFStruct(Reader); if (Callbacks is null) { AppInfoReceived(AppInfo); } else { Callbacks.Add(() => AppInfoReceived(AppInfo)); } break; } } return(true); }