1
0

handlers.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package analytic
  2. import (
  3. "encoding/csv"
  4. "encoding/json"
  5. "log"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "imuslab.com/zoraxy/mod/statistic"
  11. "imuslab.com/zoraxy/mod/utils"
  12. )
  13. func (d *DataLoader) HandleSummaryList(w http.ResponseWriter, r *http.Request) {
  14. entries, err := d.Database.ListTable("stats")
  15. if err != nil {
  16. utils.SendErrorResponse(w, "unable to load data from database")
  17. return
  18. }
  19. entryDates := []string{}
  20. for _, keypairs := range entries {
  21. entryDates = append(entryDates, string(keypairs[0]))
  22. }
  23. js, _ := json.MarshalIndent(entryDates, "", " ")
  24. utils.SendJSONResponse(w, string(js))
  25. }
  26. func (d *DataLoader) HandleLoadTargetDaySummary(w http.ResponseWriter, r *http.Request) {
  27. day, err := utils.GetPara(r, "id")
  28. if err != nil {
  29. utils.SendErrorResponse(w, "id cannot be empty")
  30. return
  31. }
  32. if strings.Contains(day, "-") {
  33. //Must be underscore
  34. day = strings.ReplaceAll(day, "-", "_")
  35. }
  36. if !statistic.IsBeforeToday(day) {
  37. utils.SendErrorResponse(w, "given date is in the future")
  38. return
  39. }
  40. var targetDailySummary statistic.DailySummaryExport
  41. if day == time.Now().Format("2006_01_02") {
  42. targetDailySummary = *d.StatisticCollector.GetExportSummary()
  43. } else {
  44. //Not today data
  45. err = d.Database.Read("stats", day, &targetDailySummary)
  46. if err != nil {
  47. utils.SendErrorResponse(w, "target day data not found")
  48. return
  49. }
  50. }
  51. js, _ := json.Marshal(targetDailySummary)
  52. utils.SendJSONResponse(w, string(js))
  53. }
  54. func (d *DataLoader) HandleLoadTargetRangeSummary(w http.ResponseWriter, r *http.Request) {
  55. start, end, err := d.GetStartAndEndDatesFromRequest(r)
  56. if err != nil {
  57. utils.SendErrorResponse(w, err.Error())
  58. return
  59. }
  60. dailySummaries, _, err := d.GetAllStatisticSummaryInRange(start, end)
  61. if err != nil {
  62. utils.SendErrorResponse(w, err.Error())
  63. return
  64. }
  65. //Merge the summaries into one
  66. mergedSummary := mergeDailySummaryExports(dailySummaries)
  67. js, _ := json.Marshal(struct {
  68. Summary *statistic.DailySummaryExport
  69. Records []*statistic.DailySummaryExport
  70. }{
  71. Summary: mergedSummary,
  72. Records: dailySummaries,
  73. })
  74. utils.SendJSONResponse(w, string(js))
  75. }
  76. // Handle exporting of a given range statistics
  77. func (d *DataLoader) HandleRangeExport(w http.ResponseWriter, r *http.Request) {
  78. start, end, err := d.GetStartAndEndDatesFromRequest(r)
  79. if err != nil {
  80. utils.SendErrorResponse(w, err.Error())
  81. return
  82. }
  83. dailySummaries, dates, err := d.GetAllStatisticSummaryInRange(start, end)
  84. if err != nil {
  85. utils.SendErrorResponse(w, err.Error())
  86. return
  87. }
  88. format, err := utils.GetPara(r, "format")
  89. if err != nil {
  90. format = "json"
  91. }
  92. if format == "csv" {
  93. // Create a buffer to store CSV content
  94. var csvContent strings.Builder
  95. // Create a CSV writer
  96. writer := csv.NewWriter(&csvContent)
  97. // Write the header row
  98. header := []string{"Date", "TotalRequest", "ErrorRequest", "ValidRequest", "ForwardTypes", "RequestOrigin", "RequestClientIp", "Referer", "UserAgent", "RequestURL"}
  99. err := writer.Write(header)
  100. if err != nil {
  101. http.Error(w, err.Error(), http.StatusInternalServerError)
  102. return
  103. }
  104. // Write each data row
  105. for i, item := range dailySummaries {
  106. row := []string{
  107. dates[i],
  108. strconv.FormatInt(item.TotalRequest, 10),
  109. strconv.FormatInt(item.ErrorRequest, 10),
  110. strconv.FormatInt(item.ValidRequest, 10),
  111. // Convert map values to a comma-separated string
  112. strings.Join(mapToStringSlice(item.ForwardTypes), ","),
  113. strings.Join(mapToStringSlice(item.RequestOrigin), ","),
  114. strings.Join(mapToStringSlice(item.RequestClientIp), ","),
  115. strings.Join(mapToStringSlice(item.Referer), ","),
  116. strings.Join(mapToStringSlice(item.UserAgent), ","),
  117. strings.Join(mapToStringSlice(item.RequestURL), ","),
  118. }
  119. err = writer.Write(row)
  120. if err != nil {
  121. http.Error(w, err.Error(), http.StatusInternalServerError)
  122. return
  123. }
  124. }
  125. // Flush the CSV writer
  126. writer.Flush()
  127. // Check for any errors during writing
  128. if err := writer.Error(); err != nil {
  129. http.Error(w, err.Error(), http.StatusInternalServerError)
  130. return
  131. }
  132. // Set the response headers
  133. w.Header().Set("Content-Type", "text/csv")
  134. w.Header().Set("Content-Disposition", "attachment; filename=analytics_"+start+"_to_"+end+".csv")
  135. // Write the CSV content to the response writer
  136. _, err = w.Write([]byte(csvContent.String()))
  137. if err != nil {
  138. http.Error(w, err.Error(), http.StatusInternalServerError)
  139. return
  140. }
  141. } else if format == "json" {
  142. type exportData struct {
  143. Stats []*statistic.DailySummaryExport
  144. Dates []string
  145. }
  146. results := exportData{
  147. Stats: dailySummaries,
  148. Dates: dates,
  149. }
  150. js, _ := json.MarshalIndent(results, "", " ")
  151. w.Header().Set("Content-Disposition", "attachment; filename=analytics_"+start+"_to_"+end+".json")
  152. utils.SendJSONResponse(w, string(js))
  153. } else {
  154. utils.SendErrorResponse(w, "Unsupported export format")
  155. }
  156. }
  157. // Reset all the keys within the given time period
  158. func (d *DataLoader) HandleRangeReset(w http.ResponseWriter, r *http.Request) {
  159. start, end, err := d.GetStartAndEndDatesFromRequest(r)
  160. if err != nil {
  161. utils.SendErrorResponse(w, err.Error())
  162. return
  163. }
  164. if r.Method != http.MethodDelete {
  165. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  166. return
  167. }
  168. keys, err := generateDateRange(start, end)
  169. if err != nil {
  170. utils.SendErrorResponse(w, err.Error())
  171. return
  172. }
  173. for _, key := range keys {
  174. log.Println("DELETING statistics " + key)
  175. d.Database.Delete("stats", key)
  176. if isTodayDate(key) {
  177. //It is today's date. Also reset statistic collector value
  178. log.Println("RESETING today's in-memory statistics")
  179. d.StatisticCollector.ResetSummaryOfDay()
  180. }
  181. }
  182. utils.SendOK(w)
  183. }