// This file is a part of Taskflow. // Copyright (C) 2025 Robby Zambito // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package api import ( "encoding/json" "fmt" "io" "net/http" "net" "strings" "regexp" "time" ) var fs http.Handler func init() { fs = http.FileServer(http.Dir("static")) } const LogLength = 100 type accessLog struct { ClientAddr string `json:"clientAddr"` RequestedPath string `json:"requestedPath"` RequestTime time.Time `json:"requestTime"` HttpMethod string `json:"httpMethod"` } func CreateFilesHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { jsonData, _ := json.Marshal(accessLog{ ClientAddr: redactIP(r.RemoteAddr), RequestedPath: r.URL.Path, RequestTime: time.Now().UTC(), HttpMethod: r.Method, }) addRotLog(logs, n, logChan, string(jsonData)) // Serve the index.html file from the static directory http.StripPrefix("/", fs).ServeHTTP(w, r) } } func CreateGetLogs(logs *[LogLength]string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { for _, s := range logs { fmt.Fprintln(w, s) } } } func CreateLoginHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } defer r.Body.Close() var data map[string]any if json.Unmarshal(body, &data) != nil { addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": %s}`, string(body))) http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized) return } if email, ok := data["email"].(string); ok { if rememberMe, ok := data["rememberMe"].(bool); ok { addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": {"email": "%s", "password": "XXXXXXXX", "loginTime": "%s", "success": false, "rememberMe": %t}}`, email, time.Now().UTC(), rememberMe)) } } http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized) } } const ( StatusOperational = "operational" StatusDegraded = "degraded" StatusDown = "down" ) const ( IconAPIGateway = "🔗" IconWeb = "🌐" IconAuth = "🔐" IconDB = "🗄️" IconStorage = "📁" IconNotifications = "📧" IconSearch = "🔍" IconAnalytics = "📊" ) const ( SeverityMinor = "minor" SeverityMajor = "major" ) const ( ServiceAPIGateway = "api" ServiceWeb = "web" ServiceAuth = "auth" ServiceDB = "database" ServiceStorage = "storage" ServiceNotifications = "notifications" ServiceSearch = "search" ServiceAnalytics = "analytics" ) func StatusHandler(w http.ResponseWriter, r *http.Request) { type response struct { Status string `json:"status"` Description string `json:"description"` Uptime float64 `json:"uptime"` ResponseTime int `json:"responseTime"` ActiveIncidents int `json:"activeIncidents"` ScheduledMaintenance int `json:"scheduledMaintenance"` } // res := response{ // Status: StatusDown, // Description: "Everything is on fire", // Uptime: 0.0, // ResponseTime: 0.0, // ActiveIncidents: 9001, // ScheduledMaintenance: 0, // } res := response{ Status: StatusDegraded, Description: "Everything is not great", Uptime: 50.0, ResponseTime: 20000, ActiveIncidents: 9001, ScheduledMaintenance: 1, } jsonData, _ := json.Marshal(res) // fmt.Printf("Overall: %s\n", string(jsonData)) fmt.Fprint(w, string(jsonData)) } func StatusServicesHandler(w http.ResponseWriter, r *http.Request) { type service struct { Id string `json:"id"` Name string `json:"name"` Description string `json:"description"` Icon string `json:"icon"` Status string `json:"status"` ResponseTime int `json:"responseTime"` Uptime float64 `json:"uptime"` } response := []service{} response = append(response, service{ Id: ServiceAPIGateway, Name: "API Gateway", Description: "Core API services", Icon: IconAPIGateway, Status: StatusOperational, ResponseTime: 50, Uptime: 69.420, }) response = append(response, service{ Id: "logs", Name: "Log Warden", Description: "The master of the Logs", Icon: "📜", Status: StatusOperational, ResponseTime: 69, Uptime: 99.999, }) jsonData, _ := json.Marshal(response) // fmt.Printf("ServicesStatus: %s\n", string(jsonData)) fmt.Fprint(w, string(jsonData)) } func StatusMetricsHandler(w http.ResponseWriter, r *http.Request) { type response struct { Uptime float64 `json:"uptime"` ResponseTime int `json:"responseTime"` RequestVolume int `json:"requestVolume"` ErrorRate float64 `json:"errorRate"` } res := response{ Uptime: 90.5, ResponseTime: 169, RequestVolume: 5, ErrorRate: 106.0, } jsonData, _ := json.Marshal(res) // fmt.Printf("Metrics: %s\n", string(jsonData)) fmt.Fprintf(w, string(jsonData)) } func StatusIncidentsHandler(w http.ResponseWriter, r *http.Request) { type incident struct { Id string `json:"id"` Title string `json:"title"` Description string `json:"description"` Status string `json:"status"` Severity string `json:"severity"` StartTime time.Time `json:"startTime"` AffectedServices []string `json:"affectedServices"` } response := []incident{} jsonData, _ := json.Marshal(response) // fmt.Printf("Incidents: %s\n", string(jsonData)) fmt.Fprintf(w, string(jsonData)) } func StatusMaintenanceHandler(w http.ResponseWriter, r *http.Request) { type event struct { Id string `json:"id"` Title string `json:"title"` Description string `json:"description"` StartTime time.Time `json:"startTime"` EndTime time.Time `json:"endTime"` AffectedServices []string `json:"affectedServices"` } response := []event{} jsonData, _ := json.Marshal(response) // fmt.Printf("Events: %s\n", string(jsonData)) fmt.Fprintf(w, string(jsonData)) } func StatusUptimeHandler(w http.ResponseWriter, r *http.Request) { type event struct { Date time.Time `json:"date"` Uptime float64 `json:"uptime"` } response := []event{} jsonData, _ := json.Marshal(response) // fmt.Printf("Uptime: %s\n", string(jsonData)) fmt.Fprintf(w, string(jsonData)) } // TODO: SUBSCRIBE TO EMAILS func StatusSubscribeHandler(w http.ResponseWriter, r *http.Request) { } // TODO: CONTACT HANDLER func ContactHandler(w http.ResponseWriter, r *http.Request) { } func redactIP(input string) string { ipRegex := `\b(?:\d{1,3}\.){3}\d{1,3}\b` re := regexp.MustCompile(ipRegex) return re.ReplaceAllStringFunc(input, func(match string) string { if ip := net.ParseIP(match); ip != nil { parts := strings.Split(match, ".") if len(parts) == 4 { parts[3] = "XXX" return strings.Join(parts, ".") } } return match }) } func addRotLog(logs *[LogLength]string, last *int, parser chan string, value string) { if strings.Contains(value, "\n") { for _, v := range strings.Split(value, "\n") { addRotLog(logs, last, parser, v) } } else { if *last == LogLength { for i := 0; i < LogLength-1; i++ { logs[i] = logs[i+1] } logs[LogLength-1] = value parser <- value } else { logs[*last] = value *last++ parser <- value } } }