package session import ( "context" "time" "github.com/go-redis/redis/v8" "go.mongodb.org/mongo-driver/bson" "repositories.action2quare.com/ayo/gocommon" "repositories.action2quare.com/ayo/gocommon/logger" ) type sessionRedis struct { *Authorization expireAt time.Time } type consumer_redis struct { consumer_common[sessionRedis] redisClient *redis.Client } func NewConsumerWithRedis(ctx context.Context, redisUrl string, ttl time.Duration) (Consumer, error) { redisClient, err := gocommon.NewRedisClient(redisUrl) if err != nil { return nil, err } consumer := &consumer_redis{ consumer_common: consumer_common[sessionRedis]{ ttl: ttl, ctx: ctx, stages: [2]*cache_stage[sessionRedis]{make_cache_stage[sessionRedis](), make_cache_stage[sessionRedis]()}, startTime: time.Now(), }, redisClient: redisClient, } updateChannel := communication_channel_name_prefix + "_u" deleteChannel := communication_channel_name_prefix + "_d" sub := redisClient.Subscribe(ctx, updateChannel, deleteChannel) go func() { stageswitch := time.Now().Add(ttl) tickTimer := time.After(ttl) for { select { case <-ctx.Done(): return case <-tickTimer: consumer.changeStage() stageswitch = stageswitch.Add(ttl) tempttl := time.Until(stageswitch) tickTimer = time.After(tempttl) case msg := <-sub.Channel(): if msg == nil { return } if len(msg.Payload) == 0 { continue } switch msg.Channel { case updateChannel: key := msg.Payload raw, err := redisClient.Get(ctx, key).Result() if err != nil { logger.Println(err) } else if len(raw) > 0 { var si Authorization if bson.Unmarshal([]byte(raw), &si) == nil { consumer.add(key, sessionRedis{ Authorization: &si, expireAt: time.Now().Add(consumer.ttl), }) } } case deleteChannel: key := msg.Payload consumer.delete(key) } } } }() return consumer, nil } func (c *consumer_redis) Query(key string) *Authorization { c.lock.Lock() defer c.lock.Unlock() if _, deleted := c.stages[0].deleted[key]; deleted { return nil } if _, deleted := c.stages[1].deleted[key]; deleted { return nil } found, ok := c.stages[0].cache[key] if !ok { found, ok = c.stages[1].cache[key] } if ok { if found.expireAt.After(time.Now()) { return found.Authorization } } payload, err := c.redisClient.Get(c.ctx, key).Result() if err == redis.Nil { return nil } else if err != nil { logger.Println("consumer Query :", err) return nil } if len(payload) > 0 { var si Authorization if bson.Unmarshal([]byte(payload), &si) == nil { ttl, err := c.redisClient.TTL(c.ctx, key).Result() if err != nil { logger.Println("consumer Query :", err) return nil } c.add_internal(key, sessionRedis{ Authorization: &si, expireAt: time.Now().Add(ttl), }) return &si } } return nil } func (c *consumer_redis) Touch(key string) bool { c.lock.Lock() defer c.lock.Unlock() ok, err := c.redisClient.Expire(c.ctx, key, c.ttl).Result() if err == redis.Nil { return false } else if err != nil { logger.Println("consumer Touch :", err) return false } if ok { newexpire := time.Now().Add(c.ttl) found, ok := c.stages[0].cache[key] if ok { found.expireAt = newexpire } found, ok = c.stages[1].cache[key] if ok { found.expireAt = newexpire } } return ok }