PlaywrightHtmlSource.java

package net.sasasin.sreader.service.extraction.browser;

import java.net.URI;
import java.util.Objects;
import net.sasasin.sreader.config.FeedReaderProperties;
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Service;

/**
 * Public facade for Playwright page rendering.
 *
 * <p>Exposes standard single-page render and short-lived standard AutoPagerize sessions. All public
 * render/start/stop operations are synchronized on this instance so Playwright operations and
 * resource teardown never interleave.
 */
@Service
public class PlaywrightHtmlSource implements SmartLifecycle {

  private final FeedReaderProperties.Playwright settings;
  private final PlaywrightResourceLifecycle lifecycle;
  private final StandardPlaywrightPageRenderer standardRenderer;

  PlaywrightHtmlSource(
      FeedReaderProperties properties,
      PlaywrightResourceLifecycle lifecycle,
      StandardPlaywrightPageRenderer standardRenderer) {
    this.settings = Objects.requireNonNull(properties, "properties must not be null").playwright();
    this.lifecycle = Objects.requireNonNull(lifecycle, "lifecycle must not be null");
    this.standardRenderer =
        Objects.requireNonNull(standardRenderer, "standardRenderer must not be null");
  }

  public synchronized String render(URI uri) {
    return renderPage(uri).html();
  }

  public synchronized RenderedPage renderPage(URI uri) {
    Objects.requireNonNull(uri, "uri must not be null");
    if (!settings.enabled()) {
      throw new IllegalStateException("Playwright full text extraction is disabled");
    }
    return standardRenderer.render(uri);
  }

  /**
   * Runs {@code work} against one short-lived standard BrowserContext/Page session while holding
   * this facade's monitor for the entire pagination chain. Does not load extensions or persistent
   * profiles.
   */
  public synchronized <T> T withStandardSession(PlaywrightSessionWork<T> work) {
    Objects.requireNonNull(work, "work must not be null");
    if (!settings.enabled()) {
      throw new IllegalStateException("Playwright full text extraction is disabled");
    }
    return standardRenderer.withSession(work);
  }

  @Override
  public synchronized void start() {
    lifecycle.start();
  }

  @Override
  public synchronized void stop() {
    lifecycle.stop();
  }

  @Override
  public boolean isRunning() {
    return lifecycle.isRunning();
  }

  @Override
  public boolean isAutoStartup() {
    return false;
  }
}