Skip to content

Commit 99e0c1f

Browse files
committed
Merge branch 'release-2.8'
Removed old "X-Requested" and "X-Result" headers Record stats for Skins and Downloads as "Skin" being served Output some useful information on start (listening address, Redis DB info) Remove the last references of "Minotar" and replace with "Imgd" Allow configuration of the redirect address Remove statisticsEnabled an unused config option Added a statistic for the number of cached skins (and differentiate more from the mem usage) Allow selecting a different Database when using Redis Removed old constants Change some references of size to width Fixed the estimation for the memory usage of the Memory cache Fixed gcfg repository and tests
2 parents 37cf7bd + 5ef4d34 commit 99e0c1f

10 files changed

+98
-58
lines changed

cache.go

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Cache interface {
99
has(username string) bool
1010
pull(username string) minecraft.Skin
1111
add(username string, skin minecraft.Skin)
12+
size() uint
1213
memory() uint64
1314
}
1415

cache_memory.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package main
22

33
import (
4-
"github.com/minotar/minecraft"
54
"time"
5+
6+
"github.com/minotar/minecraft"
67
)
78

89
const (
@@ -96,8 +97,13 @@ func (c *CacheMemory) add(username string, skin minecraft.Skin) {
9697
})
9798
}
9899

100+
// The exact number of usernames in the map
101+
func (c *CacheMemory) size() uint {
102+
return uint(len(c.Skins))
103+
}
104+
99105
// The byte size of the cache. Fairly rough... don't really want to venture
100106
// into the land of manual memory management, because there be dragons.
101107
func (c *CacheMemory) memory() uint64 {
102-
return uint64(len(c.Usernames) * SKIN_SIZE)
108+
return uint64(len(c.Skins) * SKIN_SIZE)
103109
}

