diff --git a/environment.go b/environment.go index 72a6ed2e85..340336a24b 100644 --- a/environment.go +++ b/environment.go @@ -69,6 +69,8 @@ type Environment interface { GetWrapper() io.Writer GetStatsTracker() *Tracker + + GetServer() Server } type BaseEnvironment struct { diff --git a/operation.go b/operation.go index 4007a051e7..eff94c194e 100644 --- a/operation.go +++ b/operation.go @@ -1,7 +1,7 @@ package pufferpanel type Operation interface { - Run(env Environment) OperationResult + Run(args RunOperatorArgs) OperationResult } type OperationFactory interface { @@ -16,6 +16,11 @@ type CreateOperation struct { DataMap map[string]interface{} } +type RunOperatorArgs struct { + Environment Environment + Server DaemonServer +} + type OperationResult struct { Error error VariableOverrides map[string]interface{} diff --git a/operations/alterfile/alterfile.go b/operations/alterfile/alterfile.go index 44139e84a9..1d3699184b 100644 --- a/operations/alterfile/alterfile.go +++ b/operations/alterfile/alterfile.go @@ -16,7 +16,9 @@ type AlterFile struct { Regex bool } -func (c AlterFile) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (c AlterFile) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + logging.Info.Printf("Changing data in file: %s", c.TargetFile) env.DisplayToConsole(true, "Changing some data in file: %s\n ", c.TargetFile) target := filepath.Join(env.GetRootDirectory(), c.TargetFile) diff --git a/operations/archive/archive.go b/operations/archive/archive.go index e398ac5ff7..4376e89a0b 100644 --- a/operations/archive/archive.go +++ b/operations/archive/archive.go @@ -1,7 +1,6 @@ package archive import ( - "github.com/mholt/archiver/v3" "github.com/pufferpanel/pufferpanel/v3" ) @@ -10,7 +9,7 @@ type Archive struct { Destination string } -func (op Archive) Run(pufferpanel.Environment) pufferpanel.OperationResult { - err := archiver.Archive(op.Source, op.Destination) +func (op Archive) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + err := args.Server.ArchiveItems(op.Source, op.Destination) return pufferpanel.OperationResult{Error: err} } diff --git a/operations/command/command.go b/operations/command/command.go index ca44eaf3f4..8785b756ce 100644 --- a/operations/command/command.go +++ b/operations/command/command.go @@ -14,15 +14,17 @@ type Command struct { Variables map[string]interface{} } -func (c Command) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (c Command) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + for _, cmd := range c.Commands { logging.Info.Printf("Executing command: %s", cmd) env.DisplayToConsole(true, fmt.Sprintf("Executing: %s\n", cmd)) - cmdToExec, args := pufferpanel.SplitArguments(cmd) + cmdToExec, cmdArgs := pufferpanel.SplitArguments(cmd) ch := make(chan error, 1) err := env.Execute(pufferpanel.ExecutionData{ Command: cmdToExec, - Arguments: args, + Arguments: cmdArgs, Environment: c.Env, Callback: func(exitCode int) { if exitCode != 0 { diff --git a/operations/console/console.go b/operations/console/console.go index e2b6c1c043..0be0415157 100644 --- a/operations/console/console.go +++ b/operations/console/console.go @@ -6,7 +6,9 @@ type Console struct { Text string } -func (d Console) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (d Console) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + env.DisplayToConsole(true, "Message: %s \n", d.Text) return pufferpanel.OperationResult{Error: nil} } diff --git a/operations/curseforge/curseforge.go b/operations/curseforge/curseforge.go index c0fc6f32fc..6245e62c82 100644 --- a/operations/curseforge/curseforge.go +++ b/operations/curseforge/curseforge.go @@ -49,7 +49,9 @@ var ImprovedFabricInstallerUrl = "https://meta.fabricmc.net/v2/versions/loader/$ var ForgeInstallerUrl = "https://maven.minecraftforge.net/net/minecraftforge/forge/${mcVersion}-${version}/forge-${mcVersion}-${version}-installer.jar" var ForgeInstallerName = "forge-${mcVersion}-${version}-installer.jar" -func (c CurseForge) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (c CurseForge) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + var clientFile, serverFile File var err error if c.FileId == 0 { diff --git a/operations/dockerpull/dockerpull.go b/operations/dockerpull/dockerpull.go index 087042ecbc..469dbe67d8 100644 --- a/operations/dockerpull/dockerpull.go +++ b/operations/dockerpull/dockerpull.go @@ -10,7 +10,8 @@ type DockerPull struct { ImageName string } -func (d DockerPull) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (d DockerPull) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment dockerEnv, ok := env.(*docker.Docker) if !ok { diff --git a/operations/download/download.go b/operations/download/download.go index 5aabfe7df2..28453dd9cd 100644 --- a/operations/download/download.go +++ b/operations/download/download.go @@ -10,7 +10,9 @@ type Download struct { Files []string } -func (d Download) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (d Download) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + for _, file := range d.Files { logging.Info.Printf("Download file from %s to %s", file, env.GetRootDirectory()) env.DisplayToConsole(true, "Downloading file %s\n", file) diff --git a/operations/extract/extract.go b/operations/extract/extract.go index c45a905bae..c006159b43 100644 --- a/operations/extract/extract.go +++ b/operations/extract/extract.go @@ -1,7 +1,6 @@ package extract import ( - "github.com/mholt/archiver/v3" "github.com/pufferpanel/pufferpanel/v3" ) @@ -10,7 +9,7 @@ type Extract struct { Destination string } -func (op Extract) Run(pufferpanel.Environment) pufferpanel.OperationResult { - err := archiver.Unarchive(op.Source, op.Destination) +func (op Extract) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + err := args.Server.Extract(op.Source, op.Destination) return pufferpanel.OperationResult{Error: err} } diff --git a/operations/fabricdl/fabricdl.go b/operations/fabricdl/fabricdl.go index b7a62217b9..c3bbc759f9 100644 --- a/operations/fabricdl/fabricdl.go +++ b/operations/fabricdl/fabricdl.go @@ -16,7 +16,9 @@ type FabricMetadata struct { Url string `json:"url"` } -func (f *Fabricdl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (f *Fabricdl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + env.DisplayToConsole(true, "Downloading metadata from %s\n", FabricMetadataUrl) response, err := pufferpanel.HttpGet(FabricMetadataUrl) if err != nil { diff --git a/operations/forgedl/forgedl.go b/operations/forgedl/forgedl.go index 0f6ec59ee7..ceefa522cb 100644 --- a/operations/forgedl/forgedl.go +++ b/operations/forgedl/forgedl.go @@ -34,7 +34,9 @@ type ForgeDl struct { OutputVariable string } -func (op ForgeDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (op ForgeDl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + if op.Version == "" { version, err := getLatestForMCVersion(op.MinecraftVersion) if err != nil { diff --git a/operations/javadl/javadl.go b/operations/javadl/javadl.go index 67012fb83e..0076cde3c2 100644 --- a/operations/javadl/javadl.go +++ b/operations/javadl/javadl.go @@ -21,7 +21,9 @@ type JavaDl struct { Version string } -func (op JavaDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (op JavaDl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + env.DisplayToConsole(true, "Downloading Java "+op.Version) downloader.Lock() diff --git a/operations/mkdir/mkdir.go b/operations/mkdir/mkdir.go index 2727ee6da6..f98b818a3d 100644 --- a/operations/mkdir/mkdir.go +++ b/operations/mkdir/mkdir.go @@ -11,7 +11,8 @@ type Mkdir struct { TargetFile string } -func (m *Mkdir) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (m *Mkdir) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment logging.Info.Printf("Making directory: %s\n", m.TargetFile) env.DisplayToConsole(true, "Creating directory: %s\n", m.TargetFile) target := filepath.Join(env.GetRootDirectory(), m.TargetFile) diff --git a/operations/mojangdl/mojangdl.go b/operations/mojangdl/mojangdl.go index b6ee24a2f9..e1e7d9f71e 100644 --- a/operations/mojangdl/mojangdl.go +++ b/operations/mojangdl/mojangdl.go @@ -15,7 +15,9 @@ type MojangDl struct { Target string } -func (op MojangDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (op MojangDl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + response, err := pufferpanel.HttpGet(VersionJsonUrl) if err != nil { return pufferpanel.OperationResult{Error: err} diff --git a/operations/move/move.go b/operations/move/move.go index c53609068f..f55b40884d 100644 --- a/operations/move/move.go +++ b/operations/move/move.go @@ -12,18 +12,19 @@ type Move struct { TargetFile string } -func (m Move) Run(env pufferpanel.Environment) pufferpanel.OperationResult { - source := filepath.Join(env.GetRootDirectory(), m.SourceFile) - target := filepath.Join(env.GetRootDirectory(), m.TargetFile) - result, valid := validateMove(source, target) +func (m Move) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + fs := args.Server.GetFileServer() + + result, valid := validateMove(fs, m.SourceFile, m.TargetFile) if !valid { return pufferpanel.OperationResult{Error: nil} } for k, v := range result { - logging.Info.Printf("Moving file from %s to %s", source, target) - env.DisplayToConsole(true, "Moving file from %s to %s\n", m.SourceFile, m.TargetFile) - err := os.Rename(k, v) + logging.Info.Printf("Moving file from %s to %s", k, v) + env.DisplayToConsole(true, "Moving file from %s to %s\n", k, v) + err := args.Server.GetFileServer().Rename(k, v) if err != nil { return pufferpanel.OperationResult{Error: err} } @@ -31,10 +32,10 @@ func (m Move) Run(env pufferpanel.Environment) pufferpanel.OperationResult { return pufferpanel.OperationResult{Error: nil} } -func validateMove(source string, target string) (result map[string]string, valid bool) { +func validateMove(fs pufferpanel.FileServer, source string, target string) (result map[string]string, valid bool) { result = make(map[string]string) sourceFiles, _ := filepath.Glob(source) - info, err := os.Stat(target) + info, err := fs.Stat(target) if err != nil { if os.IsNotExist(err) && len(sourceFiles) > 1 { diff --git a/operations/resolveforgeversion/resolveforgeversion.go b/operations/resolveforgeversion/resolveforgeversion.go index 0a0b33c177..0cb95c8a99 100644 --- a/operations/resolveforgeversion/resolveforgeversion.go +++ b/operations/resolveforgeversion/resolveforgeversion.go @@ -20,7 +20,6 @@ import ( "errors" "github.com/hashicorp/go-version" "github.com/pufferpanel/pufferpanel/v3" - "os" "path/filepath" "strings" ) @@ -31,11 +30,14 @@ type ResolveForgeVersion struct { OutputVariable string } -func (op ResolveForgeVersion) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (op ResolveForgeVersion) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + fs := args.Server.GetFileServer() + //if a specific version wasn't specified, we have to dig around through the files.... if op.Version == "" { - dir := filepath.Join(env.GetRootDirectory(), "libraries", "net", "minecraftforge", "forge") - folders, err := os.ReadDir(dir) + dir := filepath.Join("libraries", "net", "minecraftforge", "forge") + folders, err := fs.ReadDir(dir) if err != nil { return pufferpanel.OperationResult{Error: err} } @@ -50,7 +52,7 @@ func (op ResolveForgeVersion) Run(env pufferpanel.Environment) pufferpanel.Opera folderName := v.Name() //look for the unix file to accurately confirm this to be supported desiredFile := filepath.Join(dir, folderName, "unix_args.txt") - if _, err = os.Lstat(desiredFile); err != nil { + if _, err = fs.Stat(desiredFile); err != nil { continue } if op.Version == "" { diff --git a/operations/sleep/sleep.go b/operations/sleep/sleep.go index a972deed29..1bbf41f63d 100644 --- a/operations/sleep/sleep.go +++ b/operations/sleep/sleep.go @@ -9,7 +9,7 @@ type Sleep struct { Duration time.Duration } -func (d Sleep) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (d Sleep) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { time.Sleep(d.Duration) return pufferpanel.OperationResult{Error: nil} } diff --git a/operations/spongedl/spongedl.go b/operations/spongedl/spongedl.go index cb320baf44..18476b602a 100644 --- a/operations/spongedl/spongedl.go +++ b/operations/spongedl/spongedl.go @@ -35,7 +35,9 @@ type SpongeApiV2Asset struct { Extension string } -func (op SpongeDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (op SpongeDl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + //first, we need to get the build we need to get, if one isn't specified if op.SpongeVersion == "" { data, err := op.getLatestVersion(env) @@ -91,12 +93,12 @@ func (op SpongeDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult return pufferpanel.OperationResult{Error: err} } - res := forgeDlOp.Run(env) + res := forgeDlOp.Run(args) if res.Error != nil { return pufferpanel.OperationResult{Error: res.Error} } - err = os.Mkdir(path.Join(env.GetRootDirectory(), "mods"), 0755) + err = args.Server.GetFileServer().Mkdir("mods", 0755) if err != nil && !os.IsExist(err) { return pufferpanel.OperationResult{Error: err} } diff --git a/operations/steamgamedl/steamgamedl.go b/operations/steamgamedl/steamgamedl.go index cb50e16727..81c6708088 100644 --- a/operations/steamgamedl/steamgamedl.go +++ b/operations/steamgamedl/steamgamedl.go @@ -28,7 +28,9 @@ type SteamGameDl struct { ExtraArgs []string } -func (c SteamGameDl) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (c SteamGameDl) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + env.DisplayToConsole(true, "Downloading game from Steam") rootBinaryFolder := config.BinariesFolder.Value() @@ -52,19 +54,19 @@ func (c SteamGameDl) Run(env pufferpanel.Environment) pufferpanel.OperationResul manifestFolder := filepath.Join(env.GetRootDirectory(), ".manifest") _ = os.RemoveAll(manifestFolder) - args := []string{"-app", c.AppId, "-dir", manifestFolder, "-loginid", loginId, "-manifest-only"} + cmdArgs := []string{"-app", c.AppId, "-dir", manifestFolder, "-loginid", loginId, "-manifest-only"} if c.Username != "" { - args = append(args, "-username", c.Username, "-remember-password") + cmdArgs = append(cmdArgs, "-username", c.Username, "-remember-password") if c.Password != "" { - args = append(args, "-password", c.Password) + cmdArgs = append(cmdArgs, "-password", c.Password) } } - args = append(args, c.ExtraArgs...) + cmdArgs = append(cmdArgs, c.ExtraArgs...) ch := make(chan int, 1) steps := pufferpanel.ExecutionData{ Command: filepath.Join(rootBinaryFolder, "depotdownloader", DepotDownloaderBinary), - Arguments: args, + Arguments: cmdArgs, Callback: func(exitCode int) { ch <- exitCode }, @@ -80,21 +82,21 @@ func (c SteamGameDl) Run(env pufferpanel.Environment) pufferpanel.OperationResul } //download game itself now - args = []string{"-app", c.AppId, "-dir", env.GetRootDirectory(), "-loginid", loginId, "-validate"} + cmdArgs = []string{"-app", c.AppId, "-dir", env.GetRootDirectory(), "-loginid", loginId, "-validate"} if c.Username != "" { - args = append(args, "-username", c.Username, "-remember-password") + cmdArgs = append(cmdArgs, "-username", c.Username, "-remember-password") if c.Password != "" { - args = append(args, "-password", c.Password) + cmdArgs = append(cmdArgs, "-password", c.Password) } } if c.ExtraArgs != nil && len(c.ExtraArgs) > 0 { - args = append(args, c.ExtraArgs...) + cmdArgs = append(cmdArgs, c.ExtraArgs...) } steps = pufferpanel.ExecutionData{ Command: filepath.Join(rootBinaryFolder, "depotdownloader", DepotDownloaderBinary), - Arguments: args, + Arguments: cmdArgs, Callback: func(exitCode int) { ch <- exitCode }, diff --git a/operations/writefile/writefile.go b/operations/writefile/writefile.go index 2ad7332afc..4d04fd0e04 100644 --- a/operations/writefile/writefile.go +++ b/operations/writefile/writefile.go @@ -4,7 +4,6 @@ import ( "github.com/pufferpanel/pufferpanel/v3" "github.com/pufferpanel/pufferpanel/v3/logging" "os" - "path/filepath" ) type WriteFile struct { @@ -12,10 +11,19 @@ type WriteFile struct { Text string } -func (c WriteFile) Run(env pufferpanel.Environment) pufferpanel.OperationResult { +func (c WriteFile) Run(args pufferpanel.RunOperatorArgs) pufferpanel.OperationResult { + env := args.Environment + fs := args.Server.GetFileServer() + logging.Info.Printf("Writing data to file: %s", c.TargetFile) env.DisplayToConsole(true, "Writing some data to file: %s\n", c.TargetFile) - target := filepath.Join(env.GetRootDirectory(), c.TargetFile) - err := os.WriteFile(target, []byte(c.Text), 0644) + + file, err := fs.OpenFile(c.TargetFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + return pufferpanel.OperationResult{Error: err} + } + defer pufferpanel.Close(file) + + _, err = file.Write([]byte(c.Text)) return pufferpanel.OperationResult{Error: err} } diff --git a/server.go b/server.go index 9ad7150927..8fb0056348 100644 --- a/server.go +++ b/server.go @@ -213,12 +213,12 @@ func parseRequirementRow(str string) []string { return d } -func (c *StdinConsoleConfiguration) Replace(variables map[string]interface{}) StdinConsoleConfiguration { +func (v *StdinConsoleConfiguration) Replace(variables map[string]interface{}) StdinConsoleConfiguration { return StdinConsoleConfiguration{ - Type: c.Type, - IP: ReplaceTokens(c.IP, variables), - Port: ReplaceTokens(c.Port, variables), - Password: ReplaceTokens(c.Password, variables), + Type: v.Type, + IP: ReplaceTokens(v.IP, variables), + Port: ReplaceTokens(v.Port, variables), + Password: ReplaceTokens(v.Password, variables), } } @@ -266,3 +266,11 @@ func (v *StdinConsoleConfiguration) UnmarshalJSON(data []byte) error { *v = StdinConsoleConfiguration(aux) return nil } + +type DaemonServer interface { + GetFileServer() FileServer + + Extract(source, destination string) error + + ArchiveItems(files []string, destination string) error +} diff --git a/servers/operation_process.go b/servers/operation_process.go index 63cad9e8be..21758205c5 100644 --- a/servers/operation_process.go +++ b/servers/operation_process.go @@ -144,7 +144,11 @@ func (p *OperationProcess) Run(server *Server) error { return pufferpanel.ErrFactoryError(v.Type, err) } - result := op.Run(server.RunningEnvironment) + result := op.Run(pufferpanel.RunOperatorArgs{ + Environment: server.RunningEnvironment, + Server: server, + }) + if result.Error != nil { logging.Error.Printf("Error running command: %s", result.Error.Error()) if firstError == nil { diff --git a/servers/server.go b/servers/server.go index 832bb65a53..6700771dad 100644 --- a/servers/server.go +++ b/servers/server.go @@ -21,6 +21,7 @@ import ( ) type Server struct { + pufferpanel.DaemonServer pufferpanel.Server CrashCounter int `json:"-"`