Skip to content

Commit

Permalink
uaid, part 1.
Browse files Browse the repository at this point in the history
  • Loading branch information
schwarzlichtbezirk committed Feb 28, 2023
1 parent 6bfb8c5 commit 565167e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 87 deletions.
4 changes: 3 additions & 1 deletion aec.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ const (
AECgpsscannodata

// stat/usrlst
AECusrlstusts
AECusrlstasts
AECusrlstfost
AECusrlstpost
)

// HTTP error messages
Expand Down
4 changes: 2 additions & 2 deletions folder.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,9 @@ func folderAPI(w http.ResponseWriter, r *http.Request, aid, uid ID_t) {

var latency = time.Since(t)
Log.Infof("id%d: navigate to %s, items %d, timeout %s", acc.ID, syspath, len(ret.List), latency)
if cid, err := GetCID(r); err == nil {
if uaid, err := GetUAID(r); err == nil {
go xormUserlog.InsertOne(&OpenStore{
CID: cid,
UAID: uaid,
AID: aid,
UID: uid,
Path: syspath,
Expand Down
12 changes: 6 additions & 6 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ func fileHandler(w http.ResponseWriter, r *http.Request, aid, uid ID_t) {

if HasRangeBegin(r) { // beginning of content
Log.Infof("id%d: media-hd %s", acc.ID, path.Base(syspath))
if cid, err := GetCID(r); err == nil {
if uaid, err := GetUAID(r); err == nil {
go xormUserlog.InsertOne(&OpenStore{
CID: cid,
UAID: uaid,
AID: aid,
UID: uid,
Path: syspath,
Expand Down Expand Up @@ -147,9 +147,9 @@ func fileHandler(w http.ResponseWriter, r *http.Request, aid, uid ID_t) {

if HasRangeBegin(r) { // beginning of content
Log.Infof("id%d: media %s", acc.ID, path.Base(syspath))
if cid, err := GetCID(r); err == nil {
if uaid, err := GetUAID(r); err == nil {
go xormUserlog.InsertOne(&OpenStore{
CID: cid,
UAID: uaid,
AID: aid,
UID: uid,
Path: syspath,
Expand All @@ -165,9 +165,9 @@ func fileHandler(w http.ResponseWriter, r *http.Request, aid, uid ID_t) {

if HasRangeBegin(r) { // beginning of content
Log.Infof("id%d: serve %s", acc.ID, path.Base(syspath))
if cid, err := GetCID(r); err == nil {
if uaid, err := GetUAID(r); err == nil {
go xormUserlog.InsertOne(&OpenStore{
CID: cid,
UAID: uaid,
AID: aid,
UID: uid,
Path: syspath,
Expand Down
8 changes: 4 additions & 4 deletions jwtauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ func ParseID(s string) (id ID_t, err error) {
return
}

// GetCID extract client ID from cookie.
func GetCID(r *http.Request) (cid ID_t, err error) {
// GetUAID extract user agent ID from cookie.
func GetUAID(r *http.Request) (uaid ID_t, err error) {
var c *http.Cookie
if c, err = r.Cookie("CID"); err != nil {
if c, err = r.Cookie("UAID"); err != nil {
return
}
if cid, err = ParseID(c.Value); err != nil {
if uaid, err = ParseID(c.Value); err != nil {
return
}
return
Expand Down
63 changes: 36 additions & 27 deletions routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ func LoadTemplates() (err error) {
// Transaction locker, locks until handler will be done.
var handwg sync.WaitGroup

const alias_cond = "(cid1=? AND cid2=?) OR (cid1=? AND cid2=?)"

// AjaxMiddleware is base handler middleware for AJAX API calls.
func AjaxMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -501,40 +503,47 @@ func AjaxMiddleware(next http.Handler) http.Handler {
handwg.Add(1)
defer handwg.Done()

// get CID
if cid, err := GetCID(r); err == nil {
var (
cid ID_t
uaold, uanew ID_t
isold, isnew bool
)

var ast = &AgentStore{
Addr: StripPort(r.RemoteAddr),
UA: r.UserAgent(),
}
uanew = ID_t(ast.Hash())

// UAID at cookie
if uaold, _ = GetUAID(r); uaold == 0 {
http.SetCookie(w, &http.Cookie{
Name: "UAID",
Value: strconv.FormatUint(uint64(uanew), 10),
Path: "/",
})
}

uamux.Lock()
if cid, isnew = UaMap[uanew]; !isnew {
if cid, isold = UaMap[uaold]; !isold {
maxcid++
cid = maxcid
}
UaMap[uanew] = cid
go func() {
var ast = AgentStore{
CID: cid,
Addr: StripPort(r.RemoteAddr),
UA: r.UserAgent(),
}
ast.CID = cid
ast.UAID = uanew
if lang, ok := r.Header["Accept-Language"]; ok {
ast.Lang = lang[0]
}

var hv = ast.Hash()
uamux.Lock()
var _, ok = UaMap[hv]
if !ok {
UaMap[hv] = void{}
}
UserOnline[cid] = time.Now()
uamux.Unlock()
if !ok {
xormUserlog.InsertOne(&ast)
if _, err := xormUserlog.InsertOne(ast); err != nil {
panic(err.Error())
}
}()
} else {
var cst ClientStore
if _, err := xormUserlog.InsertOne(&cst); err == nil {
http.SetCookie(w, &http.Cookie{
Name: "CID",
Value: strconv.FormatUint(uint64(cst.CID), 16),
Path: "/",
})
}
}
UserOnline[uanew] = time.Now()
uamux.Unlock()

// call the next handler, which can be another middleware in the chain, or the final handler
next.ServeHTTP(w, r)
Expand Down
101 changes: 56 additions & 45 deletions users.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package hms

import (
"encoding/binary"
"encoding/xml"
"net/http"
"path"
Expand All @@ -16,22 +15,18 @@ import (

var xormUserlog *xorm.Engine

type ClientStore struct {
CID ID_t `xorm:"pk autoincr"`
Time Time `xorm:"created"`
}

type AgentStore struct {
CID ID_t
UAID ID_t `xorm:"unique"` // user agent ID
CID ID_t // client ID
Addr string // remote address
UA string // user agent
Lang string // accept language
Time Time `xorm:"created"`
}

type OpenStore struct {
CID ID_t // client unique ID
AID ID_t `xorm:"default 0"` // access ID
UAID ID_t // client ID
AID ID_t `xorm:"default 0"` // access profile ID
UID ID_t `xorm:"default 0"` // user profile ID
Path string // system path
Latency int // event latency, in milliseconds, or -1 if it file
Expand All @@ -41,20 +36,22 @@ type OpenStore struct {
var (
// UserOnline is map of last AJAX query time for each user.
UserOnline = map[ID_t]time.Time{}
// UaMap is the set hashes of of user-agent records.
UaMap = map[uint64]void{}
// UaMap is the map of user agent hashes and associated client IDs.
UaMap = map[ID_t]ID_t{}
// current maximum client ID
maxcid ID_t
// mutex to get access to user-agent maps.
uamux sync.Mutex
)

const ua_salt = "hms"

func (ast *AgentStore) Hash() uint64 {
var h = xxhash.New()
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], uint64(ast.CID))
h.Write(buf[:])
h.Write(s2b(ua_salt))
h.Write(s2b(ast.Addr))
h.Write(s2b(ast.UA))
return h.Sum64()
return h.Sum64() & 0x7fff_ffff_ffff_ffff
}

// InitUserlog inits database user log engine.
Expand All @@ -65,7 +62,7 @@ func InitUserlog() (err error) {
xormUserlog.SetMapper(names.GonicMapper{})
xormUserlog.ShowSQL(false)

if err = xormUserlog.Sync(&ClientStore{}, &AgentStore{}, &OpenStore{}); err != nil {
if err = xormUserlog.Sync(&AgentStore{}, &OpenStore{}); err != nil {
return
}
return
Expand All @@ -76,6 +73,12 @@ func LoadUaMap() (err error) {
var session = xormUserlog.NewSession()
defer session.Close()

var u64 uint64
if _, err = session.Table(&AgentStore{}).Select("MAX(cid)").Get(&u64); err != nil {
return
}
maxcid = ID_t(u64)

const limit = 256
var offset int
for {
Expand All @@ -85,7 +88,7 @@ func LoadUaMap() (err error) {
}
offset += limit
for _, ast := range chunk {
UaMap[ast.Hash()] = void{}
UaMap[ast.UAID] = ast.CID
}
if limit > len(chunk) {
break
Expand All @@ -100,11 +103,11 @@ func usrlstAPI(w http.ResponseWriter, r *http.Request) {
Addr string `json:"addr" yaml:"addr" xml:"addr"`
UA uas.UserAgent `json:"ua" yaml:"ua" xml:"ua"`
Lang string `json:"lang" yaml:"lang" xml:"lang"`
Online bool `json:"online" yaml:"online" xml:"online,attr"`
AID ID_t `json:"accid" yaml:"accid" xml:"accid,attr"`
UID ID_t `json:"usrid" yaml:"usrid" xml:"usrid,attr"`
Path string `json:"path" yaml:"path" xml:"path"`
File string `json:"file" yaml:"file" xml:"file"`
Online bool `json:"online" yaml:"online" xml:"online"`
AID ID_t `json:"accid" yaml:"accid" xml:"accid"`
UID ID_t `json:"usrid" yaml:"usrid" xml:"usrid"`
}

var err error
Expand All @@ -129,39 +132,47 @@ func usrlstAPI(w http.ResponseWriter, r *http.Request) {
var session = xormUserlog.NewSession()
defer session.Close()

type jstore struct {
ClientStore `xorm:"extends"`
AgentStore `xorm:"extends"`
Path OpenStore `xorm:"extends"`
File OpenStore `xorm:"extends"`
}

ret.Total, _ = session.Count(&ClientStore{})
var justs []jstore
if err = session.Distinct().Table("client_store").
Join("INNER", "agent_store", "client_store.cid = agent_store.cid AND agent_store.time = (SELECT MIN(time) FROM agent_store WHERE cid = client_store.cid)").
Join("INNER", "open_store t1", "client_store.cid = t1.cid AND t1.time = (SELECT MAX(time) FROM open_store WHERE cid = client_store.cid AND latency>=0)").
Join("INNER", "open_store t2", "client_store.cid = t2.cid AND t2.time = (SELECT MAX(time) FROM open_store WHERE cid = client_store.cid AND latency=-1)").
Limit(arg.Num, arg.Pos).Find(&justs); err != nil {
WriteError500(w, r, err, AECusrlstusts)
var asts []AgentStore
if err = xormUserlog.Limit(arg.Num, arg.Pos).Find(&asts); err != nil {
WriteError500(w, r, err, AECusrlstasts)
return
}

ret.List = make([]item, len(asts))
var now = time.Now()
for _, rec := range justs {
for i, ast := range asts {
uamux.Lock()
var online = now.Sub(UserOnline[rec.AgentStore.CID]) < cfg.OnlineTimeout
var online = now.Sub(UserOnline[ast.UAID]) < cfg.OnlineTimeout
uamux.Unlock()
var ui = item{
Addr: rec.Addr,
Lang: rec.Lang,
Path: rec.Path.Path,
File: rec.File.Path,
Addr: ast.Addr,
Lang: ast.Lang,
Online: online,
AID: rec.Path.AID,
UID: rec.Path.UID,
}
uas.ParseUserAgent(rec.UA, &ui.UA)
ret.List = append(ret.List, ui)
uas.ParseUserAgent(ast.UA, &ui.UA)

var is bool
var fost, post OpenStore
if is, err = xormUserlog.Where("uaid=? AND latency<0", ast.UAID).Desc("time").Get(&fost); err != nil {
WriteError500(w, r, err, AECusrlstfost)
return
}
if is {
ui.File = fost.Path
ui.AID = fost.AID
ui.UID = fost.UID
}
if is, err = xormUserlog.Where("uaid=? AND latency>=0", ast.UAID).Desc("time").Get(&post); err != nil {
WriteError500(w, r, err, AECusrlstpost)
return
}
if is {
ui.File = post.Path
ui.AID = post.AID
ui.UID = post.UID
}

ret.List[i] = ui
}

WriteOK(w, r, &ret)
Expand Down
3 changes: 1 addition & 2 deletions workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,9 @@ func Init() {
Log.Fatal("can not init XORM user log: " + err.Error())
}
{
var usercount, _ = xormUserlog.Count(&ClientStore{})
Log.Infof("user count %d items", usercount)
var uacount, _ = xormUserlog.Count(&AgentStore{})
Log.Infof("user agent count %d items", uacount)
Log.Infof("clients count %d", maxcid)
var opencount, _ = xormUserlog.Count(&OpenStore{})
Log.Infof("resources open count %d items", opencount)
}
Expand Down

0 comments on commit 565167e

Please sign in to comment.