From 4c319e8ba084afeeb6957543109e3ca726fda6f4 Mon Sep 17 00:00:00 2001 From: qowevisa Date: Fri, 2 Aug 2024 00:03:01 +0300 Subject: [PATCH] Create tokens package --- tokens/dispatcher.go | 126 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 tokens/dispatcher.go diff --git a/tokens/dispatcher.go b/tokens/dispatcher.go new file mode 100644 index 0000000..dc4067a --- /dev/null +++ b/tokens/dispatcher.go @@ -0,0 +1,126 @@ +package tokens + +import ( + "crypto/rand" + "encoding/base64" + "errors" + "log" + "sync" + "time" +) + +type Token struct { + Val string + LastActive time.Time +} + +var ( + ActiveDur = time.Duration(time.Hour) +) + +func (t Token) IsExpired() bool { + return time.Now().Sub(t.LastActive) >= ActiveDur +} + +type TokensMapMu struct { + Initialized bool + Tokmap map[uint]Token + TokmapRev map[string]Token + Mu sync.RWMutex +} + +var toks TokensMapMu + +// NOTE: should be launch with a goroutine +// NOTE: it cannot die +func StartTokens() { + if toks.Initialized { + return + } + toks.Tokmap = make(map[uint]Token) + toks.TokmapRev = make(map[string]Token) + toks.Initialized = true + for { + // + toks.Mu.Lock() + for id, token := range toks.Tokmap { + if token.IsExpired() { + delete(toks.Tokmap, id) + } + } + toks.Mu.Unlock() + // + time.Sleep(time.Minute) + } +} + +var ( + ERROR_DONT_HAVE_TOKEN = errors.New("Don't have token for this user") + ERROR_ALREADY_HAVE_TOKEN = errors.New("Already have token") +) + +func GetToken(id uint) (Token, error) { + toks.Mu.RLock() + val, exists := toks.Tokmap[id] + toks.Mu.RUnlock() + if !exists { + return Token{}, ERROR_DONT_HAVE_TOKEN + } + return val, nil +} + +func haveToken(id uint) bool { + toks.Mu.RLock() + _, exists := toks.Tokmap[id] + toks.Mu.RUnlock() + return exists +} + +func UpdateLastActive(id uint) error { + if !haveToken(id) { + return ERROR_DONT_HAVE_TOKEN + } + toks.Mu.Lock() + val := toks.Tokmap[id] + val.LastActive = time.Now() + toks.Tokmap[id] = val + toks.Mu.Unlock() + return nil +} + +func haveTokenVal(val string) bool { + toks.Mu.RLock() + _, exists := toks.TokmapRev[val] + toks.Mu.RUnlock() + return exists +} + +func generateRandomString(length int) string { + bytes := make([]byte, length) + if _, err := rand.Read(bytes); err != nil { + log.Printf("generateRandomString: %v", err) + } + return base64.URLEncoding.EncodeToString(bytes) +} + +func generateTokenVal() string { + for { + tok := generateRandomString(32) + if !haveTokenVal(tok) { + return tok + } + } +} + +func AddToken(id uint) (Token, error) { + toks.Mu.RLock() + _, exists := toks.Tokmap[id] + toks.Mu.RUnlock() + if exists { + return Token{}, ERROR_ALREADY_HAVE_TOKEN + } + return Token{ + Val: generateTokenVal(), + LastActive: time.Now(), + }, nil +}