automatic-mouse-mover/pkg/mousemover/mouseMover.go

175 lines
4.2 KiB
Go
Raw Normal View History

package mousemover
import (
2019-04-19 22:52:37 +00:00
"fmt"
"os"
2019-03-28 19:52:25 +00:00
"sync"
"time"
2019-04-19 22:52:37 +00:00
"github.com/sirupsen/logrus"
2019-03-28 19:52:25 +00:00
log "github.com/sirupsen/logrus"
"github.com/go-vgo/robotgo"
2019-04-23 23:51:58 +00:00
"github.com/prashantgupta24/activity-tracker/pkg/activity"
"github.com/prashantgupta24/activity-tracker/pkg/tracker"
)
2019-03-27 23:10:07 +00:00
var instance *MouseMover
2019-03-27 23:10:07 +00:00
//MouseMover is the main struct for the app
type MouseMover struct {
2019-03-28 19:52:25 +00:00
quit chan struct{}
mutex sync.RWMutex
runningStatus bool
2019-04-19 22:52:37 +00:00
logFile *os.File
}
const (
2019-04-19 22:52:37 +00:00
timeout = 100 //ms
2019-04-23 23:51:58 +00:00
logFileName = "log/logFile-amm-1"
)
2019-03-27 23:10:07 +00:00
//Start the main app
func (m *MouseMover) Start() {
2019-03-28 19:52:25 +00:00
if m.isRunning() {
return
}
m.quit = make(chan struct{})
heartbeatInterval := 60 //value always in seconds
2019-04-19 22:52:37 +00:00
workerInterval := 10
activityTracker := &tracker.Instance{
HeartbeatInterval: heartbeatInterval,
WorkerInterval: workerInterval,
//LogLevel: "debug", //if we want verbose logging
}
heartbeatCh := activityTracker.Start()
2019-03-27 23:10:07 +00:00
go func(m *MouseMover) {
2019-04-19 22:52:37 +00:00
logger := getLogger(m, false) //set writeToFile=true only for debugging
2019-03-28 19:52:25 +00:00
m.updateRunningStatus(true)
movePixel := 10
2019-04-19 22:52:37 +00:00
var lastMoved time.Time
2019-04-23 23:51:58 +00:00
isSystemSleeping := false
2019-04-19 22:52:37 +00:00
didNotMoveTimes := 0
for {
select {
case heartbeat := <-heartbeatCh:
2019-03-28 20:38:01 +00:00
if !heartbeat.WasAnyActivity {
2019-04-23 23:51:58 +00:00
if isSystemSleeping {
logger.Infof("system sleeping")
continue
}
mouseMoveSuccessCh := make(chan bool)
go moveAndCheck(movePixel, mouseMoveSuccessCh)
select {
case wasMouseMoveSuccess := <-mouseMoveSuccessCh:
if wasMouseMoveSuccess {
2019-04-19 22:52:37 +00:00
lastMoved = time.Now()
logger.Infof("moved mouse at : %v\n\n", lastMoved)
movePixel *= -1
2019-04-19 22:52:37 +00:00
didNotMoveTimes = 0
} else {
2019-04-19 22:52:37 +00:00
didNotMoveTimes++
msg := fmt.Sprintf("Mouse pointer cannot be moved at %v. Last moved at %v. Happened %v times. See README for details.",
time.Now(), lastMoved, didNotMoveTimes)
logger.Errorf(msg)
if didNotMoveTimes >= 3 {
go func() {
robotgo.ShowAlert("Error with Automatic Mouse Mover", msg)
}()
}
}
case <-time.After(timeout * time.Millisecond):
//timeout, do nothing
2019-04-19 22:52:37 +00:00
logger.Errorf("timeout happened after %vms while trying to move mouse", timeout)
}
2019-04-23 23:51:58 +00:00
} else {
logger.Infof("activity detected in the last %v seconds.", int(heartbeatInterval))
logger.Infof("Activity type:\n")
for activityType, times := range heartbeat.ActivityMap {
logger.Infof("activityType : %v times: %v\n", activityType, len(times))
if activityType == activity.MachineSleep {
isSystemSleeping = true
} else if activityType == activity.MachineWake {
isSystemSleeping = false
}
}
logger.Infof("\n\n\n")
}
case <-m.quit:
2019-04-19 22:52:37 +00:00
logger.Infof("stopping mouse mover")
2019-03-28 19:52:25 +00:00
m.updateRunningStatus(false)
activityTracker.Quit()
return
}
}
}(m)
}
2019-03-28 19:52:25 +00:00
func (m *MouseMover) isRunning() bool {
m.mutex.RLock()
defer m.mutex.RUnlock()
return m.runningStatus
}
func (m *MouseMover) updateRunningStatus(isRunning bool) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.runningStatus = isRunning
}
func moveAndCheck(movePixel int, mouseMoveSuccessCh chan bool) {
currentX, currentY := robotgo.GetMousePos()
moveToX := currentX + movePixel
moveToY := currentY + movePixel
robotgo.MoveMouse(moveToX, moveToY)
//check if mouse moved. Sometimes mac users need to give
//extra permission for controlling the mouse
movedX, movedY := robotgo.GetMousePos()
if movedX == currentX && movedY == currentY {
mouseMoveSuccessCh <- false
} else {
mouseMoveSuccessCh <- true
}
}
2019-03-27 23:10:07 +00:00
//Quit the app
func (m *MouseMover) Quit() {
//making it idempotent
2019-03-28 19:52:25 +00:00
if m != nil && m.isRunning() {
m.quit <- struct{}{}
}
2019-04-23 23:51:58 +00:00
if m.logFile != nil {
m.logFile.Close()
}
}
//GetInstance gets the singleton instance for mouse mover app
2019-03-27 23:10:07 +00:00
func GetInstance() *MouseMover {
if instance == nil {
2019-03-27 23:10:07 +00:00
instance = &MouseMover{}
}
return instance
}
2019-04-19 22:52:37 +00:00
func getLogger(m *MouseMover, doWriteToFile bool) *log.Logger {
logger := log.New()
logger.Formatter = &logrus.TextFormatter{
FullTimestamp: true,
}
if doWriteToFile {
logFile, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
logger.SetOutput(logFile)
m.logFile = logFile
}
return logger
}