Skip to content

Commit

Permalink
Split package in separate files
Browse files Browse the repository at this point in the history
  • Loading branch information
tzerk authored and tzerk committed Feb 28, 2017
1 parent 622c246 commit 870c83b
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 254 deletions.
33 changes: 33 additions & 0 deletions lib/coherentui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lib

import (
"github.com/mitchellh/go-ps"
"log"
"os"
)

func killCoherentUI() {
// Find process(es)
chp, err := ps.Processes()
if err != nil {
log.Fatal(err)
}

// Find PID and kill
for _, v := range chp {
if v.Executable() == "CoherentUI_Host.exe" {
proc, err := os.FindProcess(v.Pid())

if err != nil {
log.Println(err)
}

defer func() {
recover() // 1
return
}()
// Kill the process
proc.Kill()
}
}
}
66 changes: 66 additions & 0 deletions lib/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package lib

import (
"strings"
"io/ioutil"
"os"
"gopkg.in/yaml.v2"
)

// Telegram and program settings (config.yml)
// Guide: http://sweetohm.net/article/go-yaml-parsers.en.html
type Config struct {
Token string
Botid string
Chatid string
Message string
StayAlive bool
Process string
TimeBetweenChecksInS int
KillOnDC bool
ShutdownOnDC bool
KillCoherentUI bool
}

func Read_Settings(ex string, err error) Config {

//// SETTINGS
//--------------------------------------------------------------------------------------------------------------
// YAML PARSING
newex := strings.Replace(ex, "BDO-Watchdog.exe", "config.yml", -1)
// This is necessary for dynamic builds in Jetbrains Gogland IDE
//newex = strings.Replace(ex, "Application.exe", "config.yml", -1)

var config Config
source, err := ioutil.ReadFile(newex)

if err != nil {
// in theory, using yml.Marshal() would be more elegant, but we want to preserve the yaml comments
// as well as set some default values/hints
defconf :=
"## Get updates here: https://github.com/tzerk/BDO-Watchdog/releases/\r\n" +
"## Telegram Bot Settings\r\n" +
"token: \r\n" +
"botid: \r\n" +
"chatid: \r\n" +
"message: BDO disconnected \r\n" +
"\r\n" +
"## Program Settings\r\n" +
"stayalive: false\r\n" +
"process: BlackDesert64.exe\r\n" +
"timebetweenchecksins: 60\r\n" +
"\r\n" +
"# These settings require the .exe to be run with admin rights! \r\n" +
"killondc: true\r\n" +
"shutdownondc: false\r\n" +
"killcoherentui: false"
ioutil.WriteFile("config.yml", []byte(defconf), os.FileMode(int(0777)))
panic(err)
}
err = yaml.Unmarshal(source, &config)
if err != nil {
panic(err)
}

return(config)
}
14 changes: 14 additions & 0 deletions lib/telegram.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lib

import "net/http"

// ---------------------------------------------------------------------------------------------------------------------
// Send a telegram message using a query URL
func Send_TelegramMessage(config Config) {
// Learn how to setup a telegram bot: https://core.telegram.org/bots
resp, _ := http.Get("https://api.telegram.org/bot" + config.Botid +
":" + config.Token +
"/sendMessage?chat_id=" + config.Chatid +
"&text=" + config.Message)
defer resp.Body.Close()
}
28 changes: 28 additions & 0 deletions lib/wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lib

import (
"github.com/andlabs/ui"
"strconv"
"time"
)

// ---------------------------------------------------------------------------------------------------------------------
// A wrapper for time.Sleep() that also updates the UI label and progressbar
func wait(config Config, label_Update *ui.Label, pb *ui.ProgressBar) {
tstep := config.TimeBetweenChecksInS
var pbVal int

if tstep <= 0 {
tstep = 1
} // otherwise division by 0
for i := 0; i <= tstep; i++ {
pbVal = int(100/float32(tstep) * float32(i))
if pbVal > 100 {
pbVal = 100
}
pb.SetValue(pbVal)
label_Update.SetText(" Next update in... " + strconv.Itoa(tstep - i) + " s")
time.Sleep(1 * time.Second)
}
pb.SetValue(0)
}
146 changes: 146 additions & 0 deletions lib/watchdog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package lib

import (
"os/exec"
"syscall"
"log"
"regexp"
"strconv"
"github.com/andlabs/ui"
"github.com/mitchellh/go-ps"
"os"
"time"
)

var STATUS bool = false
var CONNECTION bool = false
var PID int

//--------------------------------------------------------------------------------------------------------------
// PROCESS
//--------------------------------------------------------------------------------------------------------------
func Watchdog(
config Config,
label_Status *ui.Label,
label_PID *ui.Label,
label_Connection *ui.Label,
label_Update *ui.Label,
pb *ui.ProgressBar) {

// KILL CoherentUI_Host.exe
if config.KillCoherentUI {
killCoherentUI()
}

// INFINITE MAIN LOOP
for {
label_Update.SetText("")

//// EXIT CONDITION
//-----------------
// If the process is running, but no longer connected we trigger the following actions
if STATUS && !CONNECTION {

// Use the Telegram API to send a message
Send_TelegramMessage(config)

// Optional: shutdown the computer if the monitored process is disconnected
if config.ShutdownOnDC {
exec.Command("cmd", "/C", "shutdown", "/s").Run()
}

// Optional: kill the monitored process if it is disconnected
// requires elevated rights --> start .exe as administrator
if config.KillOnDC {

proc, err := os.FindProcess(PID)

if err != nil {
log.Println(err)
}

defer func() {
recover() // 1
return
}()
// Kill the process
proc.Kill()

time.Sleep(5 * time.Second)
}

// Optional (YAML file, default: false): keep ts program open even if
// the process is disconnected
if !config.StayAlive {
os.Exit(1)
}
}

//// PROCESS
//----------
p, err := ps.Processes()
if err != nil {
log.Fatal(err)
}

//// PID
//------
PID = 0
for _, v := range p {
if v.Executable() == config.Process {
PID = v.Pid()
}
}
if (PID == 0) {
ui.QueueMain(func () {
STATUS = false
label_Status.SetText(" Status: not running")
label_PID.SetText(" PID: -")
label_Connection.SetText(" Connection: -" )
})

wait(config, label_Update, pb)
continue
} else {

ui.QueueMain(func () {
STATUS = true
label_Status.SetText(" Status: running")
label_PID.SetText(" PID: " + strconv.Itoa(PID))
})
}

//// CONNECTION STATUS
//--------------------
// NETSTAT
// the syscall.SysProcAttr trick found here:
// https://www.reddit.com/r/golang/comments/2c1g3x/build_golang_app_reverse_shell_to_run_in_windows/
cmd := exec.Command("cmd.exe", "/C netstat -aon")
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
out, err := cmd.Output()
if err != nil {
log.Fatal(err)
}


// RegEx matching; try to find the PID in the netstat output
re := regexp.MustCompile(strconv.Itoa(PID))
byteIndex := re.FindIndex([]byte(out))

if (len(byteIndex) == 0) {
ui.QueueMain(func () {
CONNECTION = false
label_Connection.SetText(" Connection: Offline" )
})
} else {
// Update labels
ui.QueueMain(func () {
CONNECTION = true
label_Connection.SetText(" Connection: online")
})
}

// Wait x seconds before next iteration
wait(config, label_Update, pb)
}
}
Loading

0 comments on commit 870c83b

Please sign in to comment.