forked from ops-class/test161
/
usage.go
100 lines (82 loc) · 2.18 KB
/
usage.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
package main
import (
"encoding/json"
"fmt"
"io"
"mime/multipart"
"os"
"path"
"time"
"github.com/jay1999ke/test161"
)
var usageFailDir string
func getFailedUsageFileName() string {
res := path.Join(usageFailDir, fmt.Sprintf("usage_%v.json.gz", time.Now().Unix()))
return res
}
type UsageStatsFileHandler struct {
hasError bool
header *multipart.FileHeader
}
func (handler *UsageStatsFileHandler) HandleFile(header *multipart.FileHeader,
req *test161.UploadRequest, students []*test161.Student) error {
// We'll defer grunt work to upload reader and just collect inflated lines.
lineChan := make(chan string)
reader := NewUploadFileReader(true, lineChan)
handler.header = header
handler.hasError = false
staff := false
env := submissionServer.GetEnv()
if len(students) > 0 {
staff, _ = students[0].IsStaff(env)
}
// We'll replace the user info with what comes in the validated request.
users := make([]string, 0)
for _, u := range req.Users {
users = append(users, u.Email)
}
go func() {
for line := range lineChan {
// Each line is a single usage log
var usageStat test161.UsageStat
if err := json.Unmarshal([]byte(line), &usageStat); err != nil {
handler.hasError = true
logger.Println("Invalid usage JSON:", line)
} else {
usageStat.Users = users
usageStat.IsStaff = staff
if err = usageStat.Persist(env); err != nil {
logger.Println("Error saving stat:", err)
}
}
}
}()
return reader.HandleFile(header)
}
func (handler *UsageStatsFileHandler) tryCopyFile() {
file, err := handler.header.Open()
if err != nil {
logger.Println("Failed to open the file for reading")
}
defer file.Close()
outFile := getFailedUsageFileName()
out, err := os.Create(outFile)
if err != nil {
logger.Printf("Failed to open '%v' file for writing.\n", outFile)
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
logger.Println("Failed to copy file:", err)
}
}
func (handler *UsageStatsFileHandler) FileComplete(err error) {
if err != nil || handler.hasError {
handler.tryCopyFile()
}
}
// Generator function for usage stats uploads
func GetUsageStatHandler() UploadHandler {
return &UsageStatsFileHandler{}
}