// Package officeconvertclient provides typed Connect RPC helpers for conversions. package officeconvertclient import ( "context" "errors" "net/http" "time" "connectrpc.com/connect" officeconvertapiv1 "gitea.auvem.com/end/officeconvert/gen/go/officeconvertapi/v1" "gitea.auvem.com/end/officeconvert/gen/go/officeconvertapi/v1/officeconvertapiv1connect" "github.com/segmentio/ksuid" ) const defaultPollInterval = 2 * time.Second // HtmlFormattingPolicy configures which formatting features are ignored in HTML notes mode. type HtmlFormattingPolicy = officeconvertapiv1.HtmlFormattingPolicy // NotesOptions controls speaker-notes extraction/output. type NotesOptions = officeconvertapiv1.NotesOptions // SlideRasterOptions defines rendering settings for a raster output tier. type SlideRasterOptions = officeconvertapiv1.SlideRasterOptions // CreateConversionOptions control the behaviour of a CreateConversion session. type CreateConversionOptions = officeconvertapiv1.CreateConversionRequest // Client wraps the generated Connect client with orchestration-focused helpers. type Client struct { rpc officeconvertapiv1connect.ConversionServiceClient httpClient *http.Client baseURL string pollInterval time.Duration } // NewClient creates a new typed Officeconvert client. func NewClient(baseURL string, httpClient *http.Client, options ...connect.ClientOption) *Client { if httpClient == nil { httpClient = http.DefaultClient } return &Client{ rpc: officeconvertapiv1connect.NewConversionServiceClient(httpClient, baseURL, options...), httpClient: httpClient, baseURL: baseURL, pollInterval: defaultPollInterval, } } // SetPollInterval configures the polling cadence used by WaitForCompletion. func (c *Client) SetPollInterval(interval time.Duration) { if interval > 0 { c.pollInterval = interval } } // CreateConversion starts a conversion session and returns upload metadata. func (c *Client) CreateConversion( ctx context.Context, options *CreateConversionOptions, ) (*CreateConversionResponse, error) { req := connect.NewRequest(options) res, err := c.rpc.CreateConversion(ctx, req) if err != nil { return nil, err } return augmentCreateConversionResponse(res.Msg) } // StartConversion signals that upload is complete and conversion can begin. func (c *Client) StartConversion( ctx context.Context, id ksuid.KSUID, ) (*StartConversionResponse, error) { req := connect.NewRequest(&officeconvertapiv1.StartConversionRequest{ ConversionId: id.String(), }) res, err := c.rpc.StartConversion(ctx, req) if err != nil { return nil, err } return augmentStartConversionResponse(res.Msg) } // GetConversionStatus returns the latest status for a conversion session. func (c *Client) GetConversionStatus( ctx context.Context, id ksuid.KSUID, ) (*GetConversionStatusResponse, error) { req := connect.NewRequest(&officeconvertapiv1.GetConversionStatusRequest{ ConversionId: id.String(), }) res, err := c.rpc.GetConversionStatus(ctx, req) if err != nil { return nil, err } return augmentGetConversionStatusResponse(res.Msg) } // GetSlideDeck retrieves the final converted deck response. func (c *Client) GetSlideDeck( ctx context.Context, id ksuid.KSUID, ) (*officeconvertapiv1.GetSlideDeckResponse, error) { req := connect.NewRequest(&officeconvertapiv1.GetSlideDeckRequest{ ConversionId: id.String(), }) res, err := c.rpc.GetSlideDeck(ctx, req) if err != nil { return nil, err } return res.Msg, nil } // DeleteConversion triggers immediate resource cleanup for a session. func (c *Client) DeleteConversion( ctx context.Context, id ksuid.KSUID, ) (*DeleteConversionResponse, error) { req := connect.NewRequest(&officeconvertapiv1.DeleteConversionRequest{ ConversionId: id.String(), }) res, err := c.rpc.DeleteConversion(ctx, req) if err != nil { return nil, err } return augmentDeleteConversionResponse(res.Msg) } // WaitForCompletion polls status until terminal completion or context cancellation. func (c *Client) WaitForCompletion( ctx context.Context, id ksuid.KSUID, ) (*GetConversionStatusResponse, error) { ticker := time.NewTicker(c.pollInterval) defer ticker.Stop() for { status, err := c.GetConversionStatus(ctx, id) if err != nil { return nil, err } switch status.Status { case officeconvertapiv1.ConversionStatus_CONVERSION_STATUS_SUCCEEDED: return status, nil case officeconvertapiv1.ConversionStatus_CONVERSION_STATUS_FAILED: return nil, errors.New(status.ErrorMessage) } select { case <-ctx.Done(): return nil, ctx.Err() case <-ticker.C: } } }