Skip to content
Snippets Groups Projects
Verified Commit dbfae062 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Added redis cache

parent b90463d9
No related branches found
No related tags found
No related merge requests found
hash: e3afe7d6be6078ab261a84bcc69e2f87d9805c7553025546d12074b9926fd288 hash: 096846ddf934eee04d5e78003271d70eae05b8167e2611f72d6c34c187689b27
updated: 2018-05-24T12:12:33.899483528+02:00 updated: 2018-05-24T18:48:12.125295149+02:00
imports: imports:
- name: github.com/go-redis/redis
version: 0f9028adf0837cf93c9705817493e5f6997cf026
- name: github.com/lib/pq - name: github.com/lib/pq
version: 90697d60dd844d5ef6ff15135d0203f65d2f53b8 version: 90697d60dd844d5ef6ff15135d0203f65d2f53b8
subpackages: subpackages:
- oid - oid
- name: gopkg.in/bsm/ratelimit.v1
version: db14e161995a5177acef654cb0dd785e8ee8bc22
- name: gopkg.in/redis.v4
version: c938162545c57136fa59879746bc65d0f1db3d1e
subpackages:
- internal
- internal/consistenthash
- internal/errors
- internal/hashtag
- internal/pool
- internal/proto
testImports: [] testImports: []
package: git.kuschku.de/justjanne/statsbot package: git.kuschku.de/justjanne/statsbot
import: import:
- package: github.com/lib/pq - package: github.com/lib/pq
- package: github.com/go-redis/redis
version: ^6.11.0
\ No newline at end of file
...@@ -2,8 +2,10 @@ package main ...@@ -2,8 +2,10 @@ package main
import ( import (
"database/sql" "database/sql"
"encoding/json"
"fmt" "fmt"
_ "github.com/lib/pq" _ "github.com/lib/pq"
"gopkg.in/redis.v4"
"html/template" "html/template"
"net/http" "net/http"
"os" "os"
...@@ -16,6 +18,7 @@ const DEBUG = true ...@@ -16,6 +18,7 @@ const DEBUG = true
type Config struct { type Config struct {
Database DatabaseConfig Database DatabaseConfig
Redis RedisConfig
} }
type DatabaseConfig struct { type DatabaseConfig struct {
...@@ -23,12 +26,20 @@ type DatabaseConfig struct { ...@@ -23,12 +26,20 @@ type DatabaseConfig struct {
Url string Url string
} }
type RedisConfig struct {
Address string
Password string
}
func NewConfigFromEnv() Config { func NewConfigFromEnv() Config {
config := Config{} config := Config{}
config.Database.Format = os.Getenv("KSTATS_DATABASE_TYPE") config.Database.Format = os.Getenv("KSTATS_DATABASE_TYPE")
config.Database.Url = os.Getenv("KSTATS_DATABASE_URL") config.Database.Url = os.Getenv("KSTATS_DATABASE_URL")
config.Redis.Address = os.Getenv("KSTATS_REDIS_ADDRESS")
config.Redis.Password = os.Getenv("KSTATS_REDIS_PASSWORD")
return config return config
} }
...@@ -107,6 +118,11 @@ func handleError(err error) { ...@@ -107,6 +118,11 @@ func handleError(err error) {
func main() { func main() {
config := NewConfigFromEnv() config := NewConfigFromEnv()
redisClient := redis.NewClient(&redis.Options{
Addr: config.Redis.Address,
Password: config.Redis.Password,
})
db, err := sql.Open(config.Database.Format, config.Database.Url) db, err := sql.Open(config.Database.Format, config.Database.Url)
if err != nil { if err != nil {
panic(err) panic(err)
...@@ -116,101 +132,114 @@ func main() { ...@@ -116,101 +132,114 @@ func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, channel := path.Split(r.URL.Path) _, channel := path.Split(r.URL.Path)
if strings.HasPrefix(channel, "#") { if strings.HasPrefix(channel, "#") {
channelData := ChannelData{} var channelData ChannelData
err = db.QueryRow("SELECT id, channel FROM channels WHERE channel ILIKE $1", channel).Scan(&channelData.Id, &channelData.Name) data, err := redisClient.Get(channel).Bytes()
if err == nil {
err = json.Unmarshal(data, channelData)
}
if err != nil {
channelData, err = buildChannelData(db, channel)
if err != nil { if err != nil {
handleError(err) handleError(err)
return return
} }
err = db.QueryRow("SELECT COUNT(*), SUM(words), AVG(words), AVG(characters) FROM messages WHERE channel = $1", channelData.Id).Scan(&channelData.Lines, &channelData.Words, &channelData.WordsPerLine, &channelData.CharactersPerLine) data, err = json.Marshal(channelData)
err = redisClient.Set(channel, data, time.Minute*5).Err()
if err != nil { if err != nil {
handleError(err) handleError(err)
return return
} }
}
channelData.Users, err = retrieveUsers(db, channelData.Id) err = formatTemplate(w, "statistics", channelData)
if err != nil { if err != nil {
handleError(err) handleError(err)
return return
} }
}
})
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
err = http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
func buildChannelData(db *sql.DB, channel string) (channelData ChannelData, err error) {
fmt.Printf("Recomputing channel data for %s\n", channel)
err = db.QueryRow("SELECT id, channel FROM channels WHERE channel ILIKE $1", channel).Scan(&channelData.Id, &channelData.Name)
if err != nil {
return
}
err = db.QueryRow("SELECT COUNT(*), SUM(words), AVG(words), AVG(characters) FROM messages WHERE channel = $1", channelData.Id).Scan(&channelData.Lines, &channelData.Words, &channelData.WordsPerLine, &channelData.CharactersPerLine)
if err != nil {
return
}
channelData.Users, err = retrieveUsers(db, channelData.Id)
if err != nil {
return
}
channelData.Questions, err = retrievePercentageStats(db, channelData.Id, "question") channelData.Questions, err = retrievePercentageStats(db, channelData.Id, "question")
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.Exclamations, err = retrievePercentageStats(db, channelData.Id, "exclamation") channelData.Exclamations, err = retrievePercentageStats(db, channelData.Id, "exclamation")
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.Caps, err = retrievePercentageStats(db, channelData.Id, "caps") channelData.Caps, err = retrievePercentageStats(db, channelData.Id, "caps")
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.EmojiHappy, err = retrievePercentageStats(db, channelData.Id, "emoji_happy") channelData.EmojiHappy, err = retrievePercentageStats(db, channelData.Id, "emoji_happy")
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.EmojiSad, err = retrievePercentageStats(db, channelData.Id, "emoji_sad") channelData.EmojiSad, err = retrievePercentageStats(db, channelData.Id, "emoji_sad")
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.LongestLines, err = retrieveLongestLines(db, channelData.Id) channelData.LongestLines, err = retrieveLongestLines(db, channelData.Id)
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.ShortestLines, err = retrieveShortestLines(db, channelData.Id) channelData.ShortestLines, err = retrieveShortestLines(db, channelData.Id)
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.TotalWords, err = retrieveTotalWords(db, channelData.Id) channelData.TotalWords, err = retrieveTotalWords(db, channelData.Id)
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.References, err = retrieveReferences(db, channelData.Id) channelData.References, err = retrieveReferences(db, channelData.Id)
if err != nil { if err != nil {
handleError(err)
return return
} }
channelData.AverageWords, err = retrieveAverageWords(db, channelData.Id) channelData.AverageWords, err = retrieveAverageWords(db, channelData.Id)
if err != nil { if err != nil {
handleError(err)
return return
} }
err = formatTemplate(w, "statistics", channelData)
if err != nil {
handleError(err)
return return
} }
}
})
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
err = http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
func retrievePercentageStats(db *sql.DB, channel int, stats string) ([]FloatEntry, error) { func retrievePercentageStats(db *sql.DB, channel int, stats string) ([]FloatEntry, error) {
result, err := db.Query("SELECT coalesce(users.nick, '[Unknown]'), t."+stats+" FROM (SELECT coalesce(groups.\"group\", messages.sender) AS hash, round((count(nullif(messages."+stats+", false)) * 100) :: numeric / count(*)) as "+stats+" FROM messages LEFT JOIN groups ON messages.sender = groups.nick AND groups.channel = $1 WHERE messages.channel = $1 GROUP BY hash ORDER BY "+stats+" DESC) t LEFT JOIN users ON t.hash = users.hash WHERE t."+stats+" > 0 LIMIT $2;", channel, 2) result, err := db.Query("SELECT coalesce(users.nick, '[Unknown]'), t."+stats+" FROM (SELECT coalesce(groups.\"group\", messages.sender) AS hash, round((count(nullif(messages."+stats+", false)) * 100) :: numeric / count(*)) as "+stats+" FROM messages LEFT JOIN groups ON messages.sender = groups.nick AND groups.channel = $1 WHERE messages.channel = $1 GROUP BY hash ORDER BY "+stats+" DESC) t LEFT JOIN users ON t.hash = users.hash WHERE t."+stats+" > 0 LIMIT $2;", channel, 2)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment