package main // Queue for pending authentication requests import ( "math/rand" "sync" "time" "github.com/oklog/ulid" ) type AuthenticationMap struct { requestMap map[string]*AuthRequest app *App requestMapMutex *sync.RWMutex } // Returns empty string when no request by that id is present func (q *AuthenticationMap) GetRequestByID(ID string) *AuthRequest { q.requestMapMutex.RLock() req, ok := q.requestMap[ID] q.requestMapMutex.RUnlock() if !ok { return nil } return req } func (q *AuthenticationMap) QueueRequest(r *AuthRequest) error { t := time.Unix(1000000, 0) entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0) ulidID := ulid.MustNew(ulid.Timestamp(t), entropy) ID := ulidID.String() err := r.SetId(ID) if err != nil { return err } r.Queued = time.Now() q.requestMapMutex.Lock() q.requestMap[ID] = r q.requestMapMutex.Unlock() (*q.app.Logger).Info("Queued request by id: ", ID) return nil } func (q *AuthenticationMap) Init() { q.requestMap = make(map[string]*AuthRequest) q.requestMapMutex = &sync.RWMutex{} q.startRequestMapCleaner() } func (q *AuthenticationMap) startRequestMapCleaner() { go func() { for _ = range time.Tick(10 * time.Minute) { q.requestMapMutex.Lock() for key, req := range q.requestMap { // If the request has been queued for more than 30 // minutes, it's time to delete it. if req.Queued.Add(30 * time.Minute).Before(time.Now()) { (*q.app.Logger).Info("Deleting inactive request with id: ", req.ID) req.Cancel() delete(q.requestMap, key) } } q.requestMapMutex.Unlock() } }() } func (q *AuthenticationMap) Delete(ID string) { q.requestMapMutex.Lock() delete(q.requestMap, ID) q.requestMapMutex.Unlock() }