Add projects

This commit is contained in:
Alois 2026-08-24 00:10:41 +02:00
commit 8b607dd700
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
1802 changed files with 503346 additions and 2 deletions

View file

@ -0,0 +1,243 @@
package pluginhost
import (
"context"
"errors"
"fmt"
"strconv"
"sync"
"sync/atomic"
"github.com/router-for-me/CLIProxyAPI/v7/sdk/pluginapi"
)
type streamBridge struct {
next atomic.Uint64
mu sync.Mutex
streams map[string]*streamBridgeStream
}
const streamBridgeBufferSize = 16
var errStreamBridgeClosed = errors.New("stream is not open")
type streamBridgeStream struct {
chunks chan pluginapi.ExecutorStreamChunk
emits chan streamBridgeEmit
closes chan streamBridgeClose
closed chan struct{}
finished chan struct{}
abort chan struct{}
closeOnce sync.Once
abortOnce sync.Once
}
type streamBridgeEmit struct {
ctx context.Context
chunk pluginapi.ExecutorStreamChunk
done chan error
}
type streamBridgeClose struct {
errorMessage string
accepted chan struct{}
}
type rpcStreamEmitRequest struct {
StreamID string `json:"stream_id"`
Payload []byte `json:"payload,omitempty"`
Error string `json:"error,omitempty"`
}
type rpcStreamCloseRequest struct {
StreamID string `json:"stream_id"`
Error string `json:"error,omitempty"`
}
func newStreamBridge() *streamBridge {
return &streamBridge{streams: make(map[string]*streamBridgeStream)}
}
func newStreamBridgeStream() *streamBridgeStream {
stream := &streamBridgeStream{
chunks: make(chan pluginapi.ExecutorStreamChunk),
emits: make(chan streamBridgeEmit),
closes: make(chan streamBridgeClose),
closed: make(chan struct{}),
finished: make(chan struct{}),
abort: make(chan struct{}),
}
go stream.run()
return stream
}
func (s *streamBridgeStream) run() {
defer func() {
s.markClosed()
close(s.chunks)
close(s.finished)
}()
queue := make([]pluginapi.ExecutorStreamChunk, 0, streamBridgeBufferSize)
for {
var emitC <-chan streamBridgeEmit
if len(queue) < streamBridgeBufferSize {
emitC = s.emits
}
var outputC chan pluginapi.ExecutorStreamChunk
var next pluginapi.ExecutorStreamChunk
if len(queue) > 0 {
outputC = s.chunks
next = queue[0]
}
select {
case <-s.abort:
return
case request := <-s.closes:
s.markClosed()
close(request.accepted)
if request.errorMessage != "" {
queue = append(queue, pluginapi.ExecutorStreamChunk{Err: fmt.Errorf("%s", request.errorMessage)})
}
for len(queue) > 0 {
select {
case <-s.abort:
return
case s.chunks <- queue[0]:
queue = queue[1:]
}
}
return
case request := <-emitC:
if err := request.ctx.Err(); err != nil {
request.done <- err
continue
}
queue = append(queue, request.chunk)
request.done <- nil
case outputC <- next:
queue = queue[1:]
}
}
}
func (s *streamBridgeStream) markClosed() {
if s == nil {
return
}
s.closeOnce.Do(func() { close(s.closed) })
}
func (s *streamBridgeStream) abortStream() {
if s == nil {
return
}
s.abortOnce.Do(func() {
s.markClosed()
close(s.abort)
})
}
func (s *streamBridgeStream) emit(ctx context.Context, chunk pluginapi.ExecutorStreamChunk) error {
if s == nil {
return errStreamBridgeClosed
}
if ctx == nil {
ctx = context.Background()
}
request := streamBridgeEmit{
ctx: ctx,
chunk: chunk,
done: make(chan error, 1),
}
select {
case <-ctx.Done():
return ctx.Err()
case <-s.closed:
return errStreamBridgeClosed
case s.emits <- request:
}
return <-request.done
}
func (s *streamBridgeStream) close(errorMessage string) {
if s == nil {
return
}
request := streamBridgeClose{
errorMessage: errorMessage,
accepted: make(chan struct{}),
}
select {
case <-s.finished:
return
case s.closes <- request:
}
select {
case <-request.accepted:
case <-s.finished:
}
}
func (b *streamBridge) open(ctx context.Context) (string, <-chan pluginapi.ExecutorStreamChunk, func()) {
if b == nil {
chunks := make(chan pluginapi.ExecutorStreamChunk)
close(chunks)
return "", chunks, func() {}
}
id := strconv.FormatUint(b.next.Add(1), 10)
stream := newStreamBridgeStream()
b.mu.Lock()
b.streams[id] = stream
b.mu.Unlock()
cleanup := func() {
b.mu.Lock()
if b.streams[id] == stream {
delete(b.streams, id)
}
b.mu.Unlock()
stream.abortStream()
}
if ctx != nil && ctx.Done() != nil {
// Abort streams canceled before ExecuteStream can install cleanupWhenStreamDone.
go func() {
<-ctx.Done()
cleanup()
}()
}
return id, stream.chunks, cleanup
}
func (b *streamBridge) emit(ctx context.Context, id string, chunk pluginapi.ExecutorStreamChunk) error {
if b == nil || id == "" {
return fmt.Errorf("stream id is required")
}
b.mu.Lock()
stream := b.streams[id]
b.mu.Unlock()
if stream == nil {
return fmt.Errorf("stream %s is not open", id)
}
if err := stream.emit(ctx, chunk); err != nil {
if errors.Is(err, errStreamBridgeClosed) {
return fmt.Errorf("stream %s is not open", id)
}
return err
}
return nil
}
func (b *streamBridge) close(id string, errorMessage string) {
if b == nil || id == "" {
return
}
b.mu.Lock()
stream := b.streams[id]
delete(b.streams, id)
b.mu.Unlock()
if stream == nil {
return
}
stream.close(errorMessage)
}