Merge pull request #1 from FernandoJVideira/helper-flags
This commit is contained in:
@@ -87,6 +87,10 @@ gisem_presencas.exe -w value
|
|||||||
## Flags
|
## Flags
|
||||||
|
|
||||||
- `-w` or `-wait`: Time to wait in between refreshes (default is 10 seconds).
|
- `-w` or `-wait`: Time to wait in between refreshes (default is 10 seconds).
|
||||||
|
- `-l` or `-log`: Send the output to a file.
|
||||||
|
- `-m` or `-maxtime`: Sets a maxmium time for the program to try set Attendance (default is -1 (forever)).
|
||||||
|
- `-r` or `-replace`: Forces the program into replacing the existing saved credentials.
|
||||||
|
- `-v` or `-verbose`: Shows addicional info.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os" // added for logging to file
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chromedp/chromedp"
|
"github.com/chromedp/chromedp"
|
||||||
@@ -14,21 +15,75 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var waitTime int
|
var waitTime int
|
||||||
|
var isVerbose bool
|
||||||
|
var maxTime int
|
||||||
|
var logFile string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//* Parse the flags
|
//* Parse the flags
|
||||||
wait, headless, err := parseFlags()
|
wait, verbose, headless, logFile, timeout, replacePass, err := parseFlags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to parse flags: %v", err)
|
log.Fatalf("Failed to parse flags: %v", err)
|
||||||
}
|
}
|
||||||
waitTime = wait
|
waitTime = wait
|
||||||
|
isVerbose = verbose
|
||||||
|
maxTime = timeout
|
||||||
|
if logFile != "" {
|
||||||
|
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to open log file: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
log.SetOutput(file)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Waiting time:", waitTime)
|
if isVerbose {
|
||||||
|
fmt.Println("Waiting time:", waitTime)
|
||||||
|
fmt.Println("Verbose mode:", isVerbose)
|
||||||
|
fmt.Println("Headless mode:", headless)
|
||||||
|
if logFile == "" {
|
||||||
|
fmt.Println("Logging to file: disabled")
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fmt.Println("Logging to file:", logFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxTime == -1 {
|
||||||
|
log.Println("Max time: disabled")
|
||||||
|
} else {
|
||||||
|
log.Println("Max time:", maxTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//* Welcome message
|
//* Welcome message
|
||||||
welcomeMessage()
|
welcomeMessage()
|
||||||
|
|
||||||
|
if logFile != "" {
|
||||||
|
fmt.Println("Logging to file:", logFile)
|
||||||
|
fmt.Println("(No text will be shown because logging is enabled, dont worry, the program is still running)")
|
||||||
|
log.Print("Starting new program... (logging to file)\n\n")
|
||||||
|
isVerbose = true
|
||||||
|
|
||||||
|
if maxTime == -1 {
|
||||||
|
log.Println("Max time: disabled")
|
||||||
|
} else {
|
||||||
|
log.Println("Max time:", maxTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
creds, err := getCreds()
|
creds, err := getCreds()
|
||||||
|
|
||||||
|
if replacePass {
|
||||||
|
creds, err = promptAndSaveCreds(credFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to get credentials: %v", err)
|
||||||
|
}
|
||||||
|
if isVerbose {
|
||||||
|
log.Println("Credentials replaced")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the credentials file doesn't exist, prompt for credentials
|
// If the credentials file doesn't exist, prompt for credentials
|
||||||
if err.Error() == "credentials file not found: stat "+credFile+": no such file or directory" {
|
if err.Error() == "credentials file not found: stat "+credFile+": no such file or directory" {
|
||||||
@@ -59,6 +114,9 @@ func main() {
|
|||||||
log.Fatalf("Failed to navigate: %v", err)
|
log.Fatalf("Failed to navigate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isVerbose {
|
||||||
|
log.Println("Navigated to the website")
|
||||||
|
}
|
||||||
//* Check if there's a login button
|
//* Check if there's a login button
|
||||||
var isVisible bool
|
var isVisible bool
|
||||||
if err := chromedp.Run(ctx, chromedp.Tasks{
|
if err := chromedp.Run(ctx, chromedp.Tasks{
|
||||||
@@ -68,15 +126,25 @@ func main() {
|
|||||||
log.Fatalf("Failed to evaluate: %v", err)
|
log.Fatalf("Failed to evaluate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isVerbose {
|
||||||
|
log.Println("Login button visible:", isVisible)
|
||||||
|
}
|
||||||
|
|
||||||
if isVisible {
|
if isVisible {
|
||||||
log.Println("Logging in...")
|
log.Println("Logging in...")
|
||||||
if err := login(ctx, creds); err != nil {
|
if err := login(ctx, creds); err != nil {
|
||||||
log.Fatalf("Failed to login: %v", err)
|
log.Fatalf("Failed to login: %v", err)
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
log.Println("Waiting for activation...")
|
log.Println("Logged in!")
|
||||||
|
if isVerbose {
|
||||||
|
log.Println("Waiting for activation...")
|
||||||
|
}
|
||||||
if err := marcarPresenca(ctx); err != nil {
|
if err := marcarPresenca(ctx); err != nil {
|
||||||
log.Fatalf("Failed to mark presence: %v", err)
|
log.Println("Failed to mark presence: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("Presence marked!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Print("Program finished successfully! (logging to file) \n\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -106,24 +107,37 @@ func decrypt(encryptedHex, passphrase string) (string, error) {
|
|||||||
return string(plaintext), nil
|
return string(plaintext), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFlags() (int, bool, error) {
|
func parseFlags() (int, bool, bool, string, int, bool, error) {
|
||||||
//* Set the flags
|
//* Set the flags
|
||||||
wait := flag.Int("w", 10, "Time to wait in between refreshes")
|
wait := flag.Int("w", 10, "\tTime to wait in between refreshes")
|
||||||
flag.IntVar(wait, "wait", 10, "Time to wait in between refreshes")
|
flag.IntVar(wait, "wait", 10, "\tTime to wait in between refreshes")
|
||||||
|
|
||||||
|
// Verbose mode
|
||||||
|
isVerbose := flag.Bool("v", false, "\tEnable verbose mode")
|
||||||
|
flag.BoolVar(isVerbose, "verbose", false, "\tEnable verbose mode")
|
||||||
|
|
||||||
// By default, run in headless mode
|
// By default, run in headless mode
|
||||||
headless := flag.Bool("h", true, "Run in headless mode")
|
headless := flag.Bool("h", true, "\tRun in headless mode")
|
||||||
flag.BoolVar(headless, "headless", true, "Run in headless mode")
|
flag.BoolVar(headless, "headless", true, "\tRun in headless mode")
|
||||||
|
|
||||||
|
// Log to file
|
||||||
|
logFile := flag.String("l", "", "\tLog output to file")
|
||||||
|
flag.StringVar(logFile, "log", "", "\tLog output to file")
|
||||||
|
|
||||||
|
// Maximum time to run the program (minutes)
|
||||||
|
maxTime := flag.Int("m", -1, "\tMaximum time to run the program (minutes)")
|
||||||
|
flag.IntVar(maxTime, "maxtime", -1, "\tMaximum time to run the program (minutes)")
|
||||||
|
|
||||||
|
replacePass := flag.Bool("r", false, "\tReplace saved credentials")
|
||||||
|
flag.BoolVar(replacePass, "replace", false, "\tReplace saved credentials")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *wait < 0 {
|
if *wait < 0 {
|
||||||
return 0, false, fmt.Errorf("invalid wait time: %d", *wait)
|
return 0, false, false, "", -1, false, fmt.Errorf("invalid wait time: %d", *wait)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(*headless)
|
return *wait, *isVerbose, *headless, *logFile, *maxTime, *replacePass, nil
|
||||||
|
|
||||||
return *wait, *headless, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func welcomeMessage() {
|
func welcomeMessage() {
|
||||||
@@ -253,7 +267,7 @@ func saveCreds(filePath, username, password string) (Credentials, error) {
|
|||||||
return Credentials{}, fmt.Errorf("could not write credentials to file: %v", err)
|
return Credentials{}, fmt.Errorf("could not write credentials to file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Credentials saved successfully!")
|
log.Println("Credentials saved successfully!")
|
||||||
return creds, nil
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +293,12 @@ func login(ctx context.Context, creds Credentials) error {
|
|||||||
func marcarPresenca(ctx context.Context) error {
|
func marcarPresenca(ctx context.Context) error {
|
||||||
var attempt int
|
var attempt int
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
if isVerbose || maxTime != -1 {
|
||||||
|
log.Printf("Starting attendance registration at %s\n", startTime.Format(time.RFC1123))
|
||||||
|
}
|
||||||
|
|
||||||
for attempt = 1; attempt <= maxRetries; attempt++ {
|
for attempt = 1; attempt <= maxRetries; attempt++ {
|
||||||
if err := chromedp.Run(ctx,
|
if err := chromedp.Run(ctx,
|
||||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||||
@@ -286,23 +306,23 @@ func marcarPresenca(ctx context.Context) error {
|
|||||||
waitCtx, cancel := context.WithTimeout(ctx, time.Duration(waitTime)*time.Second)
|
waitCtx, cancel := context.WithTimeout(ctx, time.Duration(waitTime)*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
//Try to wait for the element
|
|
||||||
err := chromedp.Run(waitCtx,
|
err := chromedp.Run(waitCtx,
|
||||||
chromedp.WaitVisible(menuPresencas))
|
chromedp.WaitVisible(menuPresencas))
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Println("Navigation menu is visible!")
|
if isVerbose && logFile != "" {
|
||||||
|
log.Println("Navigation menu is visible!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chromedp.Run(waitCtx, chromedp.Click(menuPresencas))
|
chromedp.Run(waitCtx, chromedp.Click(menuPresencas))
|
||||||
fmt.Println("Navigation menu clicked!")
|
|
||||||
var currentURL string
|
var currentURL string
|
||||||
if err := chromedp.Location(¤tURL).Do(ctx); err != nil {
|
if err := chromedp.Location(¤tURL).Do(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if strings.Contains(currentURL, "obterAulasMarcarPresenca") {
|
if strings.Contains(currentURL, "obterAulasMarcarPresenca") {
|
||||||
fmt.Println("Attendance page loaded!")
|
log.Println("Attendance page loaded :", time.Now().Format(time.RFC1123))
|
||||||
fmt.Println("Registering attendance...")
|
log.Println("Registering attendance... : ", time.Now().Format(time.RFC1123))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +330,14 @@ func marcarPresenca(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(waitTime) * time.Second)
|
time.Sleep(time.Duration(waitTime) * time.Second)
|
||||||
|
|
||||||
|
if maxTime != -1 {
|
||||||
|
elapsedMinutes := time.Since(startTime).Minutes()
|
||||||
|
if int(elapsedMinutes) >= maxTime {
|
||||||
|
log.Println("Maximum time reached, attendance not registered", time.Now().Format(time.RFC1123))
|
||||||
|
return errors.New("maximum time reached")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}),
|
}),
|
||||||
@@ -327,11 +355,11 @@ func marcarPresenca(ctx context.Context) error {
|
|||||||
select {
|
select {
|
||||||
case alertMessage := <-ch:
|
case alertMessage := <-ch:
|
||||||
if strings.Contains(alertMessage, "sucesso") {
|
if strings.Contains(alertMessage, "sucesso") {
|
||||||
fmt.Println("Attendance registered successfully!")
|
log.Println("Attendance registered successfully! : ", time.Now().Format(time.RFC1123))
|
||||||
} else if strings.Contains(alertMessage, "anteriormente") {
|
} else if strings.Contains(alertMessage, "anteriormente") {
|
||||||
fmt.Println("Attendance previously registered!")
|
log.Println("Attendance previously registered! : ", time.Now().Format(time.RFC1123))
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Error registering attendance: ", alertMessage)
|
log.Println("Error registering attendance: ", alertMessage)
|
||||||
}
|
}
|
||||||
case <-time.After(time.Duration(waitTime) * time.Second):
|
case <-time.After(time.Duration(waitTime) * time.Second):
|
||||||
return fmt.Errorf("timeout waiting for alert")
|
return fmt.Errorf("timeout waiting for alert")
|
||||||
@@ -339,6 +367,10 @@ func marcarPresenca(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}),
|
}),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
// Check if the error was due to maximum time reached
|
||||||
|
if err.Error() == "maximum time reached" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
log.Printf("Attempt %d: Failed to register attendance: %v", attempt, err)
|
log.Printf("Attempt %d: Failed to register attendance: %v", attempt, err)
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
continue
|
continue
|
||||||
|
|||||||
Reference in New Issue
Block a user