mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
a3265bc346
* feat: Introduce computation runner, log forwarder, ingress, and egress proxy services. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Update Go environment variable parsing and build system to use new architecture and repository. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Update package sources to `sammyoina/cocos-ai` at a specific commit, add log-forwarder pre-start hook, and rename proxy binaries. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * chore: Update build system references to a specific commit and enhance logging for service connections and message processing. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * build: Update package source repositories and versions, migrate client logging to slog, and adjust ingress/egress proxy build and install steps. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * debug stuck Signed-off-by: Sammy Oina <sammyoina@gmail.com> * debug Signed-off-by: Sammy Oina <sammyoina@gmail.com> * debug Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: add HTTP/2 support to egress proxy and update build system to use specific commit hashes Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: enhance egress proxy CONNECT handling, update package sources, and add gRPC test utility Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Update build system for various services to a specific commit from a new repository, change agent gRPC port to 7001, and add a gRPC test client. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Migrate agent-internal gRPC communication to Unix sockets, set ingress proxy to port 7002, and update build hashes. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * refactor: Remove standalone ingress-proxy systemd service and update component versions. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix: Prevent computation re-initialization in agent and update component versions across several packages. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: update package versions and enable h2c support in ingress proxy. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: refactor ingress proxy to support HTTP/2 over Unix sockets and update component versions. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: Update build system package sources to `ultravioletrs/cocos` and reduce agent logging verbosity. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * refactor: improve error handling in proxy commands and remove unused gRPC test Signed-off-by: Sammy Oina <sammyoina@gmail.com> * test: add mock service state return value in handleRunReqChunks test Signed-off-by: Sammy Oina <sammyoina@gmail.com> * feat: add comprehensive tests for service and proxy components Signed-off-by: Sammy Oina <sammyoina@gmail.com> * fix linter Signed-off-by: Sammy Oina <sammyoina@gmail.com> * improve coverage Signed-off-by: Sammy Oina <sammyoina@gmail.com> * test: add gRPC client and ingress adapter tests, and update egress proxy tests. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * improve coverage Signed-off-by: Sammy Oina <sammyoina@gmail.com> --------- Signed-off-by: Sammy Oina <sammyoina@gmail.com>
142 lines
3.0 KiB
Go
142 lines
3.0 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package grpc
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/ultravioletrs/cocos/agent/cvms"
|
|
"golang.org/x/sync/errgroup"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/peer"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
var (
|
|
_ cvms.ServiceServer = (*grpcServer)(nil)
|
|
ErrUnexpectedMsg = errors.New("unknown message type")
|
|
)
|
|
|
|
const (
|
|
bufferSize = 1024 * 1024 // 1 MB
|
|
runReqTimeout = 30 * time.Second
|
|
)
|
|
|
|
type SendFunc func(*cvms.ServerStreamMessage) error
|
|
|
|
type grpcServer struct {
|
|
cvms.UnimplementedServiceServer
|
|
incoming chan *cvms.ClientStreamMessage
|
|
svc Service
|
|
}
|
|
|
|
type Service interface {
|
|
Run(ctx context.Context, ipAddress string, sendMessage SendFunc, authInfo credentials.AuthInfo)
|
|
}
|
|
|
|
// NewServer returns new AuthServiceServer instance.
|
|
func NewServer(incoming chan *cvms.ClientStreamMessage, svc Service) cvms.ServiceServer {
|
|
return &grpcServer{
|
|
incoming: incoming,
|
|
svc: svc,
|
|
}
|
|
}
|
|
|
|
func (s *grpcServer) Process(stream cvms.Service_ProcessServer) error {
|
|
client, ok := peer.FromContext(stream.Context())
|
|
if !ok {
|
|
return errors.New("failed to get peer info")
|
|
}
|
|
|
|
slog.Info("client connected to cvms server", "address", client.Addr.String())
|
|
|
|
eg, ctx := errgroup.WithContext(stream.Context())
|
|
|
|
eg.Go(func() error {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
slog.Info("receive goroutine context done", "address", client.Addr.String())
|
|
return ctx.Err()
|
|
default:
|
|
req, err := stream.Recv()
|
|
if err != nil {
|
|
slog.Error("failed to receive from stream", "address", client.Addr.String(), "error", err)
|
|
return err
|
|
}
|
|
s.incoming <- req
|
|
}
|
|
}
|
|
})
|
|
|
|
eg.Go(func() error {
|
|
sendMessage := func(msg *cvms.ServerStreamMessage) error {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
switch m := msg.Message.(type) {
|
|
case *cvms.ServerStreamMessage_RunReq:
|
|
return s.sendRunReqInChunks(stream, m.RunReq)
|
|
default:
|
|
return stream.Send(msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
s.svc.Run(ctx, client.Addr.String(), sendMessage, client.AuthInfo)
|
|
slog.Info("send goroutine Run() returned", "address", client.Addr.String())
|
|
return nil
|
|
})
|
|
|
|
err := eg.Wait()
|
|
slog.Info("stream closed", "address", client.Addr.String(), "error", err)
|
|
return err
|
|
}
|
|
|
|
func (s *grpcServer) sendRunReqInChunks(stream cvms.Service_ProcessServer, runReq *cvms.ComputationRunReq) error {
|
|
data, err := proto.Marshal(runReq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dataBuffer := bytes.NewBuffer(data)
|
|
buf := make([]byte, bufferSize)
|
|
|
|
for {
|
|
n, err := dataBuffer.Read(buf)
|
|
isLast := false
|
|
|
|
if err == io.EOF {
|
|
isLast = true
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
chunk := &cvms.ServerStreamMessage{
|
|
Message: &cvms.ServerStreamMessage_RunReqChunks{
|
|
RunReqChunks: &cvms.RunReqChunks{
|
|
Id: runReq.Id,
|
|
Data: buf[:n],
|
|
IsLast: isLast,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := stream.Send(chunk); err != nil {
|
|
return err
|
|
}
|
|
|
|
if isLast {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|