-
Notifications
You must be signed in to change notification settings - Fork 0
/
reporthandlers.go
138 lines (114 loc) · 3.06 KB
/
reporthandlers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"github.com/gin-gonic/gin"
)
// report list handler
func reportListHandler(c *gin.Context) {
list := m.GetSummary()
logger.Info("Returning built-in reportlist.", "num", len(list))
c.JSON(http.StatusOK, list)
}
// embeded report handler
type ReportReq struct {
Name string `uri:"name" binding:"required"`
}
func reportHandler(c *gin.Context) {
var req ReportReq
if err := c.ShouldBindUri(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"msg": "invalid report request"})
return
}
logger.Info("Rendering built-in report", "name", req.Name)
p, err := m.GetProvider(req.Name)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
return
}
c.HTML(http.StatusOK, p.GetTemplate(), p.GetPayload())
}
// download handler
type DownloadReq struct {
Name string `json:"name"` // embeded report name
Uri string `json:"uri"` // or, a report uri
}
func getReportUri(req DownloadReq) (string, error) {
if req.Name == "" && req.Uri == "" {
return "", fmt.Errorf("name and uri cannot be empty at the same time")
}
if req.Name != "" && req.Uri != "" {
return "", fmt.Errorf("name and uri cannot be specified at the same time")
}
if req.Name != "" {
// built in report
if _, err := m.GetProvider(req.Name); err != nil {
return "", err
}
// Try to generate the report uri based on its name
return fmt.Sprintf(EmbededReportUriFmtString, config.Port, req.Name), nil
} else {
// external url, ensure it's valid
ret, err := url.Parse(req.Uri)
if err != nil {
return "", err
}
if (ret.Scheme != "http" && ret.Scheme != "https") || ret.Host == "" {
return "", errors.New("invalid schema or host in the uri")
}
return req.Uri, nil
}
}
func getTempFileName() (string, error) {
f, err := os.CreateTemp("", "*.pdf")
if err != nil {
return "", err
}
// We need to close the file
f.Close()
return f.Name(), nil
}
func downloadHandler(c *gin.Context) {
var req DownloadReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
return
}
// Validate and get report uri
uri, err := getReportUri(req)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
return
}
logger.Info("Generating report from uri", "uri", uri)
// get temp file name
tempFile, err := getTempFileName()
if err != nil {
logger.Error("Failed to create temp file.", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"msg": "create report file failed"})
return
}
defer os.Remove(tempFile)
// Run report generation
cmd := exec.Command(
"chromium",
"--no-sandbox",
"--headless",
"-disable-gpu",
"--no-pdf-header-footer",
fmt.Sprintf("--print-to-pdf=%s", tempFile),
fmt.Sprintf("--timeout=%d", config.ChromiumTimeoutSeconds),
uri,
)
if err = cmd.Run(); err != nil {
logger.Error("Report generation failed.", "error", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"msg": "report generation failed"})
return
}
// Return the file
c.File(tempFile)
}