The server for Open Course World
1package dump_view
2
3import (
4 "fmt"
5 "smm2_gameserver/db/dump"
6 "smm2_gameserver/db/view"
7 "smm2_gameserver/nex/connection/user"
8 "smm2_gameserver/nex/datastore"
9)
10
11func (s *DumpView) SearchCourses(state *user.State, param view.SearchCoursesParam) ([]datastore.CourseInfo, []uint32, bool, error) {
12 switch param.Type {
13 case "posted_by":
14 courses, err := s.GetCoursesTypeBy(state, "user_posted", param.Pids, param.Offset, param.Size)
15 return courses, []uint32{}, len(courses) != 0, err
16 case "liked_by":
17 courses, err := s.GetCoursesTypeBy(state, "user_liked", param.Pids, param.Offset, param.Size)
18 return courses, []uint32{}, len(courses) != 0, err
19 case "first_clear_by":
20 courses, err := s.GetCoursesTypeBy(state, "user_first_cleared", param.Pids, param.Offset, param.Size)
21 return courses, []uint32{}, len(courses) != 0, err
22 case "played_by":
23 courses, err := s.GetCoursesTypeBy(state, "user_played", param.Pids, param.Offset, param.Size)
24 return courses, []uint32{}, len(courses) != 0, err
25 case "world_record_by":
26 courses, err := s.GetCoursesTypeBy(state, "user_world_record", param.Pids, param.Offset, param.Size)
27 return courses, []uint32{}, len(courses) != 0, err
28 case "latest":
29 courses, err := s.GetCoursesLatest(state, param.Offset, param.Size)
30 return courses, []uint32{}, len(courses) != 0, err
31 case "endless":
32 courses, err := s.GetEndlessCourses(state, param.Size, param.Difficulty)
33 return courses, []uint32{}, len(courses) != 0, err
34 default:
35 fmt.Printf("SearchCourses type not supported yet: %s\n", param.Type)
36 }
37
38 return []datastore.CourseInfo{}, []uint32{}, false, nil
39}
40
41func (s *DumpView) GetDumpEndlessCourses(state *user.State, size uint32, difficulty uint8) ([]datastore.CourseInfo, error) {
42 courses := []datastore.CourseInfo{}
43
44 count := uint32(0)
45 tries := 0
46
47 isUniq := func(dataId int) bool {
48 for _, c := range courses {
49 if c.DataId == uint64(dataId) {
50 return false
51 }
52 }
53 return true
54 }
55
56 // super ugly/lame. works around dump non indexed difficulty and ORDER BY random() slowness on such a large table.
57 for count < size {
58 dumpCourseInfo := dump.CourseInfo{}
59 err := s.DumpConn.QueryRowx("SELECT * FROM level WHERE rowid = abs(random()) % (SELECT max(rowid) FROM level) + 1").StructScan(&dumpCourseInfo)
60
61 if err != nil {
62 return courses, err
63 }
64
65 if !s.Config.MixedDifficulty {
66 if err != nil || uint8(dumpCourseInfo.Difficulty) != difficulty {
67 if tries >= 100 {
68 break
69 }
70 tries += 1
71 continue
72 }
73 }
74
75 if !isUniq(dumpCourseInfo.DataId) {
76 if tries >= 100 {
77 break
78 }
79 tries += 1
80 continue
81 }
82
83 count += 1
84 courseInfo := dump.DatastoreFromCourseInfo(dumpCourseInfo)
85 s.fillThumbnails(dumpCourseInfo, &courseInfo)
86 courses = append(courses, courseInfo)
87 }
88
89 return courses, nil
90}
91
92func (s *DumpView) GetEndlessCourses(state *user.State, size uint32, difficulty uint8) ([]datastore.CourseInfo, error) {
93 return s.GetDumpEndlessCourses(state, size, difficulty)
94}
95
96func (s *DumpView) GetCoursesLatest(state *user.State, offset, size uint32) ([]datastore.CourseInfo, error) {
97 fmt.Println("getCoursesLatest", offset, size)
98 courses := []datastore.CourseInfo{}
99
100 rows, err := s.DumpConn.Queryx("SELECT * FROM level ORDER BY rowid DESC LIMIT ?, ?", offset, size)
101 if err != nil {
102 return courses, err
103 }
104
105 for rows.Next() {
106 dumpCourseInfo := dump.CourseInfo{}
107 err := rows.StructScan(&dumpCourseInfo)
108 if err != nil {
109 return courses, err
110 }
111
112 courseInfo := dump.DatastoreFromCourseInfo(dumpCourseInfo)
113 s.fillThumbnails(dumpCourseInfo, &courseInfo)
114 courses = append(courses, courseInfo)
115 }
116
117 rows.Close()
118 return courses, nil
119}
120
121func (s *DumpView) GetCoursesTypeBy(state *user.State, tableName string, pids []uint64, offset, size uint32) ([]datastore.CourseInfo, error) {
122 fmt.Println("getCoursesTypeBy", tableName, pids, offset, size)
123
124 courses := []datastore.CourseInfo{}
125
126 for _, pid := range pids {
127 if pid == 0xcafe {
128 pid = 18278933308306892249 // get ryuSMM (current user)
129 }
130
131 pidStr := fmt.Sprintf("%v", pid)
132
133 orderDir := "DESC"
134
135 rows, err := s.DumpConnUser.Queryx(fmt.Sprintf("SELECT data_id FROM %v where pid = ? ORDER BY data_id %v LIMIT ?, ?", tableName, orderDir), pidStr, offset, size)
136 if err != nil {
137 fmt.Printf("Error getCoursesTypeBy %v %v\n", tableName, err)
138 continue
139 }
140
141 for rows.Next() {
142 var dataId int
143 err := rows.Scan(&dataId)
144 if err != nil {
145 return courses, err
146 }
147
148 dumpCourseInfo := dump.CourseInfo{}
149 err = s.DumpConn.QueryRowx("SELECT * FROM level WHERE data_id = ?", dataId).StructScan(&dumpCourseInfo)
150 if err != nil {
151 fmt.Printf("Error getCoursesTypeBy %v %v %v\n", tableName, dataId, err)
152 continue
153 }
154
155 courseInfo := dump.DatastoreFromCourseInfo(dumpCourseInfo)
156 s.fillThumbnails(dumpCourseInfo, &courseInfo)
157 courses = append(courses, courseInfo)
158 }
159 rows.Close()
160 }
161
162 return courses, nil
163}