6 Commits

Author SHA1 Message Date
codeskyblue
9a950b98db modify part 2018-11-28 09:58:54 +08:00
gzliuxin
033f0a9271 fix dldcounter bug 2018-11-26 18:24:44 +08:00
gzliuxin
1f68fcb45f add dldcounter to valid ip address 2018-11-26 15:05:59 +08:00
gzliuxin
b81894b0cf add autosave interval; add column for downlowads in index.html 2018-11-26 13:32:26 +08:00
gzliuxin
cfaa27b981 add db.go 2018-11-26 11:59:28 +08:00
gzliuxin
ffcf9cc742 add download count 2018-11-26 11:54:09 +08:00
5 changed files with 130 additions and 5 deletions

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ bindata_assetfs.go
assets_vfsdata.go
*.un~
*.swp
ghs-stats.json

View File

@@ -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
View 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
}

View File

@@ -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)
}
}

View File

@@ -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