mirror of https://github.com/gabehf/trivia-api.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.4 KiB
110 lines
2.4 KiB
package trivia
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// represents the structure of trivia questions stored
|
|
// in the trivia.json file
|
|
type Question struct {
|
|
Question string `json:"question"`
|
|
Category string `json:"category"`
|
|
Format string `json:"format"`
|
|
Choices []string `json:"choices"`
|
|
Answer string `json:"answer"`
|
|
}
|
|
|
|
type Questions struct {
|
|
Categories []string
|
|
M map[string][]Question
|
|
lock *sync.RWMutex
|
|
}
|
|
|
|
func (q *Questions) Init() {
|
|
q.lock = &sync.RWMutex{}
|
|
}
|
|
|
|
func (q *Questions) Load(r io.Reader) error {
|
|
q.lock.Lock()
|
|
defer q.lock.Unlock()
|
|
if q.M == nil {
|
|
q.M = make(map[string][]Question, 0)
|
|
}
|
|
err := json.NewDecoder(r).Decode(&q.M)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if q.Categories == nil {
|
|
q.Categories = make([]string, 0)
|
|
}
|
|
for key := range q.M {
|
|
q.Categories = append(q.Categories, key)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q *Questions) categoryExists(cat string) bool {
|
|
q.lock.RLock()
|
|
defer q.lock.RUnlock()
|
|
cat = strings.ToLower(cat)
|
|
if q.M[cat] == nil || len(q.M[cat]) < 1 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (q *Questions) getRandomCategory() string {
|
|
q.lock.RLock()
|
|
defer q.lock.RUnlock()
|
|
return q.Categories[rand.Int()%len(q.Categories)]
|
|
}
|
|
|
|
// Gets a random question from the category, if specified.
|
|
func (q *Questions) GetRandomQuestion(category string) (*Question, int) {
|
|
q.lock.RLock()
|
|
defer q.lock.RUnlock()
|
|
// NOTE: it is okay to call another function that locks the RWMutex here,
|
|
// as it will not cause a deadlock since CategoryExists only locks the Read
|
|
if category == "" {
|
|
category = q.getRandomCategory()
|
|
} else if !q.categoryExists(category) {
|
|
return nil, 0
|
|
}
|
|
category = strings.ToLower(category)
|
|
qIndex := rand.Int() % len(q.M[category])
|
|
return &q.M[category][qIndex], qIndex
|
|
}
|
|
|
|
func (q *Questions) GetQuestionById(id string) *Question {
|
|
// get values from question_id
|
|
questionSlice := strings.Split(id, "|")
|
|
if len(questionSlice) != 2 {
|
|
return nil
|
|
}
|
|
category, indexS := questionSlice[0], questionSlice[1]
|
|
category = strings.ToLower(category)
|
|
index, err := strconv.Atoi(indexS)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
q.lock.RLock()
|
|
defer q.lock.RUnlock()
|
|
// ensure category exists
|
|
if !q.categoryExists(category) {
|
|
return nil
|
|
}
|
|
// ensure question index is valid
|
|
if len(q.M[category]) <= index {
|
|
return nil
|
|
}
|
|
|
|
// retrieve question
|
|
return &q.M[category][index]
|
|
}
|