diff --git a/converter/converter.go b/converter/converter.go index 907a95c..f0ae2a1 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -17,11 +17,12 @@ import ( // html to pdf converter structure for type Converter struct { - chromePath string - ctx context.Context - cancel context.CancelFunc - allocCancel context.CancelFunc - progress func(progress int) + chromePath string + allocCtx context.Context + allocCancel context.CancelFunc // Cancels the whole Chrome process manager + browserCtx context.Context // The specific browser instance + browserCancel context.CancelFunc // Closes the browser + progress func(progress int) } // NewConverter starts a new converter instance with a chrome headless shell executable @@ -43,9 +44,17 @@ func NewConverter(chromePath string) (*Converter, error) { opts = append(opts, platformOptions()) - var allocCtx context.Context - allocCtx, c.cancel = chromedp.NewExecAllocator(context.Background(), opts...) - c.ctx, c.allocCancel = chromedp.NewContext(allocCtx) + c.allocCtx, c.allocCancel = chromedp.NewExecAllocator(context.Background(), opts...) + c.browserCtx, c.browserCancel = chromedp.NewContext(c.allocCtx) + + // 5. "Warm up" the browser to ensure the executable actually runs + // This catches "file not found" or permission errors immediately + err = chromedp.Run(c.browserCtx) + if err != nil { + c.Close() // Cleanup if start fails + return nil, fmt.Errorf("failed to start chrome: %w", err) + } + return c, nil } @@ -82,11 +91,11 @@ func (c *Converter) Convert(files ...models.File) error { htmlURL.WriteString(filepath.ToSlash(absPath)) - ctx, cancel := context.WithTimeout(c.ctx, 60*time.Second) - defer cancel() + taskCtx, taskCancel := chromedp.NewContext(c.browserCtx) + timeoutCtx, timeoutCancel := context.WithTimeout(taskCtx, 60*time.Second) var pdfData []byte - err = chromedp.Run(ctx, + err = chromedp.Run(timeoutCtx, chromedp.Navigate(htmlURL.String()), chromedp.WaitReady("body", chromedp.ByQuery), chromedp.ActionFunc(func(ctx context.Context) error { @@ -103,24 +112,27 @@ func (c *Converter) Convert(files ...models.File) error { }), ) + timeoutCancel() + taskCancel() if err != nil { - c.cancel() return err } // Save PDF to file if err := os.WriteFile(f.Output, pdfData, 0644); err != nil { - c.cancel() return err } } - c.cancel() return nil } func (c *Converter) Close() { - if c.cancel != nil { - c.cancel() + // Close browser first, then allocator + if c.browserCancel != nil { + c.browserCancel() + } + if c.allocCancel != nil { + c.allocCancel() } } diff --git a/html2pdf.go b/html2pdf.go index 24dc81e..bcdb10b 100644 --- a/html2pdf.go +++ b/html2pdf.go @@ -15,6 +15,8 @@ func Convert(chromePath, inputFile, outputFile string) error { if err != nil { return err } + defer c.Close() + return c.Convert(input) } diff --git a/html2pdf_test.go b/html2pdf_test.go index 145e68a..c3cb1d6 100644 --- a/html2pdf_test.go +++ b/html2pdf_test.go @@ -46,6 +46,7 @@ func TestConvertFiles(t *testing.T) { if err != nil { t.Fatal(err) } + defer c.Close() c.SetProgressCallback(func(progress int) { fmt.Println(progress)