ce7cb702218693d08ea6d83464d2457c9250027c
This commit is contained in:
commit
34c5f8963c
1 changed files with 145336 additions and 0 deletions
131
services/minecraft/bootstrap.fsx
Normal file
131
services/minecraft/bootstrap.fsx
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
module Bootstrap
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Runtime.InteropServices
|
||||
open System.Security.Cryptography
|
||||
open System.Text
|
||||
|
||||
let digest path =
|
||||
use stream = File.OpenRead path
|
||||
SHA256.HashData stream |> Convert.ToHexString |> _.ToLowerInvariant()
|
||||
|
||||
let write (path: string) (bytes: byte[]) =
|
||||
Directory.CreateDirectory(Path.GetDirectoryName path) |> ignore
|
||||
File.WriteAllBytes(path, bytes)
|
||||
|
||||
let text path value = write path (Encoding.UTF8.GetBytes(value: string))
|
||||
|
||||
let trust source runtime =
|
||||
write (Path.Combine(runtime, "cacerts")) (File.ReadAllBytes source)
|
||||
|
||||
type Paths =
|
||||
{ Data: string
|
||||
State: string
|
||||
Backups: string
|
||||
Files: string }
|
||||
|
||||
type Config =
|
||||
{ Paths: Paths
|
||||
PasswordPath: string
|
||||
Eula: string
|
||||
Args: string
|
||||
Saltatory: string }
|
||||
|
||||
let prefixes =
|
||||
[ "mods", "mods"
|
||||
"config", "config"
|
||||
"defaultconfigs", "defaultconfigs"
|
||||
"kubejs", "kubejs"
|
||||
"libraries", "libraries"
|
||||
"libraries-integratedscripting", "libraries-integratedscripting"
|
||||
"settings", "settings"
|
||||
"tools", "tools" ]
|
||||
|
||||
let parse (value: string) =
|
||||
value.Split('\n', StringSplitOptions.RemoveEmptyEntries)
|
||||
|> Array.map (fun line ->
|
||||
let line = line.TrimEnd '\r'
|
||||
let hash, path = line.Substring(0, 64), line.Substring(66)
|
||||
hash, path)
|
||||
|
||||
let sync cache prefix inventory includeFile fetchManifest fetch =
|
||||
let root = Path.Combine(cache, prefix)
|
||||
Directory.CreateDirectory root |> ignore
|
||||
let files = fetchManifest inventory |> parse |> Array.filter (snd >> includeFile)
|
||||
|
||||
for hash, name in files do
|
||||
let path = Path.Combine(root, name)
|
||||
Directory.CreateDirectory(Path.GetDirectoryName path) |> ignore
|
||||
fetch (prefix + "/" + name) hash path
|
||||
|
||||
let names = files |> Array.map (snd >> fun name -> Path.GetFullPath(Path.Combine(root, name))) |> Set.ofArray
|
||||
|
||||
for path in Directory.EnumerateFiles(root, "*", SearchOption.AllDirectories) do
|
||||
if not (names.Contains(Path.GetFullPath path)) then
|
||||
File.Delete path
|
||||
|
||||
files
|
||||
|
||||
let copyFiles source target files =
|
||||
for _, name in files do
|
||||
let path = Path.Combine(target, name)
|
||||
Directory.CreateDirectory(Path.GetDirectoryName path) |> ignore
|
||||
File.Copy(Path.Combine(source, name), path, true)
|
||||
|
||||
let run config arch fetchManifest fetch fetchSaltatory =
|
||||
let p = config.Paths
|
||||
let cache = Path.Combine(p.State, "cache")
|
||||
Directory.CreateDirectory p.Data |> ignore
|
||||
Directory.CreateDirectory p.Backups |> ignore
|
||||
Directory.CreateDirectory(Path.Combine(p.State, "world")) |> ignore
|
||||
Directory.CreateDirectory(Path.Combine(p.State, "world/data/chunky")) |> ignore
|
||||
|
||||
for prefix, target in prefixes do
|
||||
let includeFile (name: string) =
|
||||
(prefix <> "mods" || not (name.StartsWith("saltatory-", StringComparison.OrdinalIgnoreCase)))
|
||||
&& (prefix <> "config" || not (name.StartsWith("chunky/tasks/", StringComparison.Ordinal)))
|
||||
let files = sync cache prefix (prefix + ".sha256") includeFile fetchManifest fetch
|
||||
let destination = Path.Combine(p.Data, target)
|
||||
if Directory.Exists destination then Directory.Delete(destination, true)
|
||||
copyFiles (Path.Combine(cache, prefix)) destination files
|
||||
|
||||
let saltatory = Path.Combine(cache, "saltatory.jar")
|
||||
fetchSaltatory config.Saltatory saltatory
|
||||
File.Copy(saltatory, Path.Combine(p.Data, "mods", "saltatory.jar"), true)
|
||||
|
||||
for name in [ "ops.json"; "whitelist.json"; "banned-ips.json"; "banned-players.json"; "usercache.json" ] do
|
||||
let path = Path.Combine(p.State, name)
|
||||
if not (File.Exists path) then text path "[]"
|
||||
|
||||
let names = Path.Combine(p.State, "usernamecache.json")
|
||||
if not (File.Exists names) then text names "{}"
|
||||
for name in [ "local"; "journeymap" ] do
|
||||
Directory.CreateDirectory(Path.Combine(p.State, name)) |> ignore
|
||||
|
||||
let world = Path.Combine(p.State, "world")
|
||||
for prefix in [ "datapacks"; "serverconfig" ] do
|
||||
let name = "world/" + prefix
|
||||
let files = sync cache name ("world-" + prefix + ".sha256") (fun _ -> true) fetchManifest fetch
|
||||
copyFiles (Path.Combine(cache, name)) (Path.Combine(world, prefix)) files
|
||||
|
||||
let tools =
|
||||
match arch with
|
||||
| Architecture.X64 -> "amd64"
|
||||
| Architecture.Arm64 -> "arm64"
|
||||
| _ -> invalidOp "unsupported architecture"
|
||||
|
||||
for name in [ "mc-server-runner"; "mc-monitor" ] do
|
||||
let source = Path.Combine(p.Data, "tools", tools, name)
|
||||
let path = Path.Combine(p.Data, name)
|
||||
File.Copy(source, path, true)
|
||||
File.SetUnixFileMode(path, enum<UnixFileMode> 0o755)
|
||||
|
||||
let properties = File.ReadAllText(Path.Combine(p.Files, "server.properties")).TrimEnd()
|
||||
let password = File.ReadAllText(config.PasswordPath).TrimEnd()
|
||||
text (Path.Combine(p.Data, "server.properties")) (properties + "\nrcon.password=" + password + "\n")
|
||||
File.Copy(Path.Combine(p.Data, config.Args), Path.Combine(p.Data, "server_args.txt"), true)
|
||||
let args = File.ReadAllText(Path.Combine(p.Data, "settings", "user_jvm_args.txt")).TrimEnd()
|
||||
text (Path.Combine(p.Data, "user_jvm_args.txt")) (args + "\n-Djavax.net.ssl.trustStore=/data/cacerts\n")
|
||||
text (Path.Combine(p.Data, "eula.txt")) ("eula=" + config.Eula.ToLowerInvariant() + "\n")
|
||||
printfn "Minecraft bootstrap ready"
|
||||
Loading…
Reference in a new issue