mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-02 20:06:03 +02:00
* refactor backend, implement encrypted store * refactor in-memory store * wip * wip * wip * add syncer test * fix redis expiry * fix linting issues * fix test by skipping non-config records * fix backoff import * fix init issues * fix query * wait for initial sync before starting directory sync * add type to SyncLatest * add more log messages, fix deadlock in in-memory store, always return server version from SyncLatest * update sync types and tests * add redis tests * skip macos in github actions * add comments to proto * split getBackend into separate methods * handle errors in initVersion * return different error for not found vs other errors in get * use exponential backoff for redis transaction retry * rename raw to result * use context instead of close channel * store type urls as constants in databroker * use timestampb instead of ptypes * fix group merging not waiting * change locked names * update GetAll to return latest record version * add method to grpcutil to get the type url for a protobuf type
105 lines
1.9 KiB
Go
105 lines
1.9 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/go-redis/redis/v8"
|
|
"github.com/golang/protobuf/proto"
|
|
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
|
)
|
|
|
|
type recordStream struct {
|
|
ctx context.Context
|
|
backend *Backend
|
|
|
|
changed chan struct{}
|
|
version uint64
|
|
record *databroker.Record
|
|
err error
|
|
|
|
closeOnce sync.Once
|
|
closed chan struct{}
|
|
}
|
|
|
|
func newRecordStream(ctx context.Context, backend *Backend, version uint64) *recordStream {
|
|
return &recordStream{
|
|
ctx: ctx,
|
|
backend: backend,
|
|
|
|
changed: backend.onChange.Bind(),
|
|
version: version,
|
|
|
|
closed: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (stream *recordStream) Close() error {
|
|
stream.closeOnce.Do(func() {
|
|
stream.backend.onChange.Unbind(stream.changed)
|
|
close(stream.closed)
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (stream *recordStream) Next(block bool) bool {
|
|
if stream.err != nil {
|
|
return false
|
|
}
|
|
|
|
ticker := time.NewTicker(watchPollInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
cmd := stream.backend.client.ZRangeByScore(stream.ctx, changesSetKey, &redis.ZRangeBy{
|
|
Min: fmt.Sprintf("(%d", stream.version),
|
|
Max: "+inf",
|
|
Offset: 0,
|
|
Count: 1,
|
|
})
|
|
results, err := cmd.Result()
|
|
if err != nil {
|
|
stream.err = err
|
|
return false
|
|
}
|
|
|
|
if len(results) > 0 {
|
|
result := results[0]
|
|
var record databroker.Record
|
|
err = proto.Unmarshal([]byte(result), &record)
|
|
if err != nil {
|
|
log.Warn().Err(err).Msg("redis: invalid record detected")
|
|
} else {
|
|
stream.record = &record
|
|
}
|
|
stream.version++
|
|
return true
|
|
}
|
|
|
|
if block {
|
|
select {
|
|
case <-stream.ctx.Done():
|
|
stream.err = stream.ctx.Err()
|
|
return false
|
|
case <-stream.closed:
|
|
return false
|
|
case <-ticker.C: // check again
|
|
case <-stream.changed: // check again
|
|
}
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
func (stream *recordStream) Record() *databroker.Record {
|
|
return stream.record
|
|
}
|
|
|
|
func (stream *recordStream) Err() error {
|
|
return stream.err
|
|
}
|