Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a950b98db | ||
|
|
033f0a9271 | ||
|
|
1f68fcb45f | ||
|
|
b81894b0cf | ||
|
|
cfaa27b981 | ||
|
|
ffcf9cc742 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ bindata_assetfs.go
|
||||
assets_vfsdata.go
|
||||
*.un~
|
||||
*.swp
|
||||
ghs-stats.json
|
||||
@@ -109,6 +109,7 @@
|
||||
<th class="hidden-xs">
|
||||
<span style="cursor: pointer" v-on:click='mtimeTypeFromNow = !mtimeTypeFromNow'>ModTime</span>
|
||||
</th>
|
||||
<th>Downloads</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -126,6 +127,7 @@
|
||||
</td>
|
||||
<td><span v-if="f.type == 'dir'">~</span> {{f.size | formatBytes}}</td>
|
||||
<td class="hidden-xs">{{formatTime(f.mtime)}}</td>
|
||||
<td class="hidden-xs">{{f.dldcnt}}</td>
|
||||
<td style="text-align: left">
|
||||
<template v-if="f.type == 'dir'">
|
||||
<a class="btn btn-default btn-xs" href="/-/zip/{{f.path}}">
|
||||
|
||||
107
db.go
Normal file
107
db.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func panicErr(e error) {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
Filename string
|
||||
Data *map[string]int
|
||||
LastSave time.Time
|
||||
}
|
||||
|
||||
var DBModel Model = Model{}
|
||||
|
||||
// var SaveInterval float64 = 60.0 // seconds
|
||||
const SaveInterval = 60.0
|
||||
|
||||
func (model *Model) DBRead(filename string) *map[string]int {
|
||||
data := make(map[string]int)
|
||||
model.Filename = filename
|
||||
model.Data = &data
|
||||
|
||||
// create if file not exist
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
f, cerr := os.Create(filename)
|
||||
panicErr(cerr)
|
||||
|
||||
s, jerr := json.Marshal(data)
|
||||
panicErr(jerr)
|
||||
f.Write(s)
|
||||
defer f.Close()
|
||||
return &data
|
||||
}
|
||||
|
||||
dat, err := ioutil.ReadFile(filename)
|
||||
panicErr(err)
|
||||
|
||||
err = json.Unmarshal(dat, &data)
|
||||
panicErr(err)
|
||||
|
||||
fmt.Println(data)
|
||||
return &data
|
||||
}
|
||||
|
||||
func (model *Model) DBWrite() error {
|
||||
fmt.Println("db writing")
|
||||
dat, err := json.Marshal(model.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmp := model.Filename + ".un~"
|
||||
err = ioutil.WriteFile(tmp, dat, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmp, model.Filename)
|
||||
}
|
||||
|
||||
func (model *Model) Incre(key string) {
|
||||
(*model.Data)[key]++
|
||||
fmt.Println(model.Data)
|
||||
go model.AutoSave()
|
||||
}
|
||||
|
||||
func (model *Model) AutoSave() bool {
|
||||
if time.Since(model.LastSave).Seconds() > SaveInterval {
|
||||
model.DBWrite()
|
||||
model.LastSave = time.Now()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type dldEntry struct {
|
||||
ip string
|
||||
path string
|
||||
}
|
||||
|
||||
// DldCounter is used to validate duplicated download requests
|
||||
type DldCounter struct {
|
||||
IPHistory map[dldEntry]time.Time
|
||||
}
|
||||
|
||||
var DCounter DldCounter = DldCounter{}
|
||||
var DldInterval float64 = 60.0 // seconds
|
||||
|
||||
func (counter *DldCounter) Validate(ip string, path string) bool {
|
||||
if counter.IPHistory == nil {
|
||||
counter.IPHistory = make(map[dldEntry]time.Time)
|
||||
}
|
||||
entry := dldEntry{ip, path}
|
||||
if time.Since(counter.IPHistory[entry]).Seconds() > DldInterval {
|
||||
counter.IPHistory[entry] = time.Now()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -50,12 +51,13 @@ type HTTPStaticServer struct {
|
||||
PlistProxy string
|
||||
GoogleTrackerID string
|
||||
AuthType string
|
||||
DBModel Model
|
||||
|
||||
indexes []IndexFileItem
|
||||
m *mux.Router
|
||||
}
|
||||
|
||||
func NewHTTPStaticServer(root string) *HTTPStaticServer {
|
||||
func NewHTTPStaticServer(root string, dbmodel Model) *HTTPStaticServer {
|
||||
if root == "" {
|
||||
root = "./"
|
||||
}
|
||||
@@ -66,9 +68,10 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
|
||||
log.Printf("root path: %s\n", root)
|
||||
m := mux.NewRouter()
|
||||
s := &HTTPStaticServer{
|
||||
Root: root,
|
||||
Theme: "black",
|
||||
m: m,
|
||||
Root: root,
|
||||
Theme: "black",
|
||||
m: m,
|
||||
DBModel: dbmodel,
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -124,6 +127,7 @@ func (s *HTTPStaticServer) hIndex(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if r.FormValue("download") == "true" {
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(filepath.Base(path)))
|
||||
DldIncre(s.DBModel, r.RemoteAddr, path)
|
||||
}
|
||||
http.ServeFile(w, r, relPath)
|
||||
}
|
||||
@@ -286,6 +290,7 @@ func (s *HTTPStaticServer) hInfo(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *HTTPStaticServer) hZip(w http.ResponseWriter, r *http.Request) {
|
||||
path := mux.Vars(r)["path"]
|
||||
DldIncre(s.DBModel, r.RemoteAddr, path)
|
||||
CompressToZip(w, filepath.Join(s.Root, path))
|
||||
}
|
||||
|
||||
@@ -407,6 +412,7 @@ type HTTPFileInfo struct {
|
||||
Type string `json:"type"`
|
||||
Size int64 `json:"size"`
|
||||
ModTime int64 `json:"mtime"`
|
||||
DldCnt int `json:"dldcnt"`
|
||||
}
|
||||
|
||||
type AccessTable struct {
|
||||
@@ -541,6 +547,7 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
|
||||
Name: info.Name(),
|
||||
Path: path,
|
||||
ModTime: info.ModTime().UnixNano() / 1e6,
|
||||
DldCnt: (*s.DBModel.Data)[path],
|
||||
}
|
||||
if search != "" {
|
||||
name, err := filepath.Rel(requestPath, path)
|
||||
@@ -760,3 +767,10 @@ func checkFilename(name string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DldIncre(model Model, rAddress string, path string) {
|
||||
ip, _, _ := net.SplitHostPort(rAddress)
|
||||
if DCounter.Validate(ip, path) {
|
||||
model.Incre(path)
|
||||
}
|
||||
}
|
||||
|
||||
3
main.go
3
main.go
@@ -144,7 +144,8 @@ func main() {
|
||||
}
|
||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
||||
|
||||
ss := NewHTTPStaticServer(gcfg.Root)
|
||||
DBModel.DBRead("ghs-stats.json")
|
||||
ss := NewHTTPStaticServer(gcfg.Root, DBModel) // FIXME(ssx): should put DBModel inside HTTPStaticServer
|
||||
ss.Theme = gcfg.Theme
|
||||
ss.Title = gcfg.Title
|
||||
ss.GoogleTrackerID = gcfg.GoogleTrackerID
|
||||
|
||||
Reference in New Issue
Block a user