cache_off.go

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ func (c *CacheOff) pull(username string) minecraft.Skin {
2525
func (c *CacheOff) add(username string, skin minecraft.Skin) {
2626
}
2727

28+
func (c *CacheOff) size() uint {
29+
return 0
30+
}
31+
2832
func (c *CacheOff) memory() uint64 {
2933
return 0
3034
}

cache_redis.go

+34-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package main
33
import (
44
"bytes"
55
"errors"
6-
"fmt"
7-
"github.com/fzzy/radix/extra/pool"
8-
"github.com/fzzy/radix/redis"
9-
"github.com/minotar/minecraft"
106
"image/png"
117
"strconv"
128
"strings"
9+
10+
"github.com/fzzy/radix/extra/pool"
11+
"github.com/fzzy/radix/redis"
12+
"github.com/minotar/minecraft"
1313
)
1414

1515
type CacheRedis struct {
@@ -22,12 +22,22 @@ func dialFunc(network, addr string) (*redis.Client, error) {
2222
if err != nil {
2323
return nil, err
2424
}
25+
2526
if config.Redis.Auth != "" {
26-
if err := client.Cmd("AUTH", config.Redis.Auth).Err; err != nil {
27+
r := client.Cmd("AUTH", config.Redis.Auth)
28+
if r.Err != nil {
2729
client.Close()
2830
return nil, err
2931
}
3032
}
33+
34+
// Select the DB within Redis
35+
r := client.Cmd("SELECT", config.Redis.DB)
36+
if r.Err != nil {
37+
client.Close()
38+
return nil, err
39+
}
40+
3141
return client, nil
3242
}
3343

@@ -45,7 +55,7 @@ func (c *CacheRedis) setup() error {
4555

4656
c.Pool = pool
4757

48-
log.Info("Loaded Redis cache (pool: " + fmt.Sprintf("%v", config.Redis.PoolSize) + ")")
58+
log.Info("Loaded Redis cache (address: %s, db: %v, prefix: \"%s\", pool: %v)", config.Redis.Address, config.Redis.DB, config.Redis.Prefix, config.Redis.PoolSize)
4959
return nil
5060
}
5161

@@ -128,6 +138,24 @@ func (c *CacheRedis) remove(username string) {
128138
err = client.Cmd("DEL", config.Redis.Prefix+username).Err
129139
}
130140

141+
func (c *CacheRedis) size() uint {
142+
var err error
143+
client := c.getFromPool()
144+
if client == nil {
145+
return 0
146+
}
147+
defer c.Pool.CarefullyPut(client, &err)
148+
149+
resp := client.Cmd("DBSIZE")
150+
size, err := resp.Int()
151+
if err != nil {
152+
log.Error(err.Error())
153+
return 0
154+
}
155+
156+
return uint(size)
157+
}
158+
131159
func (c *CacheRedis) memory() uint64 {
132160
var err error
133161
client := c.getFromPool()

config.example.gcfg

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ address = 0.0.0.0:8000
44
# Cache you want to use for skins. May be "redis", "memory", or "off".
55
# If it's Redis, you should fill out the [redis] section below.
66
cache = memory
7-
# Whether to store statistics about API usage. This requires a
8-
# redis connection if true (fill the config below).
9-
statisticsEnabled = false
7+
# Address to redirect users to upon browsing /
8+
url = https://minotar.net/
109
# The duration, in seconds we should store item in our cache. Default: 48 hrs
1110
ttl = 172800
1211

@@ -16,6 +15,8 @@ ttl = 172800
1615
address = 127.0.0.1:6379
1716
# "auth" is optional, it can be left blank if you don't need authentication.
1817
auth =
18+
# If you use your Redis for other data it may be useful to further separate it with databases.
19+
db = 0
1920
# We'll place this before skin caches in Redis to prevent conflicts.
2021
prefix = skins:
2122
# The number of Redis connections to use. 10 is a good number.

configuration.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4-
"code.google.com/p/gcfg"
54
"io"
65
"os"
6+
7+
"gopkg.in/gcfg.v1"
78
)
89

910
const (
@@ -16,15 +17,16 @@ const (
1617

1718
type Configuration struct {
1819
Server struct {
19-
Address string
20-
Cache string
21-
StatisticsEnabled bool
22-
Ttl int
20+
Address string
21+
Cache string
22+
URL string
23+
Ttl int
2324
}
2425

2526
Redis struct {
2627
Address string
2728
Auth string
29+
DB int
2830
Prefix string
2931
PoolSize int
3032
}

http.go

+18-21
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package main
22

33
import (
44
"fmt"
5-
"github.com/gorilla/mux"
6-
"github.com/minotar/minecraft"
75
"net/http"
86
"strconv"
97
"strings"
8+
9+
"github.com/gorilla/mux"
10+
"github.com/minotar/minecraft"
1011
)
1112

1213
type Router struct {
@@ -17,37 +18,33 @@ type NotFoundHandler struct{}
1718

1819
// Handles 404 errors
1920
func (h NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
20-
w.WriteHeader(404)
21+
w.WriteHeader(http.StatusNotFound)
2122
fmt.Fprintf(w, "404 not found")
2223
}
2324

24-
// Converts and sanitizes the string for the avatar size.
25-
func (r *Router) GetSize(inp string) uint {
25+
// GetWidth converts and sanitizes the string for the avatar width.
26+
func (r *Router) GetWidth(inp string) uint {
2627
out64, err := strconv.ParseUint(inp, 10, 0)
2728
out := uint(out64)
2829
if err != nil {
29-
return DefaultSize
30-
} else if out > MaxSize {
31-
return MaxSize
32-
} else if out < MinSize {
33-
return MinSize
30+
return DefaultWidth
31+
} else if out > MaxWidth {
32+
return MaxWidth
33+
} else if out < MinWidth {
34+
return MinWidth
3435
}
3536
return out
3637

3738
}
3839

3940
// Shows only the user's skin.
4041
func (router *Router) SkinPage(w http.ResponseWriter, r *http.Request) {
42+
stats.Served("Skin")
4143
vars := mux.Vars(r)
42-
4344
username := vars["username"]
44-
4545
skin := fetchSkin(username)
4646

4747
w.Header().Add("Content-Type", "image/png")
48-
w.Header().Add("X-Requested", "skin")
49-
w.Header().Add("X-Result", "ok")
50-
5148
skin.WriteSkin(w)
5249
}
5350

@@ -112,7 +109,7 @@ func (router *Router) writeType(ext string, skin *mcSkin, w http.ResponseWriter)
112109
func (router *Router) Serve(resource string) {
113110
fn := func(w http.ResponseWriter, r *http.Request) {
114111
vars := mux.Vars(r)
115-
size := router.GetSize(vars["size"])
112+
width := router.GetWidth(vars["width"])
116113
skin := fetchSkin(vars["username"])
117114
skin.Mode = router.getResizeMode(vars["extension"])
118115

@@ -121,17 +118,17 @@ func (router *Router) Serve(resource string) {
121118
return
122119
}
123120

124-
err := router.ResolveMethod(skin, resource)(int(size))
121+
err := router.ResolveMethod(skin, resource)(int(width))
125122
if err != nil {
126-
w.WriteHeader(500)
123+
w.WriteHeader(http.StatusInternalServerError)
127124
fmt.Fprintf(w, "500 internal server error")
128125
return
129126
}
130127
router.writeType(vars["extension"], skin, w)
131128
}
132129

133130
router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}{extension:(\\..*)?}", fn)
134-
router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}/{size:[0-9]+}{extension:(\\..*)?}", fn)
131+
router.Mux.HandleFunc("/"+strings.ToLower(resource)+"/{username:"+minecraft.ValidUsernameRegex+"}/{width:[0-9]+}{extension:(\\..*)?}", fn)
135132
}
136133

137134
// Binds routes to the ServerMux.
@@ -153,7 +150,7 @@ func (router *Router) Bind() {
153150
router.Mux.HandleFunc("/skin/{username:"+minecraft.ValidUsernameRegex+"}{extension:(.png)?}", router.SkinPage)
154151

155152
router.Mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
156-
fmt.Fprintf(w, "%s", MinotarVersion)
153+
fmt.Fprintf(w, "%s", ImgdVersion)
157154
})
158155

159156
router.Mux.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
@@ -162,7 +159,7 @@ func (router *Router) Bind() {
162159
})
163160

164161
router.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
165-
http.Redirect(w, r, "https://minotar.net/", 302)
162+
http.Redirect(w, r, config.Server.URL, http.StatusFound)
166163
})
167164
}
168165

main.go

+13-15
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,21 @@ package main
22

33
import (
44
"fmt"
5-
"github.com/gorilla/mux"
6-
"github.com/op/go-logging"
75
"net/http"
86
"os"
97
"runtime"
8+
9+
"github.com/gorilla/mux"
10+
"github.com/op/go-logging"
1011
)
1112

13+
// Set the default, min and max width to resize processed images to.
1214
const (
13-
DefaultSize = uint(180)
14-
MaxSize = uint(300)
15-
MinSize = uint(8)
15+
DefaultWidth = uint(180)
16+
MinWidth = uint(8)
17+
MaxWidth = uint(300)
1618

17-
SkinCache
18-
19-
Minutes uint = 60
20-
Hours = 60 * Minutes
21-
Days = 24 * Hours
22-
TimeoutActualSkin = 2 * Days
23-
TimeoutFailedFetch = 15 * Minutes
24-
25-
MinotarVersion = "2.7"
19+
ImgdVersion = "2.8"
2620
)
2721

2822
var (
@@ -61,8 +55,12 @@ func startServer() {
6155
r := Router{Mux: mux.NewRouter()}
6256
r.Bind()
6357
http.Handle("/", r.Mux)
58+
log.Info("imgd %s starting on %s", ImgdVersion, config.Server.Address)
6459
err := http.ListenAndServe(config.Server.Address, nil)
65-
log.Critical(err.Error())
60+
if err != nil {
61+
log.Critical("ListenAndServe: \"%s\"", err.Error())
62+
os.Exit(1)
63+
}
6664
}
6765

6866
func main() {

main_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func TestRenders(t *testing.T) {
7070
So(err, ShouldBeNil)
7171

7272
hash := hashRender(skin.Processed)
73-
So(hash, ShouldEqual, "a579af057377c35cbd4e53ed6bc5f03e")
73+
So(hash, ShouldEqual, "a253bb68f5ed938eb235ff1e3807940c")
7474
})
7575

7676
Convey("GetBust should return a valid image", t, func() {

status.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type statusCollectorMessage struct {
2525
type StatusCollector struct {
2626
info struct {
2727
// Number of bytes allocated to the process.
28-
Memory uint64
28+
ImgdMem uint64
2929
// Time in seconds the process has been running for
3030
Uptime int64
3131
// Number of times a request type has been served.
@@ -34,8 +34,10 @@ type StatusCollector struct {
3434
CacheHits uint
3535
// Number of times skins have failed to be served from the cache.
3636
CacheMisses uint
37-
// Size of cached skins
38-
Cached uint64
37+
// Number of skins in cache.
38+
CacheSize uint
39+
// Size of cache memory.
40+
CacheMem uint64
3941
}
4042

4143
// Unix timestamp the process was booted at.
@@ -96,9 +98,10 @@ func (s *StatusCollector) Collect() {
9698
memstats := &runtime.MemStats{}
9799
runtime.ReadMemStats(memstats)
98100

99-
s.info.Memory = memstats.Alloc
101+
s.info.ImgdMem = memstats.Alloc
100102
s.info.Uptime = time.Now().Unix() - s.StartedAt
101-
s.info.Cached = cache.memory()
103+
s.info.CacheSize = cache.size()
104+
s.info.CacheMem = cache.memory()
102105
}
103106

104107
// Increments the request counter for the specific type of request.

0 commit comments

Comments
 (0)