package main import ( "bytes" "fmt" "html/template" "log" "net/http" "os" "os/exec" "path/filepath" "time" "github.com/joho/godotenv" ) const logFilePath = "monitor.log" const testFilePath = "test.sh" func main() { // Load the .env file err := godotenv.Load() if err != nil { // Try to load the .env.example file fmt.Println("Error loading .env file, trying .env.example") err = godotenv.Load(".env.example") if err != nil { log.Fatal("Error loading .env.example file") } } // Start ticker go startTicker() // Start the server http.HandleFunc("/", mainHandler) http.HandleFunc("/assets/", assetHandler) fmt.Println("Starting server on http://127.0.0.1:3000 ...") log.Fatal(http.ListenAndServe(":3000", nil)) } func mainHandler(w http.ResponseWriter, r *http.Request) { // Sanitize the path to prevent directory traversal attacks relPath := r.URL.Path if relPath == "/" { relPath = "/index" } // Check method switch r.Method { case http.MethodGet: getHandler(relPath, w, r) case http.MethodPost: postHandler(relPath, w, r) default: errorPage(405, w, r) } } func getHandler(relPath string, w http.ResponseWriter, r *http.Request) { tmplPath := filepath.Join("templates", filepath.Clean(relPath)+".html") // Get message from Env message := os.Getenv("MESSAGE") // Parse the template tmpl, err := template.ParseFiles(tmplPath) if err != nil { errorPage(404, w, r) return } // Try to get monitor.log file logData, err := os.ReadFile(logFilePath) if err != nil { logData = []byte("No log file found") } else { // Keep any lines that don't contain test and invert line order lines := bytes.Split(logData, []byte("\n")) var newLines [][]byte for i := len(lines) - 1; i >= 0; i-- { if !bytes.Contains(lines[i], []byte("Test")) { newLines = append(newLines, lines[i]) } } // Add latest test line (excluding the last line which is empty) newLines = append(newLines, lines[len(lines)-2]) logData = bytes.Join(newLines, []byte("\n")) } // Create a map to hold the data requestData := map[string]interface{}{"envMessage": message, "logContent": string(logData)} // Execute the template err = tmpl.Execute(w, requestData) if err != nil { http.Error(w, "Error rendering template", http.StatusInternalServerError) } } func postHandler(relPath string, w http.ResponseWriter, r *http.Request) { switch relPath { case "/index": indexPostHandler(w, r) default: errorPage(405, w, r) } } func indexPostHandler(w http.ResponseWriter, r *http.Request) { // Parse the form data err := r.ParseForm() if err != nil { errorPage(500, w, r) return } // Get the form data message := r.FormValue("message") // Print the message to the console log.Printf("Message: %s", message) // Create a map to hold the data requestData := map[string]interface{}{ "message": message, } // Return a page with message tmpl, err := template.ParseFiles("templates/index.html") if err != nil { errorPage(500, w, r) return } err = tmpl.Execute(w, requestData) if err != nil { errorPage(500, w, r) } } func errorPage(errorCode int, w http.ResponseWriter, r *http.Request) { w.WriteHeader(errorCode) tmpl, err := template.ParseFiles("templates/error.html") if err != nil { log.Printf("Error loading error page template: %v", err) http.Error(w, "Error loading error page", http.StatusInternalServerError) return } errorMsgs := map[int]string{ 404: "Page not found for " + r.URL.Path, 405: "Method not allowed", 500: "Internal server error", } // Check if errorcode isn't in the map if _, ok := errorMsgs[errorCode]; !ok { errorCode = 500 } // Correcting the initialization of the errorData map errorData := map[string]interface{}{ "short": errorCode, "long": errorMsgs[errorCode], } err = tmpl.Execute(w, errorData) if err != nil { log.Printf("Error executing error page template: %v", err) http.Error(w, "Error rendering error page", http.StatusInternalServerError) } } func assetHandler(w http.ResponseWriter, r *http.Request) { // Serve static files from templates/assets http.ServeFile(w, r, filepath.Join("templates", filepath.Clean(r.URL.Path))) } func startTicker() { ticker := time.NewTicker(10 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: runBashScript() } } } func runBashScript() { // Log the time log.Printf("Running script at %v", time.Now()) cmd := exec.Command("bash", testFilePath) var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out err := cmd.Run() if err != nil { log.Printf("Error running script: %v", err) return } }