Пример #1
0
        public override IEnumerator Run()
        {
            return(Cmds.Get <CmdAhornRunJuliaTask>().Run(@"
env = ENV[""AHORN_ENV""]

logfilePath = joinpath(dirname(env), ""log-install-ahorn.txt"")
println(""Logging to "" * logfilePath)
logfile = open(logfilePath, ""w"")

flush(stdout)
flush(stderr)

stdoutReal = stdout
(rd, wr) = redirect_stdout()
redirect_stderr(stdout)

@async while !eof(rd)
    data = String(readavailable(rd))
    print(stdoutReal, data)
    flush(stdoutReal)
    print(logfile, data)
    flush(logfile)
end


if VERSION < v""1.3""
    println(""Outdated version of Julia - $VERSION installed, 1.3+ needed."")
    exit(1)
end

using Logging
logger = SimpleLogger(stdout, Logging.Debug)
loggerPrev = Logging.global_logger(logger)

using Pkg
Pkg.activate(ENV[""AHORN_ENV""])

install_or_update(url::String, pkg::String) = if ""Ahorn"" ∈ keys(Pkg.Types.Context().env.project.deps)
    println(""Updating $pkg..."")
    Pkg.update(pkg)
else
    println(""Adding $pkg..."")
    Pkg.add(PackageSpec(url = url))
end

try
    println(""#OLYMPUS# TIMEOUT START"")

    Pkg.instantiate()

    install_or_update(""https://github.com/CelestialCartographers/Maple.git"", ""Maple"")
    install_or_update(""https://github.com/CelestialCartographers/Ahorn.git"", ""Ahorn"")

    Pkg.instantiate()
    Pkg.API.precompile()

    import Ahorn

    println(""#OLYMPUS# TIMEOUT END"")
catch e
    println(""FATAL ERROR"")
    println(sprint(showerror, e, catch_backtrace()))
    exit(1)
end

exit(0)
", null));
        }
Пример #2
0
        public static void Main(string[] args)
        {
            bool debug   = false;
            bool verbose = false;

            for (int i = 1; i < args.Length; i++)
            {
                string arg = args[i];
                if (arg == "--debug")
                {
                    debug = true;
                }
                else if (arg == "--verbose")
                {
                    verbose = true;
                }
                else if (arg == "--console")
                {
                    AllocConsole();
                }
            }

            CultureInfo.DefaultThreadCurrentCulture   = CultureInfo.InvariantCulture;
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

            SelfPath        = Assembly.GetExecutingAssembly().Location;
            RootDirectory   = Path.GetDirectoryName(Environment.CurrentDirectory);
            ConfigDirectory = Environment.GetEnvironmentVariable("OLYMPUS_CONFIG");
            if (string.IsNullOrEmpty(ConfigDirectory) || !Directory.Exists(ConfigDirectory))
            {
                ConfigDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Olympus");
            }
            Console.Error.WriteLine(RootDirectory);

            if (Type.GetType("Mono.Runtime") != null)
            {
                // Mono hates HTTPS.
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => {
                    return(true);
                };
            }

            // Enable TLS 1.2 to fix connecting to GitHub.
            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

            if (args.Length >= 1 && args[0] == "--uninstall" && PlatformHelper.Is(Platform.Windows))
            {
                new CmdWin32AppUninstall().Run(args.Length >= 2 && args[1] == "--quiet");
                return;
            }

            Process parentProc   = null;
            int     parentProcID = 0;

            TcpListener   listener = new TcpListener(IPAddress.Loopback, 0);
            List <Thread> threads  = new List <Thread>();

            listener.Start();

            Console.WriteLine($"{((IPEndPoint) listener.LocalEndpoint).Port}");

            try {
                parentProc = Process.GetProcessById(parentProcID = int.Parse(args.Last()));
            } catch {
                Console.Error.WriteLine("[sharp] Invalid parent process ID");
            }

            if (debug)
            {
                Debugger.Launch();
                Console.WriteLine(@"""debug""");
            }
            else
            {
                Console.WriteLine(@"""ok""");
            }

            Console.WriteLine(@"null");
            Console.Out.Flush();

            if (parentProc != null)
            {
                Thread killswitch = new Thread(() => {
                    try {
                        while (!parentProc.HasExited && parentProc.Id == parentProcID)
                        {
                            Thread.Yield();
                            Thread.Sleep(1000);
                        }
                        Environment.Exit(0);
                    } catch {
                        Environment.Exit(-1);
                    }
                })
                {
                    Name         = "Killswitch",
                    IsBackground = true
                };
                killswitch.Start();
            }

            Cmds.Init();

            try {
                while ((parentProc != null && !parentProc.HasExited && parentProc.Id == parentProcID) || parentProc == null)
                {
                    TcpClient client = listener.AcceptTcpClient();
                    try {
                        string ep = client.Client.RemoteEndPoint.ToString();
                        Console.Error.WriteLine($"[sharp] New TCP connection: {ep}");

                        client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
                        Stream stream = client.GetStream();

                        MessageContext ctx = new MessageContext();

                        lock (Cache)
                            foreach (Message msg in Cache.Values)
                            {
                                ctx.Reply(msg);
                            }

                        Thread threadW = new Thread(() => {
                            try {
                                using (StreamWriter writer = new StreamWriter(stream, UTF8NoBOM))
                                    WriteLoop(parentProc, ctx, writer, verbose);
                            } catch (Exception e) {
                                if (e is ObjectDisposedException)
                                {
                                    Console.Error.WriteLine($"[sharp] Failed writing to {ep}: {e.GetType()}: {e.Message}");
                                }
                                else
                                {
                                    Console.Error.WriteLine($"[sharp] Failed writing to {ep}: {e}");
                                }
                                client.Close();
                            } finally {
                                ctx.Dispose();
                            }
                        })
                        {
                            Name         = $"Write Thread for Connection {ep}",
                            IsBackground = true
                        };

                        Thread threadR = new Thread(() => {
                            try {
                                using (StreamReader reader = new StreamReader(stream, UTF8NoBOM))
                                    ReadLoop(parentProc, ctx, reader, verbose);
                            } catch (Exception e) {
                                if (e is ObjectDisposedException)
                                {
                                    Console.Error.WriteLine($"[sharp] Failed reading from {ep}: {e.GetType()}: {e.Message}");
                                }
                                else
                                {
                                    Console.Error.WriteLine($"[sharp] Failed reading from {ep}: {e}");
                                }
                                client.Close();
                            } finally {
                                ctx.Dispose();
                            }
                        })
                        {
                            Name         = $"Read Thread for Connection {ep}",
                            IsBackground = true
                        };

                        threads.Add(threadW);
                        threads.Add(threadR);
                        threadW.Start();
                        threadR.Start();
                    } catch (ThreadAbortException) {
                    } catch (Exception e) {
                        Console.Error.WriteLine($"[sharp] Failed listening for TCP connection:\n{e}");
                        client.Close();
                    }
                }
            } catch (ThreadAbortException) {
            } catch (Exception e) {
                Console.Error.WriteLine($"[sharp] Failed listening for TCP connection:\n{e}");
            }

            Console.Error.WriteLine("[sharp] Goodbye");
        }
Пример #3
0
        public override IEnumerator Run(string root, string artifactBase)
        {
            // MiniInstaller reads orig/Celeste.exe and copies Celeste.exe into it but only if missing.
            // Olympus can help out and delete the orig folder if the existing Celeste.exe isn't modded.
            string installedVersion = Cmds.Get <CmdGetVersionString>().Run(root);

            if (installedVersion.StartsWith("Celeste ") && !installedVersion.Contains("Everest"))
            {
                string orig = Path.Combine(root, "orig");
                if (Directory.Exists(orig))
                {
                    yield return(Status("Deleting previous backup", false, "", false));

                    Directory.Delete(orig, true);
                }
            }

            if (artifactBase.StartsWith("file://"))
            {
                artifactBase = artifactBase.Substring("file://".Length);
                yield return(Status($"Unzipping {Path.GetFileName(artifactBase)}", false, "download", false));

                using (FileStream wrapStream = File.Open(artifactBase, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
                    using (ZipArchive wrap = new ZipArchive(wrapStream, ZipArchiveMode.Read)) {
                        ZipArchiveEntry zipEntry = wrap.GetEntry("olympus-build/build.zip");
                        if (zipEntry == null)
                        {
                            yield return(Unpack(wrap, root, "main/"));
                        }
                        else
                        {
                            using (Stream zipStream = zipEntry.Open())
                                using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Read))
                                    yield return(Unpack(zip, root));
                        }
                    }
            }
            else
            {
                // Only new builds offer olympus-meta and olympus-build artifacts.
                yield return(Status("Downloading metadata", false, "", false));

                int size;

                try {
                    byte[] zipData;
                    using (WebClient wc = new WebClient())
                        zipData = wc.DownloadData(artifactBase + "olympus-meta");
                    using (MemoryStream zipStream = new MemoryStream(zipData))
                        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Read)) {
                            using (Stream sizeStream = zip.GetEntry("olympus-meta/size.txt").Open())
                                using (StreamReader sizeReader = new StreamReader(sizeStream))
                                    size = int.Parse(sizeReader.ReadToEnd().Trim());
                        }
                } catch (Exception) {
                    size = 0;
                }

                if (size > 0)
                {
                    yield return(Status("Downloading olympus-build.zip", false, "download", false));

                    using (MemoryStream wrapStream = new MemoryStream()) {
                        yield return(Download(artifactBase + "olympus-build", size, wrapStream));

                        yield return(Status("Unzipping olympus-build.zip", false, "download", false));

                        wrapStream.Seek(0, SeekOrigin.Begin);
                        using (ZipArchive wrap = new ZipArchive(wrapStream, ZipArchiveMode.Read)) {
                            using (Stream zipStream = wrap.GetEntry("olympus-build/build.zip").Open())
                                using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Read)) {
                                    yield return(Unpack(zip, root));
                                }
                        }
                    }
                }
                else
                {
                    yield return(Status("Downloading main.zip", false, "download", false));

                    using (MemoryStream zipStream = new MemoryStream()) {
                        yield return(Download(artifactBase + "main", size, zipStream));

                        yield return(Status("Unzipping main.zip", false, "download", false));

                        zipStream.Seek(0, SeekOrigin.Begin);
                        using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Read)) {
                            yield return(Unpack(zip, root, "main/"));
                        }
                    }
                }
            }

            yield return(Status("Starting MiniInstaller", false, "monomod", false));

            yield return(Install(root));
        }
