215 lines
7.5 KiB
Bash
Executable File
215 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
ARGS=("$@")
|
|
CYAN="\033[1;96m"
|
|
RED="\033[0;91m"
|
|
GREEN="\033[0;92m"
|
|
RESET='\033[0m'
|
|
|
|
HOLESAIL_DOCKER_IMAGE='anaxios/holesail:2.2.0'
|
|
|
|
readonly base_url="https://api.my-mc.link/"
|
|
readonly headers=( -H "Accept: application/json" -H "Content-Type: application/json" -H "x-my-mc-auth: ${MY_MC_API_KEY}" )
|
|
|
|
|
|
# command format: '<endpoint> <method> [options]'
|
|
|
|
declare -rA commands=(
|
|
[hello]='hello GET {} Say hello to the server.'
|
|
[time]='time GET {} Get server time.'
|
|
[stats]='stats GET {} Get stats of server container.'
|
|
[log]='log GET {} Get link for server logs.'
|
|
[start]='start GET {} Start the server.'
|
|
[stop]='stop GET {} Stop the server.'
|
|
[restart]='restart GET {} Restart the server.'
|
|
[my-link]='my-link GET {} Get connection info for server.'
|
|
[my-geyser-link]='my-geyser-link GET {} Get info for Bedrock connection.'
|
|
[my-sftp]='my-sftp GET {} Get connection info for sftp connection.'
|
|
[my-hash]='my-hash GET {} Get Holsail connection info.'
|
|
[my-geyser-hash]='my-geyser-hash GET {} Get Holesail connection information for bedrock connection.'
|
|
[my-hash-sftp]='my-hash-sftp GET {} Get the Holesail connection information.'
|
|
[list-players]='list-players GET {} List players on the server.'
|
|
[website]='website GET {} Get link to Website.'
|
|
[map]='map GET {} Get link to Bluemap.'
|
|
[status-minecraft]='status/Minecraft GET {} Get status of the my-link connection to the server.'
|
|
[status-bedrock]='status/Bedrock GET {} Get status of the bedrock connection to the server.'
|
|
[status-sftp]='status/SFTP GET {} Get status and info of sftp connection to the server.'
|
|
[ban]='ban POST {"username":"%s"} Ban a player.'
|
|
[unban]='unban POST {"username":"%s"} Unban a player.'
|
|
[say]='say POST {"message":"%s"} Broadcast a message on the server.'
|
|
[tell]='tell POST {"username":"%s","message":"%s"} Send a message to a player.'
|
|
[console]='console POST {"command":"%s"} Run a console command.'
|
|
[give]='give POST {"username":"%s","item":"%s","amount":"%s"} Give player item.'
|
|
[install]='install POST {"mod":"%s"} install a mod using id.'
|
|
[uninstall]='uninstall POST {"mod":"%s"} Uninstall a mod using id.'
|
|
[search]='search POST {"mod":"%s"} Search for mods by name or id.'
|
|
[mod-list]='mod-list GET {} Get list of mods installed on ther server.'
|
|
[backup]='backup FUNC {} EXPERIMENTAL! Make a local copy of server files over sftp.'
|
|
[connect]='connect FUNC {port} Open a connection to server using docker. Leave arg blank for default 25565.'
|
|
[check-update]='check_update FUNC {game_version} Check installed mods have available version.'
|
|
[version]='version FUNC {} Check the version of Minecraft the server is running.'
|
|
[kick]='kick FUNC {player} Kick a player.'
|
|
[smite]='smite FUNC {player} Smite a player with lightening.'
|
|
[op]='op FUNC {player} Make player an operator.'
|
|
[deop]='deop FUNC {player} Deop player.'
|
|
)
|
|
|
|
function op() {
|
|
local player="$1"
|
|
call_api console "op $player"
|
|
}
|
|
|
|
function deop() {
|
|
local player="$1"
|
|
call_api console "deop $player"
|
|
}
|
|
|
|
|
|
function smite() {
|
|
local player="$1"
|
|
call_api console "execute at $player run summon minecraft:lightning_bolt"
|
|
}
|
|
|
|
function kick() {
|
|
local player="$1"
|
|
call_api console "kick $player"
|
|
}
|
|
|
|
function version() {
|
|
local message="$(call_api console version | jq -r '.message')"
|
|
|
|
if [[ $message =~ ([0-9]+\.[0-9]+\.[0-9]+) ]]; then
|
|
local version="${BASH_REMATCH[0]}"
|
|
fi
|
|
|
|
echo "$version"
|
|
}
|
|
|
|
function check_update() {
|
|
local version="${1:-$(version)}"
|
|
local mods="$(call_api mod-list | jq -c '.mods')"
|
|
|
|
local -a result=("MOD\tID\tAVAILABLE\n")
|
|
local item id name latest available has_version available_versions
|
|
while read -r item; do
|
|
name="$(jq -r '.name' <<<"$item")"
|
|
id="$(jq -r '.id' <<<"$item")"
|
|
available_versions="$(curl -sS -X GET "https://api.modrinth.com/v2/project/$id" | jq -r '.game_versions')"
|
|
has_version="$(jq "contains([\"$version\"])" <<<"$available_versions")"
|
|
|
|
if [[ "$has_version" == "true" ]]; then
|
|
available="${GREEN}true${RESET}";
|
|
else
|
|
available="${RED}false${RESET}";
|
|
fi
|
|
|
|
result+=("$name\t$id\t$available\n")
|
|
done < <(jq -c '.[]' <<<"$mods")
|
|
|
|
echo -e "${result[*]}" | column -t -s $'\t'
|
|
}
|
|
|
|
function connect() {
|
|
local port="${1:-25565}"
|
|
if [[ ! $(which docker) ]]; then echo "docker is required"; exit 1; fi
|
|
docker run --rm \
|
|
-e MODE=my-mc \
|
|
-e PORT=25565 \
|
|
-e HOST=0.0.0.0 \
|
|
-e PUBLIC=false \
|
|
-e MY_MC_API_KEY=$MY_MC_API_KEY \
|
|
-p $port:25565 "$HOLESAIL_DOCKER_IMAGE"
|
|
echo ""
|
|
}
|
|
|
|
function backup() {
|
|
if [[ ! $(which lftp) ]]; then echo "lftp is required"; exit 1; fi
|
|
|
|
local sftp_credentials="$(call_api my-sftp)"
|
|
if [[ "$(jq -r '.success' <<<"${sftp_credentials}" )" != "true" ]]; then
|
|
echo "ERROR: failed to get sftp login info";
|
|
exit 1;
|
|
fi
|
|
|
|
local host="$(jq -r '.hostname' <<<"${sftp_credentials}")"
|
|
local username="$(jq -r '.user' <<<"${sftp_credentials}")"
|
|
local port="$(jq -r '.port' <<<"${sftp_credentials}")"
|
|
local password="$(jq -r '.password' <<<"${sftp_credentials}")"
|
|
|
|
local localdir="${MY_MC_BACKUP_DIR:-${HOME}/my-mc_backup/}"
|
|
if [[ ! -d ${localdir} ]]; then mkdir -p ${localdir}; fi
|
|
|
|
pushd "${localdir}"
|
|
|
|
lftp -u "${username}","${password}" "${host}":"${port}" \
|
|
-e "set sftp:connect-program 'ssh -o StrictHostKeyChecking=no'; mirror -c --use-pget minecraft/ minecraft/; quit"
|
|
|
|
popd
|
|
}
|
|
|
|
function usage() {
|
|
printf "API key for my-mc must be exported using 'export MY_MC_API_KEY=<my-mc api key>'\n\n"
|
|
printf "Backup directory can be changed from default ~/mc-mc_backup/ by using 'export MY_MC_BACKUP_DIR=</path/to/dir/>'\n\n"
|
|
printf "Positional arguments will fill the JSON objects with values from left to right.\n\n"
|
|
|
|
local -a message=("COMMAND\tARGUMENTS\tDESCRIPTION\n")
|
|
local command
|
|
for command in "${!commands[@]}"; do
|
|
local endpoint method body description
|
|
read -r endpoint method body description <<<"${commands[${command}]}"
|
|
message+=("$(echo -e "${command}\t${body}" | sed 's/[":\{\}]//g' |sed 's/%s//g'| sed 's/[,]/ /g')\t$description\n")
|
|
done
|
|
|
|
echo -e "${message[*]}" | column -t -s $'\t'
|
|
}
|
|
|
|
function call_api() {
|
|
local command="$1"
|
|
local args=("${@}")
|
|
# remove command from arg list while preserving quoted strings.
|
|
local args=("${args[@]:1}")
|
|
|
|
# Check if key does NOT exists in command array
|
|
if [[ ! -v commands[$command] ]]; then
|
|
printf "${0}: invalid option -- $1\n\n"
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
local endpoint method body description
|
|
read -r endpoint method body description <<<"${commands[$command]}"
|
|
|
|
case "${method}" in
|
|
"POST")
|
|
curl -sS "${headers[@]}" -X "${method}" "${base_url}${endpoint}" \
|
|
-d "$(printf "${body}\n" "${args[@]}")"
|
|
echo ""
|
|
;;
|
|
"GET")
|
|
curl -sS "${headers[@]}" -X "${method}" "${base_url}${endpoint}"
|
|
echo ""
|
|
;;
|
|
"FUNC")
|
|
eval "${endpoint}" "${args[@]}"
|
|
;;
|
|
*)
|
|
echo "ERROR: Invalid state. Check for typo in command array."
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
function main() {
|
|
if [[ ! $(which curl) ]]; then echo "curl is required"; exit 1; fi
|
|
if [[ ! $(which jq) ]]; then echo "jq is required"; exit 1; fi
|
|
|
|
call_api "${ARGS[@]}"
|
|
|
|
exit 0
|
|
}
|
|
|
|
|
|
if [[ "$(basename "$0")" == "mc" ]]; then
|
|
main
|
|
fi
|