001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.terminal.region; 018 019import java.io.*; 020 021/** 022 * A growing stream of raw terminal bytes, read by absolute byte offset. 023 * 024 * <p> 025 * The bytes are exactly what the producer's terminal wrote, escape sequences included. The server never decodes 026 * them. 027 */ 028public interface TerminalSource { 029 030 /** The largest number of bytes one {@link #read(long, int)} returns. */ 031 int MAX_READ_BYTES = 256 * 1024; 032 033 /** 034 * Reads up to {@code maxBytes} bytes starting at {@code fromOffset}. 035 * 036 * <p> 037 * When {@code fromOffset} equals the end, the chunk is empty. When it is past the end, the chunk is empty, its 038 * {@code next} is its {@code end}, and that is below {@code fromOffset}, which the endpoint answers with {@code 416}. When it is no longer 039 * held, the chunk is {@code truncated} and starts at the oldest offset held. When the backing store has 040 * disappeared, the chunk is empty and {@code gone}, with {@code next} and {@code end} equal to {@code fromOffset}. 041 * 042 * @param fromOffset The offset to read from, at least 0. 043 * @param maxBytes The most bytes to return, clamped to 0-{@link #MAX_READ_BYTES}. 044 * @return The chunk. 045 * @throws IOException If the backing store could not be read. 046 */ 047 TerminalChunk read(long fromOffset, int maxBytes) throws IOException; 048 049 /** 050 * Copies every byte still held, oldest first, up to the end at the time of the call. 051 * 052 * <p> 053 * If the oldest bytes have been overwritten, the copy starts at the oldest offset held and the gap is skipped. 054 * 055 * @param out The stream to write to. 056 * @throws IOException If the source could not be read or the stream written. 057 */ 058 default void copyTo(OutputStream out) throws IOException { 059 var from = 0L; 060 var stop = -1L; 061 while (true) { 062 var c = read(from, MAX_READ_BYTES); 063 if (stop < 0) 064 stop = c.end(); 065 out.write(c.bytes()); 066 if (c.gone() || c.bytes().length == 0 || c.next() >= stop) 067 return; 068 from = c.next(); 069 } 070 } 071}