Пример #4
0
        public static void ReadLoop(Process parentProc, MessageContext ctx, StreamReader reader, bool verbose, char delimiter = '\0')
        {
            // JsonTextReader would be neat here but Newtonsoft.Json is unaware of NetworkStreams and tries to READ PAST STRINGS
            while (!(parentProc?.HasExited ?? false))
            {
                // Commands from Olympus come in pairs of two objects:

                if (verbose)
                {
                    Console.Error.WriteLine("[sharp] Awaiting next command");
                }

                // Unique ID
                string uid = JsonConvert.DeserializeObject <string>(reader.ReadTerminatedString(delimiter));
                if (verbose)
                {
                    Console.Error.WriteLine($"[sharp] Receiving command {uid}");
                }

                // Command ID
                string cid = JsonConvert.DeserializeObject <string>(reader.ReadTerminatedString(delimiter)).ToLowerInvariant();
                if (cid == "_ack")
                {
                    reader.ReadTerminatedString(delimiter);
                    if (verbose)
                    {
                        Console.Error.WriteLine($"[sharp] Ack'd command {uid}");
                    }
                    lock (Cache)
                        if (Cache.ContainsKey(uid))
                        {
                            Cache.Remove(uid);
                        }
                        else
                        {
                            Console.Error.WriteLine($"[sharp] Ack'd command that was already ack'd {uid}");
                        }
                    continue;
                }

                if (cid == "_stop")
                {
                    // Let's hope that everyone knows how to handle this.
                    Environment.Exit(0);
                    continue;
                }

                Message msg = new Message()
                {
                    UID = uid,
                    CID = cid
                };

                Cmd cmd = Cmds.Get(cid);
                if (cmd == null)
                {
                    reader.ReadTerminatedString(delimiter);
                    Console.Error.WriteLine($"[sharp] Unknown command {cid}");
                    msg.Error = "cmd failed running: not found: " + cid;
                    ctx.Reply(msg);
                    continue;
                }

                if (verbose)
                {
                    Console.Error.WriteLine($"[sharp] Parsing args for {cid}");
                }

                // Payload
                object input = JsonConvert.DeserializeObject(reader.ReadTerminatedString(delimiter), cmd.InputType);
                object output;
                try {
                    if (verbose || cmd.LogRun)
                    {
                        Console.Error.WriteLine($"[sharp] Executing {cid}");
                    }
                    if (cmd.Taskable)
                    {
                        output = Task.Run(() => cmd.Run(input));
                    }
                    else
                    {
                        output = cmd.Run(input);
                    }
                } catch (Exception e) {
                    Console.Error.WriteLine($"[sharp] Failed running {cid}: {e}");
                    msg.Error = "cmd failed running: " + e;
                    ctx.Reply(msg);
                    continue;
                }

                if (output is Task <object> task)
                {
                    task.ContinueWith(t => {
                        if (task.Exception != null)
                        {
                            Exception e = task.Exception;
                            Console.Error.WriteLine($"[sharp] Failed running task {cid}: {e}");
                            msg.Error = "cmd task failed running: " + e;
                            ctx.Reply(msg);
                            return;
                        }

                        msg.Value = t.Result;
                        lock (Cache)
                            Cache[uid] = msg;
                        ctx.Reply(msg);
                    });
                }
                else
                {
                    msg.Value = output;
                    lock (Cache)
                        Cache[uid] = msg;
                    ctx.Reply(msg);
                }
            }
        }
