Esempio n. 1
0
        public static void Unload(IrcClient client, IrcMessageData messageData)
        {
            var buildInfo = RemoteBuildManager.GetBuild(messageData.MessageArray[1]);

            if (buildInfo != null)
            {
                buildInfo.Unload();
            }
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 3
0
        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;
                });
            });
        }
Esempio n. 4
0
        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);
            }
        }
Esempio n. 5
0
        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();
        }
Esempio n. 6
0
        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);
        }