summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/api/constants.go50
-rw-r--r--internal/api/data.go156
-rw-r--r--internal/api/handlers.go288
-rw-r--r--internal/api/types.go78
-rw-r--r--internal/api/utilities.go74
5 files changed, 360 insertions, 286 deletions
diff --git a/internal/api/constants.go b/internal/api/constants.go
new file mode 100644
index 0000000..1cd18ca
--- /dev/null
+++ b/internal/api/constants.go
@@ -0,0 +1,50 @@
+// 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 <https://www.gnu.org/licenses/>.
+
+package api
+
+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"
+)
diff --git a/internal/api/data.go b/internal/api/data.go
new file mode 100644
index 0000000..57ee53e
--- /dev/null
+++ b/internal/api/data.go
@@ -0,0 +1,156 @@
+// 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 <https://www.gnu.org/licenses/>.
+
+package api
+
+// Not const because can't use runtime append in const definition
+var (
+ normalIncidentTitles = []string{
+ "Database connection timeout",
+ "Unexpected 500 Internal Server Error",
+ "API rate limit exceeded",
+ "Missing authentication token",
+ "Service unavailable due to maintenance",
+ "Invalid request payload",
+ "Cross‑domain request blocked",
+ "SSL certificate expired",
+ "Memory leak detected in worker process",
+ "Database deadlock detected",
+ "Failed to serialize response",
+ "Cache miss leading to latency spike",
+ "Outdated API endpoint usage",
+ "Insufficient permissions for resource",
+ "Concurrent request overload",
+ "Unexpected null reference",
+ "Data consistency violation",
+ "Failed to enqueue background job",
+ "Rate limiter misconfigured",
+ "Unexpected null pointer exception",
+ }
+ normalIncidentDescriptions = []string{
+ "The database server failed to establish a connection within the allotted timeout period, causing API requests to hang and eventually fail.",
+ "The web service returned a generic 500 Internal Server Error due to an unhandled exception in the request handler.",
+ "Clients exceeded the predefined rate limit, resulting in throttled responses and temporary denial of service.",
+ "Incoming requests lacked a valid authentication token, leading to unauthorized access attempts.",
+ "The service was temporarily unavailable because of scheduled maintenance and infrastructure upgrades.",
+ "The request payload was malformed or missing required fields, causing validation errors.",
+ "Cross‑origin resource sharing (CORS) policy blocked the request from an unauthorized domain.",
+ "The SSL/TLS certificate had expired, preventing secure connections from clients.",
+ "A memory leak in the worker process caused gradual exhaustion of available RAM.",
+ "A deadlock occurred between database transactions, blocking all pending queries.",
+ "The response could not be serialized into JSON, leading to malformed output.",
+ "Cache misses caused a spike in latency as the backend had to recompute data.",
+ "Clients used deprecated API endpoints that are no longer supported.",
+ "The user lacked sufficient permissions to access the requested resource.",
+ "The server was overwhelmed by concurrent requests, exceeding its capacity limits.",
+ "A null reference exception was thrown during request processing.",
+ "Data integrity constraints were violated, causing transaction rollbacks.",
+ "Background job enqueuing failed due to a full queue or missing worker.",
+ "The rate limiter was misconfigured, allowing too many requests per interval.",
+ "A null pointer exception caused the service to crash during execution.",
+ }
+ mixedIncidentTitels = []string{
+ "Database connection timeout",
+ "Unexpected 500 error on /api/v1/users",
+ "Missing authentication token",
+ "Rate limit exceeded for client IP 192.168.1.42",
+ "Service unavailable due to maintenance",
+ "Malformed JSON payload",
+ "Cache miss leading to slow response",
+ "Duplicate request IDs detected",
+ "Circular dependency in microservices",
+ "Out-of-memory exception in worker thread",
+ "DNS resolution failure for external API",
+ "Malformed URL in webhook callback",
+ "Cat in the server room",
+ "Unexpected emoji in user profile",
+ "Randomly generated error: 42 is the answer",
+ }
+ mixedIncidentDescriptions = []string{
+ "The database server stopped accepting connections, causing a timeout for all client queries.",
+ "The `/api/v1/users` endpoint returned a 500 Internal Server Error due to an unhandled exception.",
+ "Requests were rejected because the authentication token was missing or malformed.",
+ "Requests from the IP `192.168.1.42` exceeded the rate limit, resulting in 429 responses.",
+ "The service was temporarily unavailable due to scheduled maintenance.",
+ "The API received malformed JSON, leading to a 400 Bad Request response.",
+ "The cache layer missed the key, forcing a slow database lookup.",
+ "Duplicate request IDs were detected, causing duplicate processing.",
+ "A circular dependency in the microservice architecture caused a deadlock.",
+ "The worker thread ran out of memory and crashed.",
+ "DNS resolution failed for an external API, blocking outbound calls.",
+ "A webhook callback URL contained invalid characters, causing a 400 error.",
+ "A stray cat wandered into the server room and triggered a physical security alarm.",
+ "User profiles contained unexpected emoji characters that broke rendering.",
+ "A random error message appeared: \"42 is the answer\", indicating a placeholder bug.",
+ }
+ sillyIncidentTitles = []string{
+ "The API returned a rainbow instead of JSON",
+ "All requests were answered with a GIF of a dancing cat",
+ "The service responded with a random haiku",
+ "The endpoint started singing opera",
+ "All data was encrypted with a secret handshake",
+ "The server replied with a fortune cookie message",
+ "The service accidentally sent a selfie of the developer",
+ "All responses were wrapped in a Shakespearean sonnet",
+ "The API returned a random meme image",
+ "The service responded with a countdown to the moon landing",
+ "All requests were answered with a joke about HTTP",
+ "The server sent back a playlist of elevator music",
+ "The endpoint replied with a random dad joke",
+ "All data was sorted alphabetically by the last letter",
+ "The service responded with a random emoji string",
+ "The API returned a random recipe",
+ "All responses were encoded in Morse code",
+ "The server replied with a random motivational quote",
+ "The endpoint responded with a random crossword clue",
+ "All requests were answered with a random song lyric",
+ "The service returned a random conspiracy theory",
+ "The API responded with a random horoscope",
+ "All data was shuffled like a deck of cards",
+ "The server replied with a random conspiracy theory",
+ "The endpoint responded with a random tongue twister",
+ }
+ sillyIncidentDescriptions = []string{
+ "The JSON parser returned a holographic rainbow that demanded cookies in exchange for schema validation.",
+ "Every API response included a looping dancing cat that judged your headers and sashayed through your CORS policy.",
+ "The server replied only in haiku and refused to switch out of seventeen syllables even when begged with ramen.",
+ "The endpoint belted operatic arias at 120 dB and required earplugs for POST requests.",
+ "Payloads were encrypted with a secret handshake, a wink, and a kazoo solo — mobile apps kept failing the kazoo step.",
+ "Responses arrived as fortune-cookie slips predicting uncanny laptop weather and advising investments in rubber ducks.",
+ "The API accidentally uploaded the lead dev's selfie wearing a cape and labeled it 'new JSON schema'.",
+ "Every error was delivered as a Shakespearean sonnet, complete with stage directions and a tragic '404 Romeo'.",
+ "Endpoints served meme PNGs captioned 'When your query times out but you're still fabulous' instead of data.",
+ "Responses counted down to the next moon landing in reverse, prompting clients to RSVP and NASA to ask why.",
+ "Headers contained nothing but increasingly elaborate HTTP puns, causing an epidemic of groans across the office.",
+ "Requests yielded a 45-minute elevator-music playlist narrated by a bored brass section and an oddly philosophical sheep.",
+ "Each response began with a groan-inducing dad joke and ended with 'Did you get it? No? Okay.'",
+ "Data was alphabetized by the last letter of each word, resulting in sentences like 'zoo apes banana' and much confusion.",
+ "Every field turned into a cryptic emoji cipher that required a three-hour romance with an online emoji oracle to decode.",
+ "The API returned microwave recipes involving glitter, two bananas, and an optional unicycle for garnish.",
+ "Responses blinked in Morse via server LEDs; clients had to tap along on toast to translate the payload.",
+ "The server replied with overenthusiastic motivational quotes, some signed 'Sincerely, Your Router'.",
+ "Each endpoint answered with a crossword clue so obscure it demanded a PhD in Breakfast Cereals.",
+ "Responses contained obscure song lyrics that led to several lawsuits from very offended shower singers.",
+ "The service offered a handcrafted conspiracy about pigeons, quantum routers, and a secret society of baristas.",
+ "Users received horoscopes telling their IPs to avoid Tuesdays and to invest heavily in chamomile tea.",
+ "Records were shuffled like a magician's deck, with the ace of spades mysteriously serving as the primary key.",
+ "The server spun a conspiracy about sentient staplers plotting to replace USB‑C with fashionable shoelaces.",
+ "Replies were impossible tongue twisters typed by the server while giggling, causing voice assistants to short out.",
+ }
+
+ allIncidentTitles = append(append(append([]string{}, normalIncidentTitles...), mixedIncidentTitels...), sillyIncidentTitles...)
+ allIncidentDescriptions = append(append(append([]string{}, normalIncidentDescriptions...), mixedIncidentTitels...), sillyIncidentDescriptions...)
+)
diff --git a/internal/api/handlers.go b/internal/api/handlers.go
index 2fedcdd..676f57f 100644
--- a/internal/api/handlers.go
+++ b/internal/api/handlers.go
@@ -22,10 +22,7 @@ import (
"io"
"math"
"math/rand"
- "net"
"net/http"
- "regexp"
- "strings"
"time"
)
@@ -91,48 +88,6 @@ func CreateLoginHandler(logs *[LogLength]string, n *int, toLogParser chan string
}
}
-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"
-)
-
-type statusData struct {
- overallStatus overallStatus
- services []service
- metrics metrics
- incidents []incident
- maintenanceEvents []maintenanceEvent
- uptimeEvents []uptimeEvent
-}
-
var status statusData
func init() {
@@ -223,12 +178,12 @@ func init() {
case <-tick10s.C:
runChance(1.0, func() {
severity := SeverityMinor
- runChance(0.3, func(){
+ runChance(0.3, func() {
severity = SeverityMajor
})
i := rand.Intn(int(math.Min(float64(len(allIncidentTitles)), float64(len(allIncidentDescriptions)))))
serviceStatus := StatusDown
- runChance(0.5, func(){
+ runChance(0.5, func() {
serviceStatus = StatusDegraded
})
status.incidents = append(status.incidents, incident{
@@ -248,70 +203,6 @@ func init() {
}()
}
-func runChance(likelihood float64, action func()) {
- if likelihood <= 0 {
- return // never run
- }
- if likelihood >= 1 {
- action()
- return
- }
-
- if rand.Float64() < likelihood {
- action()
- }
-}
-
-type overallStatus 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"`
-}
-
-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"`
-}
-
-type metrics struct {
- Uptime float64 `json:"uptime"`
- ResponseTime int `json:"responseTime"`
- RequestVolume int `json:"requestVolume"`
- ErrorRate float64 `json:"errorRate"`
-}
-
-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"`
-}
-
-type maintenanceEvent 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"`
-}
-
-type uptimeEvent struct {
- Date time.Time `json:"date"`
- Uptime float64 `json:"uptime"`
-}
-
func StatusHandler(w http.ResponseWriter, r *http.Request) {
jsonData, _ := json.Marshal(status.overallStatus)
fmt.Fprint(w, string(jsonData))
@@ -369,178 +260,3 @@ func CreateContactHandler(logs *[LogLength]string, n *int, toLogParser chan stri
fmt.Fprint(w, "{}")
}
}
-
-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
- }
- }
-}
-
-// Not const because can't use runtime append in const definition
-var (
- normalIncidentTitles = []string{
- "Database connection timeout",
- "Unexpected 500 Internal Server Error",
- "API rate limit exceeded",
- "Missing authentication token",
- "Service unavailable due to maintenance",
- "Invalid request payload",
- "Cross‑domain request blocked",
- "SSL certificate expired",
- "Memory leak detected in worker process",
- "Database deadlock detected",
- "Failed to serialize response",
- "Cache miss leading to latency spike",
- "Outdated API endpoint usage",
- "Insufficient permissions for resource",
- "Concurrent request overload",
- "Unexpected null reference",
- "Data consistency violation",
- "Failed to enqueue background job",
- "Rate limiter misconfigured",
- "Unexpected null pointer exception",
- }
- normalIncidentDescriptions = []string{
- "The database server failed to establish a connection within the allotted timeout period, causing API requests to hang and eventually fail.",
- "The web service returned a generic 500 Internal Server Error due to an unhandled exception in the request handler.",
- "Clients exceeded the predefined rate limit, resulting in throttled responses and temporary denial of service.",
- "Incoming requests lacked a valid authentication token, leading to unauthorized access attempts.",
- "The service was temporarily unavailable because of scheduled maintenance and infrastructure upgrades.",
- "The request payload was malformed or missing required fields, causing validation errors.",
- "Cross‑origin resource sharing (CORS) policy blocked the request from an unauthorized domain.",
- "The SSL/TLS certificate had expired, preventing secure connections from clients.",
- "A memory leak in the worker process caused gradual exhaustion of available RAM.",
- "A deadlock occurred between database transactions, blocking all pending queries.",
- "The response could not be serialized into JSON, leading to malformed output.",
- "Cache misses caused a spike in latency as the backend had to recompute data.",
- "Clients used deprecated API endpoints that are no longer supported.",
- "The user lacked sufficient permissions to access the requested resource.",
- "The server was overwhelmed by concurrent requests, exceeding its capacity limits.",
- "A null reference exception was thrown during request processing.",
- "Data integrity constraints were violated, causing transaction rollbacks.",
- "Background job enqueuing failed due to a full queue or missing worker.",
- "The rate limiter was misconfigured, allowing too many requests per interval.",
- "A null pointer exception caused the service to crash during execution.",
- }
- mixedIncidentTitels = []string{
- "Database connection timeout",
- "Unexpected 500 error on /api/v1/users",
- "Missing authentication token",
- "Rate limit exceeded for client IP 192.168.1.42",
- "Service unavailable due to maintenance",
- "Malformed JSON payload",
- "Cache miss leading to slow response",
- "Duplicate request IDs detected",
- "Circular dependency in microservices",
- "Out-of-memory exception in worker thread",
- "DNS resolution failure for external API",
- "Malformed URL in webhook callback",
- "Cat in the server room",
- "Unexpected emoji in user profile",
- "Randomly generated error: 42 is the answer",
- }
- mixedIncidentDescriptions = []string{
- "The database server stopped accepting connections, causing a timeout for all client queries.",
- "The `/api/v1/users` endpoint returned a 500 Internal Server Error due to an unhandled exception.",
- "Requests were rejected because the authentication token was missing or malformed.",
- "Requests from the IP `192.168.1.42` exceeded the rate limit, resulting in 429 responses.",
- "The service was temporarily unavailable due to scheduled maintenance.",
- "The API received malformed JSON, leading to a 400 Bad Request response.",
- "The cache layer missed the key, forcing a slow database lookup.",
- "Duplicate request IDs were detected, causing duplicate processing.",
- "A circular dependency in the microservice architecture caused a deadlock.",
- "The worker thread ran out of memory and crashed.",
- "DNS resolution failed for an external API, blocking outbound calls.",
- "A webhook callback URL contained invalid characters, causing a 400 error.",
- "A stray cat wandered into the server room and triggered a physical security alarm.",
- "User profiles contained unexpected emoji characters that broke rendering.",
- "A random error message appeared: \"42 is the answer\", indicating a placeholder bug.",
- }
- sillyIncidentTitles = []string{
- "The API returned a rainbow instead of JSON",
- "All requests were answered with a GIF of a dancing cat",
- "The service responded with a random haiku",
- "The endpoint started singing opera",
- "All data was encrypted with a secret handshake",
- "The server replied with a fortune cookie message",
- "The service accidentally sent a selfie of the developer",
- "All responses were wrapped in a Shakespearean sonnet",
- "The API returned a random meme image",
- "The service responded with a countdown to the moon landing",
- "All requests were answered with a joke about HTTP",
- "The server sent back a playlist of elevator music",
- "The endpoint replied with a random dad joke",
- "All data was sorted alphabetically by the last letter",
- "The service responded with a random emoji string",
- "The API returned a random recipe",
- "All responses were encoded in Morse code",
- "The server replied with a random motivational quote",
- "The endpoint responded with a random crossword clue",
- "All requests were answered with a random song lyric",
- "The service returned a random conspiracy theory",
- "The API responded with a random horoscope",
- "All data was shuffled like a deck of cards",
- "The server replied with a random conspiracy theory",
- "The endpoint responded with a random tongue twister",
- }
- sillyIncidentDescriptions = []string{
- "The JSON parser returned a holographic rainbow that demanded cookies in exchange for schema validation.",
- "Every API response included a looping dancing cat that judged your headers and sashayed through your CORS policy.",
- "The server replied only in haiku and refused to switch out of seventeen syllables even when begged with ramen.",
- "The endpoint belted operatic arias at 120 dB and required earplugs for POST requests.",
- "Payloads were encrypted with a secret handshake, a wink, and a kazoo solo — mobile apps kept failing the kazoo step.",
- "Responses arrived as fortune-cookie slips predicting uncanny laptop weather and advising investments in rubber ducks.",
- "The API accidentally uploaded the lead dev's selfie wearing a cape and labeled it 'new JSON schema'.",
- "Every error was delivered as a Shakespearean sonnet, complete with stage directions and a tragic '404 Romeo'.",
- "Endpoints served meme PNGs captioned 'When your query times out but you're still fabulous' instead of data.",
- "Responses counted down to the next moon landing in reverse, prompting clients to RSVP and NASA to ask why.",
- "Headers contained nothing but increasingly elaborate HTTP puns, causing an epidemic of groans across the office.",
- "Requests yielded a 45-minute elevator-music playlist narrated by a bored brass section and an oddly philosophical sheep.",
- "Each response began with a groan-inducing dad joke and ended with 'Did you get it? No? Okay.'",
- "Data was alphabetized by the last letter of each word, resulting in sentences like 'zoo apes banana' and much confusion.",
- "Every field turned into a cryptic emoji cipher that required a three-hour romance with an online emoji oracle to decode.",
- "The API returned microwave recipes involving glitter, two bananas, and an optional unicycle for garnish.",
- "Responses blinked in Morse via server LEDs; clients had to tap along on toast to translate the payload.",
- "The server replied with overenthusiastic motivational quotes, some signed 'Sincerely, Your Router'.",
- "Each endpoint answered with a crossword clue so obscure it demanded a PhD in Breakfast Cereals.",
- "Responses contained obscure song lyrics that led to several lawsuits from very offended shower singers.",
- "The service offered a handcrafted conspiracy about pigeons, quantum routers, and a secret society of baristas.",
- "Users received horoscopes telling their IPs to avoid Tuesdays and to invest heavily in chamomile tea.",
- "Records were shuffled like a magician's deck, with the ace of spades mysteriously serving as the primary key.",
- "The server spun a conspiracy about sentient staplers plotting to replace USB‑C with fashionable shoelaces.",
- "Replies were impossible tongue twisters typed by the server while giggling, causing voice assistants to short out.",
- }
-
- allIncidentTitles = append(append(append([]string{}, normalIncidentTitles...), mixedIncidentTitels...), sillyIncidentTitles...)
- allIncidentDescriptions = append(append(append([]string{}, normalIncidentDescriptions...), mixedIncidentTitels...), sillyIncidentDescriptions...)
-)
diff --git a/internal/api/types.go b/internal/api/types.go
new file mode 100644
index 0000000..c641004
--- /dev/null
+++ b/internal/api/types.go
@@ -0,0 +1,78 @@
+// 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 <https://www.gnu.org/licenses/>.
+
+package api
+
+import "time"
+
+type statusData struct {
+ overallStatus overallStatus
+ services []service
+ metrics metrics
+ incidents []incident
+ maintenanceEvents []maintenanceEvent
+ uptimeEvents []uptimeEvent
+}
+
+type overallStatus 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"`
+}
+
+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"`
+}
+
+type metrics struct {
+ Uptime float64 `json:"uptime"`
+ ResponseTime int `json:"responseTime"`
+ RequestVolume int `json:"requestVolume"`
+ ErrorRate float64 `json:"errorRate"`
+}
+
+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"`
+}
+
+type maintenanceEvent 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"`
+}
+
+type uptimeEvent struct {
+ Date time.Time `json:"date"`
+ Uptime float64 `json:"uptime"`
+}
diff --git a/internal/api/utilities.go b/internal/api/utilities.go
new file mode 100644
index 0000000..508e341
--- /dev/null
+++ b/internal/api/utilities.go
@@ -0,0 +1,74 @@
+// 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 <https://www.gnu.org/licenses/>.
+
+package api
+
+import (
+ "math/rand"
+ "net"
+ "regexp"
+ "strings"
+)
+
+func runChance(likelihood float64, action func()) {
+ if likelihood <= 0 {
+ return // never run
+ }
+ if likelihood >= 1 {
+ action()
+ return
+ }
+
+ if rand.Float64() < likelihood {
+ action()
+ }
+}
+
+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
+ }
+ }
+}