diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93ebe8c --- /dev/null +++ b/.gitignore @@ -0,0 +1,207 @@ +### NotepadPP template +# Notepad++ backups # +*.bak + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Go template +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText template +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..1c2fda5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/gamequery-cli.iml b/.idea/gamequery-cli.iml new file mode 100644 index 0000000..338a266 --- /dev/null +++ b/.idea/gamequery-cli.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..44c9b61 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..9661ac7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/gamequery-cli b/gamequery-cli new file mode 100644 index 0000000..4c231ce Binary files /dev/null and b/gamequery-cli differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e4872b9 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/Neo-Desktop/gamequery-cli + +go 1.18 + +require github.com/wisp-gg/gamequery v0.0.0-20211108193149-8c623c640ded // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f9a2020 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/wisp-gg/gamequery v0.0.0-20211108193149-8c623c640ded h1:g4gxZ/7DDLqI0l6nYubEeBSZnYO8QQ/NnKgkpI/Gwzg= +github.com/wisp-gg/gamequery v0.0.0-20211108193149-8c623c640ded/go.mod h1:4ZdFgc6g8gMu5f3kuJJTf6ZZil3YwxQ4erZvDsfZYLA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..ca13ea8 --- /dev/null +++ b/main.go @@ -0,0 +1,121 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "strconv" + "time" + + "github.com/wisp-gg/gamequery" + "github.com/wisp-gg/gamequery/api" +) + +var ( + IP string + PORT uint16 + TIMEOUT int + INDENT bool +) + +func init() { + flagIP := flag.String("ip", "", "Required: IP address to query [env: GQ_IP]") + flagPORT := flag.Int("port", 0, "Required: Port number to test [env: GQ_PORT]") + flagTIMEOUT := flag.Int("timeout", 5, "Timeout value in milliseconds [env: GQ_TIMEOUT]") + flagHELP := flag.Bool("help", false, "Displays this help message") + flagINDENT := flag.Bool("indent", false, "Should the output be indented") + + envIP := os.Getenv("GQ_IP") + envPORT := os.Getenv("GQ_PORT") + envTIMEOUT := os.Getenv("GQ_TIMEOUT") + + flag.Parse() + + if flagIP != nil && *flagIP != "" { + IP = *flagIP + } else if envIP != "" { + IP = envIP + } else { + fmt.Fprintf(os.Stderr, "please specify an IP\n\n") + flag.Usage() + os.Exit(1) + } + + if flagPORT != nil && *flagPORT > 0 { + PORT = uint16(*flagPORT) + } else if envPORT != "" { + PORT16, err := strconv.ParseInt(envPORT, 10, 16) + if err != nil || PORT16 <= 0 { + fmt.Fprintf(os.Stderr, "unable to process GQ_PORT (%s)\n\n", envPORT) + flag.Usage() + os.Exit(1) + } + PORT = uint16(PORT16) + } else { + fmt.Fprintf(os.Stderr, "please specify a Port\n\n") + flag.Usage() + os.Exit(1) + } + + if flagTIMEOUT != nil && *flagTIMEOUT >= 0 { + TIMEOUT = *flagTIMEOUT + } else if envTIMEOUT != "" { + TIMEOUT64, err := strconv.ParseInt(envTIMEOUT, 10, 32) + if err != nil || TIMEOUT64 < 0 { + fmt.Fprintf(os.Stderr, "unable to process GQ_TIMEOUT (%s)\n\n", envPORT) + flag.Usage() + os.Exit(1) + } + TIMEOUT = int(TIMEOUT64) + } else { + fmt.Fprintf(os.Stderr, "please specify a Timeout\n\n") + flag.Usage() + os.Exit(1) + } + + if *flagHELP { + flag.Usage() + os.Exit(1) + } + + INDENT = *flagINDENT +} + +type results struct { + Protocol string + *api.Response +} + +func main() { + timeout := time.Duration(TIMEOUT) * time.Millisecond + + res, protocol, err := gamequery.Detect(api.Request{ + IP: IP, + Port: PORT, + Timeout: &timeout, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to query: %s\n\n", err) + os.Exit(2) + } + + out := results{ + Protocol: protocol, + Response: &res, + } + + var outBytes []byte + + if INDENT { + outBytes, err = json.MarshalIndent(out, "", " ") + } else { + outBytes, err = json.Marshal(out) + } + if err != nil { + fmt.Fprintf(os.Stderr, "failed to package response: %s\n\n", err) + os.Exit(2) + } + + fmt.Fprintf(os.Stdout, "%s\n\n", outBytes) +}