HttpArticlePageSession.java

package net.sasasin.sreader.service.http;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.util.Objects;
import net.sasasin.sreader.service.autopagerize.ArticlePageSession;
import net.sasasin.sreader.service.autopagerize.PageLoadException;
import net.sasasin.sreader.service.autopagerize.PageSnapshot;
import net.sasasin.sreader.service.outcome.FailureKind;

/**
 * Cookie-isolated HTTP session for one article pagination chain. Shares User-Agent, timeouts,
 * redirect policy, retry, and charset decoding with {@link HttpFetchService} via {@link
 * HttpTransport}.
 */
final class HttpArticlePageSession implements ArticlePageSession {

  private final HttpClient client;
  private final HttpTransport transport;
  private boolean closed;

  HttpArticlePageSession(HttpClient client, HttpTransport transport) {
    this.client = Objects.requireNonNull(client, "client must not be null");
    this.transport = Objects.requireNonNull(transport, "transport must not be null");
  }

  @Override
  public PageSnapshot load(URI uri) throws PageLoadException {
    Objects.requireNonNull(uri, "uri must not be null");
    if (closed) {
      throw new PageLoadException(FailureKind.INVALID_INPUT, "HTTP article page session is closed");
    }
    try {
      HttpTransport.FetchedBytes fetched = transport.get(client, uri);
      return new PageSnapshot(uri, fetched.finalUri(), fetched.body(), fetched.rawByteLength());
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new PageLoadException(
          FailureKind.INTERRUPTED, "Article page load interrupted for " + uri, e);
    } catch (HttpStatusException e) {
      throw new PageLoadException(
          FailureKind.HTTP_STATUS,
          "Article page load failed for " + uri + ": " + e.getMessage(),
          e);
    } catch (IOException e) {
      throw new PageLoadException(
          FailureKind.IO, "Article page load failed for " + uri + ": " + message(e), e);
    } catch (IllegalArgumentException e) {
      throw new PageLoadException(
          FailureKind.INVALID_INPUT,
          "Article page load invalid URI for " + uri + ": " + message(e),
          e);
    }
  }

  @Override
  public void close() {
    closed = true;
  }

  private static String message(Throwable e) {
    String message = e.getMessage();
    return message == null || message.isBlank() ? e.getClass().getSimpleName() : message;
  }
}