2019-03-20 19:44:51 +00:00
package mousemover
import (
2019-04-19 22:52:37 +00:00
"fmt"
2019-03-20 19:44:51 +00:00
"time"
"github.com/go-vgo/robotgo"
2019-04-23 23:51:58 +00:00
"github.com/prashantgupta24/activity-tracker/pkg/activity"
2019-03-20 19:44:51 +00:00
"github.com/prashantgupta24/activity-tracker/pkg/tracker"
)
2019-03-27 23:10:07 +00:00
var instance * MouseMover
2019-03-20 19:44:51 +00:00
const (
2019-04-19 22:52:37 +00:00
timeout = 100 //ms
2019-04-24 00:26:56 +00:00
logDir = "log"
2019-06-30 04:57:20 +00:00
logFileName = "logFile-amm-5"
2019-03-20 19:44:51 +00:00
)
2023-08-28 14:33:01 +00:00
// Start the main app
2019-03-27 23:10:07 +00:00
func ( m * MouseMover ) Start ( ) {
2019-05-01 01:53:53 +00:00
if m . state . isRunning ( ) {
2019-03-28 19:52:25 +00:00
return
}
2019-05-01 01:53:53 +00:00
m . state = & state { }
2019-03-20 19:44:51 +00:00
m . quit = make ( chan struct { } )
2019-04-11 01:47:01 +00:00
heartbeatInterval := 60 //value always in seconds
2019-04-19 22:52:37 +00:00
workerInterval := 10
2019-04-11 01:47:01 +00:00
2019-03-20 19:44:51 +00:00
activityTracker := & tracker . Instance {
2019-04-11 01:47:01 +00:00
HeartbeatInterval : heartbeatInterval ,
WorkerInterval : workerInterval ,
2021-08-19 19:01:17 +00:00
// LogLevel: "debug", //if we want verbose logging
2019-03-20 19:44:51 +00:00
}
heartbeatCh := activityTracker . Start ( )
2019-04-27 01:05:16 +00:00
m . run ( heartbeatCh , activityTracker )
2019-04-24 00:41:01 +00:00
}
2019-03-20 19:44:51 +00:00
2019-04-27 01:05:16 +00:00
func ( m * MouseMover ) run ( heartbeatCh chan * tracker . Heartbeat , activityTracker * tracker . Instance ) {
go func ( ) {
2019-05-01 01:53:53 +00:00
state := m . state
if state != nil && state . isRunning ( ) {
2019-04-27 01:05:16 +00:00
return
}
2019-05-01 01:53:53 +00:00
state . updateRunningStatus ( true )
2019-05-03 00:58:01 +00:00
logger := getLogger ( m , false , logFileName ) //set writeToFile=true only for debugging
2019-03-20 19:44:51 +00:00
movePixel := 10
for {
select {
case heartbeat := <- heartbeatCh :
2019-03-28 20:38:01 +00:00
if ! heartbeat . WasAnyActivity {
2019-05-01 01:53:53 +00:00
if state . isSystemSleeping ( ) {
2019-04-23 23:51:58 +00:00
logger . Infof ( "system sleeping" )
continue
}
2019-03-28 22:02:36 +00:00
mouseMoveSuccessCh := make ( chan bool )
2019-05-01 01:53:53 +00:00
go moveAndCheck ( state , movePixel , mouseMoveSuccessCh )
2019-03-20 19:44:51 +00:00
select {
2019-03-28 22:02:36 +00:00
case wasMouseMoveSuccess := <- mouseMoveSuccessCh :
2019-03-20 19:44:51 +00:00
if wasMouseMoveSuccess {
2019-05-01 01:53:53 +00:00
state . updateLastMouseMovedTime ( time . Now ( ) )
2019-06-30 04:57:20 +00:00
logger . Infof ( "Is system sleeping? : %v : moved mouse at : %v\n\n" , state . isSystemSleeping ( ) , state . getLastMouseMovedTime ( ) )
2019-03-20 19:44:51 +00:00
movePixel *= - 1
2019-05-01 01:53:53 +00:00
state . updateDidNotMoveCount ( 0 )
2019-03-28 22:02:36 +00:00
} else {
2019-05-01 01:53:53 +00:00
didNotMoveCount := state . getDidNotMoveCount ( )
state . updateDidNotMoveCount ( didNotMoveCount + 1 )
2022-10-04 04:37:39 +00:00
state . updateLastErrorTime ( time . Now ( ) )
msg := fmt . Sprintf ( "Mouse pointer cannot be moved at %v. Last moved at %v. Happened %v times. (Only notifies once every 24 hours.) See README for details." ,
2019-05-01 01:53:53 +00:00
time . Now ( ) , state . getLastMouseMovedTime ( ) , state . getDidNotMoveCount ( ) )
2019-04-19 22:52:37 +00:00
logger . Errorf ( msg )
2022-10-04 04:37:39 +00:00
if state . getDidNotMoveCount ( ) >= 10 && ( time . Since ( state . lastErrorTime ) . Hours ( ) > 24 ) { //show only 1 error in a 24 hour window
2019-04-19 22:52:37 +00:00
go func ( ) {
2023-08-28 14:33:01 +00:00
robotgo . Alert ( "Error with Automatic Mouse Mover" , msg )
2019-04-19 22:52:37 +00:00
} ( )
}
2019-03-20 19:44:51 +00:00
}
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-03-20 19:44:51 +00:00
}
2019-04-23 23:51:58 +00:00
} else {
2019-04-27 01:05:16 +00:00
logger . Infof ( "activity detected in the last %v seconds." , int ( activityTracker . HeartbeatInterval ) )
2019-04-23 23:51:58 +00:00
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 {
2019-05-01 01:53:53 +00:00
state . updateMachineSleepStatus ( true )
2019-06-30 04:57:20 +00:00
logger . Infof ( "system sleep registered. Is system sleeping? : %v" , state . isSystemSleeping ( ) )
break
2019-05-11 00:54:56 +00:00
} else {
2019-05-01 01:53:53 +00:00
state . updateMachineSleepStatus ( false )
2019-04-23 23:51:58 +00:00
}
}
logger . Infof ( "\n\n\n" )
2019-03-20 19:44:51 +00:00
}
case <- m . quit :
2019-04-19 22:52:37 +00:00
logger . Infof ( "stopping mouse mover" )
2019-05-01 01:53:53 +00:00
state . updateRunningStatus ( false )
2019-03-20 19:44:51 +00:00
activityTracker . Quit ( )
return
}
}
2019-04-27 01:05:16 +00:00
} ( )
2019-03-20 19:44:51 +00:00
}
2023-08-28 14:33:01 +00:00
// Quit the app
2019-03-27 23:10:07 +00:00
func ( m * MouseMover ) Quit ( ) {
2019-03-20 19:44:51 +00:00
//making it idempotent
2019-05-01 01:53:53 +00:00
if m != nil && m . state . isRunning ( ) {
2019-03-20 19:44:51 +00:00
m . quit <- struct { } { }
}
2019-04-23 23:51:58 +00:00
if m . logFile != nil {
m . logFile . Close ( )
}
2019-03-20 19:44:51 +00:00
}
2023-08-28 14:33:01 +00:00
// GetInstance gets the singleton instance for mouse mover app
2019-03-27 23:10:07 +00:00
func GetInstance ( ) * MouseMover {
2019-03-20 19:44:51 +00:00
if instance == nil {
2019-05-01 01:53:53 +00:00
instance = & MouseMover {
state : & state { } ,
}
2019-03-20 19:44:51 +00:00
}
return instance
}