Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Added Server API Intergration #158

Merged
merged 1 commit into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions frontend/src/pages/server/Administration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ function ServerStartupCard({setServ, serv}: {setServ: React.Dispatch<React.SetSt
disableUpdateOnStart: e.target.checked,
convertValues: p.convertValues
}))}/><br/>
<Checkbox label="Use ASA Server Api (if not installed it will be installed)" checked={serv?.useAsaAPI}
onChange={(e) => setServ((p) => ({
...p,
useAsaAPI: e.target.checked,
convertValues: p.convertValues
}))}/><br/>
{/*<Checkbox label="Restart server on server quit" checked={serv?.restartOnServerQuit} onChange={(e) => setServ((p) => ({ ...p, restartOnServerQuit: e.target.checked }))} />*/}
<Checkbox label="Start server when application opens" checked={serv?.startWithApplication}
onChange={(e) => setServ((p) => ({
Expand Down
1 change: 1 addition & 0 deletions helpers/app_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Asset struct {
}

type Release struct {
ID int64 `json:"id"`
Url string `json:"url"`
TagName string `json:"tag_name"`
Name string `json:"name"`
Expand Down
163 changes: 163 additions & 0 deletions helpers/asa_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package helpers

import (
"archive/zip"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
)

// Download the latest release of AsaApi from GitHub and extract it to the specified path
func PlantLatestAsaAPIRelease(extractionPath string) error {

owner := "ServersHub"
repo := "ServerAPI"

// Get the latest release information
release, err := getLatestRelease(owner, repo)
if err != nil {
return fmt.Errorf("Error getting latest release: %v", err)
}

// Get the tag name of the latest release
tagName := release.TagName

// Construct the zip file name with AsaApi
zipFileName := fmt.Sprintf("AsaApi_%s.zip", strings.TrimPrefix(tagName, "v"))

// Create a file to store the downloaded zip file
zipFilePath := filepath.Join(extractionPath, zipFileName)
zipFile, err := os.Create(zipFilePath)
if err != nil {
return fmt.Errorf("Error creating zip file: %v", err)
}
defer zipFile.Close()

// Download the first release asset
if len(release.Assets) > 0 {
assetURL := release.Assets[0].DownloadUrl
if err := downloadFile(zipFile, assetURL); err != nil {
return fmt.Errorf("Error downloading zip file: %v", err)
}
} else {
return fmt.Errorf("No release assets found.")
}

// Extract the downloaded zip file
if err := extractZipFile(zipFilePath, extractionPath); err != nil {
return fmt.Errorf("Error extracting zip file: %v", err)
}

fmt.Printf("Release extracted to: %s\n", extractionPath)

return nil
}

func extractZipFile(zipFilePath, extractionPath string) error {
// Add code to extract the zip file to the specified path
// You can use a library like "archive/zip" or "github.com/mholt/archiver" for this purpose
// For example, using "archive/zip":
reader, err := zip.OpenReader(zipFilePath)
if err != nil {
return err
}
defer reader.Close()

for _, file := range reader.File {
path := filepath.Join(extractionPath, file.Name)

if file.FileInfo().IsDir() {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
} else {
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()

targetFile, err := os.Create(path)
if err != nil {
return err
}
defer targetFile.Close()

if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
}

return nil
}

func getLatestRelease(owner, repo string) (*Release, error) {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo)

resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch latest release: %s", resp.Status)
}

var release Release
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
return nil, err
}

// Fetch the release assets
assets, err := getReleaseAssets(owner, repo, release.ID)
if err != nil {
return nil, err
}

release.Assets = assets

return &release, nil
}

func getReleaseAssets(owner, repo string, releaseID int64) ([]Asset, error) {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/%d/assets", owner, repo, releaseID)

resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch release assets: %s", resp.Status)
}

var assets []Asset
if err := json.NewDecoder(resp.Body).Decode(&assets); err != nil {
return nil, err
}

return assets, nil
}

func downloadFile(file *os.File, url string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to download file: %s", resp.Status)
}

_, err = io.Copy(file, resp.Body)
return err
}
17 changes: 17 additions & 0 deletions server/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,20 @@ func KillProcessUsingPid(pid uint32) error {

return nil
}

// add a func that checks if asa server api is installed on s.ServerPath + ShooterGame\Binaries\Win64
func (s *Server) checkIfAsaApiInstalled() bool {
// Check if the file already exists
if _, err := os.Stat(filepath.Join(s.ServerPath, "ShooterGame", "Binaries", "Win64", "AsaApiLoader.exe")); os.IsNotExist(err) {
// File does not exist, return false
return false
} else if err != nil {
runtime.LogError(s.ctx, "Error checking if AsaApiLoader.exe exists: "+err.Error())
// There was an error checking the file's existence
return false
}

// File already exists
return true

}
43 changes: 41 additions & 2 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"time"

"github.com/JensvandeWiel/ArkAscendedServerManager/helpers"
Expand All @@ -29,6 +30,7 @@ type Server struct {
UseIniConfig bool `json:"useIniConfig"`
DiscordWebHook string `json:"discordWebHook"`
DiscordWebHookEnabled bool `json:"discordWebHookEnabled"`
UseAsaAPI bool `json:"useAsaAPI"`

//CONFIGURATION VARIABLES

Expand Down Expand Up @@ -106,9 +108,30 @@ func (s *Server) UpdateConfig() error {
//TODO Add startup arguments parsing
//TODO Add check for running application (ensures no accidental duplicated servers, especially with addition of start with application)

func (s *Server) CheckAsaAPI() error {
if s.UseAsaAPI {
installed := s.checkIfAsaApiInstalled()
if !installed {
err := helpers.PlantLatestAsaAPIRelease(filepath.Join(s.ServerPath, "ShooterGame", "Binaries", "Win64"))
if err != nil {
return err
}
}
}

return nil
}

//TODO if using asa api embed the console in the application

func (s *Server) Start() error {

err := s.UpdateConfig()
err := s.CheckAsaAPI()
if err != nil {
return fmt.Errorf("error starting server: failed checking ASA API: %v", err)
}

err = s.UpdateConfig()
if err != nil {
return fmt.Errorf("error starting server: failed updating server configuration: %v", err)
}
Expand Down Expand Up @@ -152,7 +175,23 @@ func (s *Server) Start() error {
// CreateServerCmd returns the command to start the server
func (s *Server) CreateServerCmd() *exec.Cmd {
args := s.CreateArguments()
return exec.Command(path.Join(s.ServerPath, "ShooterGame\\Binaries\\Win64\\ArkAscendedServer.exe"), args...)

if s.UseAsaAPI {

cmd := exec.Command(path.Join(s.ServerPath, "ShooterGame\\Binaries\\Win64\\AsaApiLoader.exe"), args...)

cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: false,
CreationFlags: 0x00000010, //CREATE_NEW_CONSOLE
}

cmd.Dir = path.Join(s.ServerPath, "ShooterGame\\Binaries\\Win64")

return cmd
} else {
return exec.Command(path.Join(s.ServerPath, "ShooterGame\\Binaries\\Win64\\ArkAscendedServer.exe"), args...)
}

}

// ForceStop forces the server to stop "quitting/killing the process"
Expand Down
Loading