<commit_before>﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading;
using Mono.Unix.Native;
using ObjectStream;
using ObjectStream.Data;
using Oxide.Core;

namespace Oxide.Plugins
{
    public class PluginCompiler
    {
        public static bool AutoShutdown = true;
        public static string BinaryPath;
        public static string CompilerVersion;

        public static void CheckCompilerBinary()
        {
            BinaryPath = null;
            var filename = "basic.exe";
            var rootDirectory = Interface.Oxide.RootDirectory;
            var binaryPath = Path.Combine(rootDirectory, filename);
            if (File.Exists(binaryPath))
            {
                BinaryPath = binaryPath;
                return;
            }

            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.Win32NT:
                case PlatformID.Win32S:
                case PlatformID.Win32Windows:
                    filename = "CSharpCompiler.exe";
                    binaryPath = Path.Combine(rootDirectory, filename);
                    if (!File.Exists(binaryPath))
                    {
                        try
                        {
                            UpdateCheck(filename); // TODO: Only check once on server startup
                        }
                        catch (Exception)
                        {
                            Interface.Oxide.LogError($"Cannot compile C# (.cs) plugins; unable to find {filename}");
                            return;
                        }
                    }
                    break;
                case PlatformID.Unix:
                case PlatformID.MacOSX:
                    filename = $"CSharpCompiler.{(IntPtr.Size != 8 ? "x86" : "x86_x64")}";
                    binaryPath = Path.Combine(rootDirectory, filename);
                    if (!File.Exists(binaryPath))
                    {
                        try
                        {
                            UpdateCheck(filename); // TODO: Only check once on server startup
                        }
                        catch (Exception)
                        {
                            Interface.Oxide.LogError($"Cannot compile .cs (C#) plugins; unable to find {filename}");
                            return;
                        }
                    }
                    try
                    {
                        if (Syscall.access(binaryPath, AccessModes.X_OK) == -1)
                        {
                            try
                            {
                                Syscall.chmod(binaryPath, FilePermissions.S_IRWXU);
                            }
                            catch (Exception ex)
                            {
                                Interface.Oxide.LogError($"Could not set {filename} as executable; please set manually");
                                Interface.Oxide.LogError(ex.Message);
                            }
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        Interface.Oxide.LogError($"Cannot compile .cs (C#) plugins; {filename} is not executable");
                        Interface.Oxide.LogError(ex.Message);
                        return;
                    }
                    break;
            }
            BinaryPath = binaryPath;
        }

        private static void DependencyTrace()
        {
            if (Environment.OSVersion.Platform != PlatformID.Unix) return;

            var startInfo = new ProcessStartInfo("LD_TRACE_LOADED_OBJECTS=1", BinaryPath)
            {
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            };
            var process = Process.Start(startInfo);
            process.OutputDataReceived += (s, e) => Interface.Oxide.LogError(e.Data);
            process.BeginOutputReadLine();
            process.Start();
            process.WaitForExit();
            //Thread.Sleep(5000);
        }

        private static void UpdateCheck(string filename)
        {
            var filePath = Path.Combine(Interface.Oxide.RootDirectory, filename);
            var request = WebRequest.Create($"https://dl.bintray.com/oxidemod/builds/{filename}");
            var response = request.GetResponse();
            var etag = response.Headers[HttpResponseHeader.ETag];
            var remoteChecksum = etag.Substring(0, etag.LastIndexOf(':')).Trim('"').ToLower();
            var localChecksum = "0";

            if (File.Exists(filePath)) localChecksum = GetChecksum(filePath, Algorithms.MD5);
            if (remoteChecksum != localChecksum) DownloadCompiler(filename, response);
        }

