~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
87 lines · 1.6 KB Raw History
package runtime

import (
	"context"
	"sync"

	"sigs.k8s.io/controller-runtime/pkg/manager"

	"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/supervise"
)

const forwardBuffer = 64

func (m *Manager) Go(name string, fn func(context.Context) error) error {
	return m.mgr.GetLocalManager().Add(manager.RunnableFunc(func(ctx context.Context) error {
		return supervise.Run(ctx, name, fn)
	}))
}

func Forward[V any](m *Manager, name string, in <-chan V, fan func(V) []Request) (<-chan Request, error) {
	out := make(chan Request, forwardBuffer)
	err := m.Go(name, func(ctx context.Context) error {
		defer close(out)
		for {
			var v V
			var ok bool
			select {
			case <-ctx.Done():
				return nil
			case v, ok = <-in:
			}
			if !ok {
				return nil
			}
			for _, r := range fan(v) {
				select {
				case out <- r:
				case <-ctx.Done():
					return nil
				}
			}
		}
	})
	if err != nil {
		return nil, err
	}
	return out, nil
}

type Queue struct {
	mu      sync.Mutex
	pending []Request
	queued  map[Request]bool
	wake    chan struct{}
}

func NewQueue() *Queue {
	return &Queue{queued: map[Request]bool{}, wake: make(chan struct{}, 1)}
}

func (q *Queue) Add(rs ...Request) {
	q.mu.Lock()
	for _, r := range rs {
		if !q.queued[r] {
			q.queued[r] = true
			q.pending = append(q.pending, r)
		}
	}
	q.mu.Unlock()
	select {
	case q.wake <- struct{}{}:
	default:
	}
}

func (q *Queue) take(struct{}) []Request {
	q.mu.Lock()
	defer q.mu.Unlock()
	out := q.pending
	q.pending = nil
	clear(q.queued)
	return out
}

func (q *Queue) Run(m *Manager, name string) (<-chan Request, error) {
	return Forward(m, name, q.wake, q.take)
}