mirror of
https://github.com/xaionaro-go/streamctl.git
synced 2025-10-15 12:00:41 +08:00
263 lines
5.2 KiB
Go
263 lines
5.2 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/facebookincubator/go-belt/tool/logger"
|
|
"github.com/xaionaro-go/streamctl/pkg/observability"
|
|
"github.com/xaionaro-go/streamctl/pkg/recoder"
|
|
"github.com/xaionaro-go/streamctl/pkg/recoder/libav/saferecoder/grpc/go/recoder_grpc"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
type Client struct {
|
|
Target string
|
|
}
|
|
|
|
func New(target string) *Client {
|
|
return &Client{Target: target}
|
|
}
|
|
|
|
func (c *Client) grpcClient() (recoder_grpc.RecoderClient, *grpc.ClientConn, error) {
|
|
conn, err := grpc.NewClient(
|
|
c.Target,
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("unable to initialize a gRPC client: %w", err)
|
|
}
|
|
|
|
client := recoder_grpc.NewRecoderClient(conn)
|
|
return client, conn, nil
|
|
}
|
|
|
|
func (c *Client) SetLoggingLevel(
|
|
ctx context.Context,
|
|
logLevel logger.Level,
|
|
) error {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
|
|
_, err = client.SetLoggingLevel(ctx, &recoder_grpc.SetLoggingLevelRequest{
|
|
Level: logLevelGo2Protobuf(logLevel),
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("query error: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type InputConfig = recoder.InputConfig
|
|
type InputID uint64
|
|
|
|
func (c *Client) NewInputFromURL(
|
|
ctx context.Context,
|
|
url string,
|
|
config InputConfig,
|
|
) (InputID, error) {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer conn.Close()
|
|
|
|
resp, err := client.NewInput(ctx, &recoder_grpc.NewInputRequest{
|
|
Path: &recoder_grpc.ResourcePath{
|
|
ResourcePath: &recoder_grpc.ResourcePath_Url{
|
|
Url: url,
|
|
},
|
|
},
|
|
Config: &recoder_grpc.InputConfig{},
|
|
})
|
|
if err != nil {
|
|
return 0, fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return InputID(resp.GetId()), nil
|
|
}
|
|
|
|
func (c *Client) CloseInput(
|
|
ctx context.Context,
|
|
inputID InputID,
|
|
) error {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
|
|
_, err = client.CloseInput(ctx, &recoder_grpc.CloseInputRequest{
|
|
InputID: uint64(inputID),
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type OutputID uint64
|
|
type OutputConfig = recoder.OutputConfig
|
|
|
|
func (c *Client) NewOutputFromURL(
|
|
ctx context.Context,
|
|
url string,
|
|
config OutputConfig,
|
|
) (OutputID, error) {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer conn.Close()
|
|
|
|
resp, err := client.NewOutput(ctx, &recoder_grpc.NewOutputRequest{
|
|
Path: &recoder_grpc.ResourcePath{
|
|
ResourcePath: &recoder_grpc.ResourcePath_Url{
|
|
Url: url,
|
|
},
|
|
},
|
|
Config: &recoder_grpc.OutputConfig{},
|
|
})
|
|
if err != nil {
|
|
return 0, fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return OutputID(resp.GetId()), nil
|
|
}
|
|
|
|
func (c *Client) CloseOutput(
|
|
ctx context.Context,
|
|
outputID OutputID,
|
|
) error {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
|
|
_, err = client.CloseOutput(ctx, &recoder_grpc.CloseOutputRequest{
|
|
OutputID: uint64(outputID),
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type RecoderID uint64
|
|
type RecoderConfig = recoder.Config
|
|
|
|
func (c *Client) NewRecoder(
|
|
ctx context.Context,
|
|
config RecoderConfig,
|
|
) (RecoderID, error) {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer conn.Close()
|
|
|
|
resp, err := client.NewRecoder(ctx, &recoder_grpc.NewRecoderRequest{
|
|
Config: &recoder_grpc.RecoderConfig{},
|
|
})
|
|
if err != nil {
|
|
return 0, fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return RecoderID(resp.GetId()), nil
|
|
}
|
|
|
|
func (c *Client) StartRecoding(
|
|
ctx context.Context,
|
|
recoderID RecoderID,
|
|
inputID InputID,
|
|
outputID OutputID,
|
|
) error {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
|
|
_, err = client.StartRecoding(ctx, &recoder_grpc.StartRecodingRequest{
|
|
RecoderID: uint64(recoderID),
|
|
InputID: uint64(inputID),
|
|
OutputID: uint64(outputID),
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type RecoderStats = recoder.Stats
|
|
|
|
func (c *Client) GetRecoderStats(
|
|
ctx context.Context,
|
|
recoderID RecoderID,
|
|
) (*RecoderStats, error) {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer conn.Close()
|
|
|
|
resp, err := client.GetRecoderStats(ctx, &recoder_grpc.GetRecoderStatsRequest{
|
|
RecoderID: uint64(recoderID),
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
return &RecoderStats{
|
|
BytesCountRead: resp.GetBytesCountRead(),
|
|
BytesCountWrote: resp.GetBytesCountWrote(),
|
|
}, nil
|
|
}
|
|
|
|
func (c *Client) RecodingEndedChan(
|
|
ctx context.Context,
|
|
recoderID RecoderID,
|
|
) (<-chan struct{}, error) {
|
|
client, conn, err := c.grpcClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
waiter, err := client.RecodingEndedChan(ctx, &recoder_grpc.RecodingEndedChanRequest{
|
|
RecoderID: uint64(recoderID),
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query error: %w", err)
|
|
}
|
|
|
|
result := make(chan struct{})
|
|
waiter.CloseSend()
|
|
observability.Go(ctx, func() {
|
|
defer conn.Close()
|
|
defer func() {
|
|
close(result)
|
|
}()
|
|
|
|
_, err := waiter.Recv()
|
|
if err == io.EOF {
|
|
logger.Debugf(ctx, "the receiver is closed: %v", err)
|
|
return
|
|
}
|
|
if err != nil {
|
|
logger.Errorf(ctx, "unable to read data: %v", err)
|
|
return
|
|
}
|
|
})
|
|
|
|
return result, nil
|
|
}
|