public static void Unload(IrcClient client, IrcMessageData messageData) { var buildInfo = RemoteBuildManager.GetBuild(messageData.MessageArray[1]); if (buildInfo != null) { buildInfo.Unload(); } }
private static void CheckFileExists(string buildName, Action <BuildInfo> successHandler, Action <BuildInfo> failHandler, Action onReady) { var buildInfo = RemoteBuildManager.GetBuild(buildName); if (!buildInfo.Ready) { // Save memory by unloading old data. RemoteBuildManager.ClearExpiredBuilds(); failHandler(buildInfo); buildInfo.OnReady += onReady; if (!buildInfo.Loading) { buildInfo.Prepare(); } } else { successHandler(buildInfo); } }
public static void HandleDownloadFile(IrcClient client, IrcMessageData messageData) { if (!Scanner.Configuration.Proxy.Enabled) { client.SendReply(messageData, "Command disabled."); return; } if (!RemoteBuildManager.IsBuildKnown(messageData.MessageArray[1])) { client.SendReply(messageData, "Unknown build."); return; } CheckFileExists(messageData.MessageArray[1], buildInfo => { var remoteFileName = string.Join(" ", messageData.MessageArray.Skip(2)); var indexEntry = buildInfo.GetEntry(remoteFileName); if (indexEntry == null) { client.SendReply(messageData, $"{messageData.Nick}: File does not exist."); return; } // Give out link // Disable resharper for readability // ReSharper disable once UseStringInterpolation var response = string.Format("http://{0}/{1}/{2}/{3}", Scanner.Proxy.PublicDomain, buildInfo.VersionName, JenkinsHashing.Instance.ComputeHash(messageData.MessageArray[2]), Path.GetFileName(remoteFileName.Replace('\\', '/'))); client.SendReply(messageData, $"{messageData.Nick}: {response}"); }, buildInfo => { client.SendReply(messageData, $"{messageData.Nick}: Loading {buildInfo.VersionName} ..."); }, () => { var buildInfo = RemoteBuildManager.GetBuild(messageData.MessageArray[1]); if (buildInfo.Loading) { client.SendReply(messageData, $"{messageData.Nick}: Build {buildInfo.VersionName} is currently loading."); return; } client.SendReply(messageData, $"{messageData.Nick}: Build {buildInfo.VersionName} has been loaded."); if (!buildInfo.Install.Loaded) { client.SendReply(messageData, $"{messageData.Nick}: Install file could not be downloaded, expect erroneous results."); } Task.Delay(10 * 60 * 1000).ContinueWith(t => { buildInfo.Expired = true; }); }); }
private static void Process(HttpListenerContext context) { var tokens = context.Request.Url.AbsolutePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { WriteError(context, "Badly formatted request.", HttpStatusCode.BadRequest); return; } var buildName = tokens[0]; var fileHash = ulong.Parse(tokens[1]); var fileName = tokens[2]; var buildInfo = RemoteBuildManager.GetBuild(buildName); if (buildInfo == null) { WriteError(context, "Unknown build.", HttpStatusCode.BadRequest); return; } var fileEntry = buildInfo.GetEntry(fileHash); if (fileEntry == null) { WriteError(context, "This build is currently loading. Try again later.", HttpStatusCode.BadRequest); return; } try { using (var blte = new BLTE(buildInfo.CDN.Hosts[0])) { if (fileEntry.ArchiveIndex != -1) { blte.AddHeader("Range", $"bytes={fileEntry.Offset}-{fileEntry.Offset + fileEntry.Size - 1}"); } var archiveName = fileEntry.Hash.ToHexString(); if (fileEntry.ArchiveIndex != -1) { archiveName = buildInfo.Indices.Archives[fileEntry.ArchiveIndex].ToHexString(); } blte.Send($"/{buildInfo.CDN.Path}/data/{archiveName.Substring(0, 2)}/{archiveName.Substring(2, 2)}/{archiveName}"); Scanner.WriteLine($"[PROXY] Serving {fileName} through {blte.URL}."); if (!blte.Failed) { context.Response.ContentType = "application/octet-stream"; context.Response.ContentLength64 = blte.DecompressedLength; context.Response.AddHeader("Date", blte.ResponseHeaders.Get("Date")); context.Response.AddHeader("ETag", blte.ResponseHeaders.Get("ETag")); context.Response.AddHeader("Last-Modified", DateTime.Now.ToString("r")); context.Response.AddHeader("Connection", "Keep-Alive"); context.Response.StatusCode = (int)HttpStatusCode.OK; Scanner.WriteLine($"[PROXY] Serving {fileName} to {context.Request.RemoteEndPoint} - {archiveName}"); blte.PipeTo(context.Response.OutputStream); } else { var sBuilder = new StringBuilder(); sBuilder.AppendLine($"File {fileName} cannot be downloaded - it might be an encrypted archive..."); sBuilder.AppendLine(); sBuilder.AppendLine($"Requested archive: {blte.URL}"); if (fileEntry.ArchiveIndex != -1) { sBuilder.AppendLine($"Range: {fileEntry.Offset}-{fileEntry.Offset + fileEntry.Size - 1}"); } WriteError(context, sBuilder.ToString(), HttpStatusCode.InternalServerError); } } } catch (IOException ioe) { Scanner.WriteLine("[PROXY] Remote client closed the connection."); } catch (Exception e) { Scanner.WriteLine(e.ToString()); WriteError(context, e.ToString(), HttpStatusCode.InternalServerError); } }
public static void Main(string[] args) { #if !UNIX && !DEBUG if (args.Length == 0) { Console.WriteLine("Arguments:"); Console.WriteLine("--conf, -c Path the xml configuration file."); return; } #endif #if !UNIX // Setup console _styleSheet = new StyleSheet(Color.White); _styleSheet.AddStyle(@"[0-9\/]+ [0-9:]+ (?:A|P)M", Color.SlateBlue); _styleSheet.AddStyle(@"\[[A-Z]+\]", Color.Gold); _styleSheet.AddStyle(@"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)", Color.Purple); _styleSheet.AddStyle(@"#[-az0-9_-]", Color.DarkGreen); _styleSheet.AddStyle(@"[a-f0-9]{32}", Color.Orange); _styleSheet.AddStyle(@"[a-z_-]+\-[0-9]{5}patch[0-9]\.[0-9]\.[0-9]_[A-Za-z]+", Color.Firebrick); #endif _startupArguments = args; Console.CancelKeyPress += (s, ea) => { WriteLine("[ERROR] Aborting ..."); foreach (var knownServer in _ircClients) { knownServer.Value.Disconnect(); } Proxy?.Stop(); _token.Cancel(); }; #region Load XML configuration file var configurationFileName = GetStringParam("--conf", "-c", "conf.xml"); var serializer = new XmlSerializer(typeof(Configuration)); using (var reader = new StreamReader(configurationFileName)) Configuration = (Configuration)serializer.Deserialize(reader); #endregion // Read channels from XML foreach (var channelInfo in Configuration.Branches) { var newChannel = new Channel() { ChannelName = channelInfo.Name, DisplayName = channelInfo.Description }; newChannel.BuildDeployed += OnBuildDeployed; Channels.Add(newChannel); } #region HTTP Proxy setup if (Configuration.Proxy.Enabled) { WriteLine("[HTTP] Listening on http://{1}:{0}", Configuration.Proxy.PublicDomainName, Configuration.Proxy.BindPort); Proxy = new HttpServer(Configuration.Proxy.Endpoint, Configuration.Proxy.PublicDomainName); Proxy.Listen(Configuration.Proxy.BindPort, _token); } #endregion // Setup IRC clients foreach (var serverInfo in Configuration.Servers) { WriteLine("[IRC] Connecting to {0}:{1}", serverInfo.Address, serverInfo.Port); var client = new IrcClient() { SupportNonRfc = true, ActiveChannelSyncing = true }; client.OnConnected += (sender, eventArgs) => StartThreads(); client.OnChannelMessage += (sender, eventArgs) => { Dispatcher.Dispatch(eventArgs.Data, client); }; client.Connect(serverInfo.Address, serverInfo.Port); client.Login(serverInfo.Username, serverInfo.Username, 0, serverInfo.Username); foreach (var channelInfo in serverInfo.Channels) { if (string.IsNullOrEmpty(channelInfo.Key)) { client.RfcJoin("#" + channelInfo.Name); } else { client.RfcJoin("#" + channelInfo.Name, channelInfo.Key); } } Task.Run(() => { client.Listen(); }); _ircClients[serverInfo.Address] = client; } while (!_token.IsCancellationRequested) { if (_token.Token.WaitHandle.WaitOne(10000)) { break; } RemoteBuildManager.ClearExpiredBuilds(); } RemoteBuildManager.ClearExpiredBuilds(); }
public void Update(bool silent) { Version = new Versions(ChannelName); CDN = new CDNs(ChannelName); // Walk through versions foreach (var versionInfo in Version.Records) { var versionName = versionInfo.Value.GetName(DisplayName); // Get CDN data. if (!CDN.Records.TryGetValue(versionInfo.Value.Region, out var serverInfo)) { continue; } var currentBuildInfo = RemoteBuildManager.GetBuild(versionName); var isNewBuild = currentBuildInfo == null; if (!isNewBuild) { currentBuildInfo.Regions.Add(versionInfo.Value.Region); } else { currentBuildInfo = new BuildInfo { Version = versionInfo.Value, CDN = serverInfo, VersionName = versionName }; RemoteBuildManager.AddBuild(currentBuildInfo); } // Get build info currentBuildInfo.BuildConfiguration = new BuildConfiguration(serverInfo, versionInfo.Value.BuildConfig); currentBuildInfo.ContentConfiguration = new ContentConfiguration(serverInfo, versionInfo.Value.CDNConfig); if (currentBuildInfo.BuildConfiguration.Encoding == null || currentBuildInfo.ContentConfiguration.Archives == null) { Scanner.WriteLine($"[{versionName}] Error retrieving either CDN or build configuration file."); } else if (isNewBuild) { Scanner.QueueInitialUpdate(currentBuildInfo); } } foreach (var currentBuild in RemoteBuildManager.Builds.Values.Where(b => b.JustDeployed && b.Channel == ChannelName)) { currentBuild.JustDeployed = false; var coalescedRegions = string.Join(", ", currentBuild.Regions).ToUpperInvariant(); if (!silent) { BuildDeployed?.Invoke(ChannelName, currentBuild.VersionName, coalescedRegions); } Scanner.WriteLine($"[{currentBuild.VersionName}] Deployed to regions {coalescedRegions}."); } // Sleep half a second to make sure every message goes through. Thread.Sleep(500); }