Пример #5
0
        public override IEnumerator Run()
        {
            yield return(Status("Preparing installation of Ahorn-VHD", false, "", false));

            if (!PlatformHelper.Is(Platform.Windows | Platform.Bits64))
            {
                yield return(Status("Unsupported platform.", 1f, "error", false));

                throw new PlatformNotSupportedException($"Platform not supported: {PlatformHelper.Current}");
            }

            string vhd = AhornHelper.VHDPath;

            if (File.Exists(vhd))
            {
                yield return(Status("Ahorn-VHD already exists - please delete it before reinstalling.", 1f, "error", false));

                throw new Exception("Ahorn-VHD already exists.");
            }

            string archive = vhd + ".7z";
            bool   tmpPerm = File.Exists(archive);

            try {
                if (tmpPerm)
                {
                    yield return(Status($"{Path.GetFileName(archive)} already exists - reusing and preserving", false, "", false));
                }
                else
                {
                    const string url = "https://0x0ade.ga/ahornvhd/files/ahornvhd.7z";
                    yield return(Status($"Downloading {url} to {archive}", false, "download", false));

                    string tmp = archive + ".part";
                    if (File.Exists(tmp))
                    {
                        File.Delete(tmp);
                    }
                    using (FileStream stream = File.Open(tmp, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                        yield return(Download(url, 0, stream));

                    File.Move(tmp, archive);
                }

                string sevenzip = Path.Combine(Program.RootDirectory, "7zr.exe");

                if (!File.Exists(sevenzip))
                {
                    const string url = "https://raw.githubusercontent.com/EverestAPI/Olympus/main/lib-windows/7zr.exe";
                    yield return(Status($"Couldn't find 7zr.exe, downloading from {url}", false, "download", false));

                    using (FileStream stream = File.Open(sevenzip, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
                        yield return(Download(url, 0, stream));
                }

                yield return(Status("Extracting ahornvhd.7z", false, "download", false));

                using (Process process = ProcessHelper.Wrap(sevenzip, $"x \"{archive}\" \"-o{Path.GetDirectoryName(vhd)}\" {Path.GetFileName(vhd)} -bb3")) {
                    process.Start();
                    for (string line; (line = process.StandardOutput.ReadLine()) != null;)
                    {
                        yield return(Status(line, false, "download", false));
                    }
                    process.WaitForExit();
                    if (process.ExitCode != 0)
                    {
                        throw new Exception("7zr encountered a fatal error:\n" + process.StandardError.ReadToEnd());
                    }
                    if (!File.Exists(vhd))
                    {
                        throw new Exception($"File not extracted: {vhd}");
                    }
                    yield return(Status("ahornvhd.7z extracted", false, "download", false));
                }
            } finally {
                if (!tmpPerm && File.Exists(archive))
                {
                    File.Delete(archive);
                }
            }

            yield return(Cmds.Get <CmdAhornMountAhornVHD>().Run());

            yield return(Cmds.Get <CmdAhornInstallAhorn>().Run());
        }