        private static void DownloadCompiler(string filename, WebResponse response)
        {
            try
            {
                Interface.Oxide.LogInfo($"Downloading {filename} for .cs (C#) plugin compilation");

                var stream = response.GetResponseStream();
                var fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);<commit_msg>[CSharp] Fallback to alternate Bintray URL if main doesn't work<commit_after>﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Threading;
using Mono.Unix.Native;
using ObjectStream;
using ObjectStream.Data;
using Oxide.Core;

namespace Oxide.Plugins
{
    public class PluginCompiler
    {
        public static bool AutoShutdown = true;
        public static string BinaryPath;
        public static string CompilerVersion;

        public static void CheckCompilerBinary()
        {
            BinaryPath = null;
            var filename = "basic.exe";
            var rootDirectory = Interface.Oxide.RootDirectory;
            var binaryPath = Path.Combine(rootDirectory, filename);
            if (File.Exists(binaryPath))
            {
                BinaryPath = binaryPath;
                return;
            }

            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.Win32NT:
                case PlatformID.Win32S:
                case PlatformID.Win32Windows:
                    filename = "CSharpCompiler.exe";
                    binaryPath = Path.Combine(rootDirectory, filename);
                    if (!File.Exists(binaryPath))
                    {
                        try
                        {
                            UpdateCheck(filename); // TODO: Only check once on server startup
                        }
                        catch (Exception)
                        {
                            Interface.Oxide.LogError($"Cannot compile C# (.cs) plugins; unable to find {filename}");
                            return;
                        }
                    }
                    break;
                case PlatformID.Unix:
                case PlatformID.MacOSX:
                    filename = $"CSharpCompiler.{(IntPtr.Size != 8 ? "x86" : "x86_x64")}";
                    binaryPath = Path.Combine(rootDirectory, filename);
                    if (!File.Exists(binaryPath))
                    {
                        try
                        {
                            UpdateCheck(filename); // TODO: Only check once on server startup
                        }
                        catch (Exception ex)
                        {
                            Interface.Oxide.LogError($"Cannot compile .cs (C#) plugins; unable to find {filename}");
                            Interface.Oxide.LogWarning(ex.Message);
                            return;
                        }
                    }
                    try
                    {
                        if (Syscall.access(binaryPath, AccessModes.X_OK) == -1)
                        {
                            try
                            {
                                Syscall.chmod(binaryPath, FilePermissions.S_IRWXU);
                            }
                            catch (Exception ex)
                            {
                                Interface.Oxide.LogError($"Could not set {filename} as executable; please set manually");
                                Interface.Oxide.LogError(ex.Message);
                            }
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        Interface.Oxide.LogError($"Cannot compile .cs (C#) plugins; {filename} is not executable");
                        Interface.Oxide.LogError(ex.Message);
                        return;
                    }
                    break;
            }
            BinaryPath = binaryPath;
        }

        private static void DependencyTrace()
        {
            if (Environment.OSVersion.Platform != PlatformID.Unix) return;

            var startInfo = new ProcessStartInfo("LD_TRACE_LOADED_OBJECTS=1", BinaryPath)
            {
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            };
            var process = Process.Start(startInfo);
            process.OutputDataReceived += (s, e) => Interface.Oxide.LogError(e.Data);
            process.BeginOutputReadLine();
            process.Start();
            process.WaitForExit();
            //Thread.Sleep(5000);
        }

        private static void UpdateCheck(string filename)
        {
            var filePath = Path.Combine(Interface.Oxide.RootDirectory, filename);

            HttpWebRequest request;
            try
            {
                request = (HttpWebRequest)WebRequest.Create($"https://dl.bintray.com/oxidemod/builds/{filename}");
            }
            catch (Exception ex)
            {
                Interface.Oxide.LogWarning("Main download location failed, using mirror");
                request = (HttpWebRequest)WebRequest.Create($"https://bintray.com/oxidemod/builds/download_file?file_path={filename}");
                Interface.Oxide.LogWarning(ex.Message);
            }

            var response = (HttpWebResponse)request.GetResponse();
            var statusCode = (int)response.StatusCode;
            var etag = response.Headers[HttpResponseHeader.ETag];
            var remoteChecksum = etag.Substring(0, etag.LastIndexOf(':')).Trim('"').ToLower();
            var localChecksum = "0";

            if (File.Exists(filePath)) localChecksum = GetChecksum(filePath, Algorithms.MD5);
            if (remoteChecksum != localChecksum) DownloadCompiler(filename, response);
        }

        private static void DownloadCompiler(string filename, WebResponse response)
        {
            try
            {
                Interface.Oxide.LogInfo($"Downloading {filename} for .cs (C#) plugin compilation");

                var stream = response.GetResponseStream();
                var fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
{'fraction_non_alphanumeric': 0.08385816581830731, 'fraction_numerical': 0.0037960486584418945, 'mean_word_length': 1.2832381327555644, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3392004', 'n_tokens_mistral': 2812, 'n_tokens_neox': 2590, 'n_words': 567}