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.*;
020import java.util.*;
021
022import org.apache.juneau.http.*;
023import org.apache.juneau.rest.server.*;
024
025/**
026 * Mixin interface that serves the terminal bytes and raw endpoints, plus this module's own JS and CSS.
027 *
028 * <p>
029 * The one abstract method is the application's resolver, which is where authorization lives: an unknown id and a
030 * forbidden id both answer {@code 404}.  Ids match {@code ^[A-Za-z0-9_-]{1,128}$}; anything else answers {@code 400}
031 * before the resolver runs.  The mixin adds no auth of its own; the host resource's guards apply.
032 *
033 * <p>
034 * Step events are not served here: pair the terminal with {@code TerminalViewMixin} over the same id.
035 *
036 * <h5 class='section'>Example:</h5>
037 * <p class='bjava'>
038 *    <ja>@Rest</ja>
039 *    <jk>public class</jk> RunsResource <jk>extends</jk> BasicRestServlet <jk>implements</jk> TerminalMixin, TerminalViewMixin {
040 *       <ja>@Override</ja>
041 *       <jk>public</jk> Optional&lt;TerminalSource&gt; terminalSource(String <jv>id</jv>, RestRequest <jv>req</jv>) {
042 *          <jk>return</jk> <jf>runs</jf>.find(<jv>id</jv>).map(Run::terminal);
043 *       }
044 *    }
045 * </p>
046 */
047public interface TerminalMixin {
048
049   /** The URL path prefix of the terminal endpoints (relative to the host mount). */
050   String TERMINAL_PREFIX = "/juneau-terminal";
051
052   /** The URL path template of the bytes endpoint. */
053   String BYTES_PATH = TERMINAL_PREFIX + "/{id}/bytes";
054
055   /** The URL path template of the raw download. */
056   String RAW_PATH = TERMINAL_PREFIX + "/{id}/raw";
057
058   /** The URL path of the terminal runtime. */
059   String JS_PATH = "/juneau-terminal.js";
060
061   /** The URL path of the terminal stylesheet. */
062   String CSS_PATH = "/juneau-terminal.css";
063
064   /** The {@code WebJarResolver} asset id of the xterm.js UMD bundle. */
065   String XTERM_JS_ASSET = "org.webjars.npm:xterm__xterm:xterm__xterm/{version}/lib/xterm.js";
066
067   /** The {@code WebJarResolver} asset id of the xterm.js stylesheet. */
068   String XTERM_CSS_ASSET = "org.webjars.npm:xterm__xterm:xterm__xterm/{version}/css/xterm.css";
069
070   /**
071    * Resolves the source for a terminal id, applying the application's own access rules.
072    *
073    * @param id The id from the URL path (already checked against the grammar).
074    * @param req The in-flight request.
075    * @return The source, or empty when the id is unknown or the caller may not read it.
076    */
077   Optional<TerminalSource> terminalSource(String id, RestRequest req);
078
079   /**
080    * [GET /juneau-terminal/{id}/bytes] &mdash; raw bytes from an offset.
081    *
082    * @param id The terminal id.
083    * @param req The request.
084    * @param res The response.
085    * @throws IOException If the response could not be written.
086    */
087   @RestGet(path=BYTES_PATH, summary="Terminal bytes", swagger=@OpSwagger(ignore=true))
088   default void terminalBytes(@Path("id") String id, RestRequest req, RestResponse res) throws IOException {
089      TerminalEndpoints.bytes(terminalSource(TerminalEndpoints.checkId(id), req), req, res);
090   }
091
092   /**
093    * [GET /juneau-terminal/{id}/raw] &mdash; the whole log as an attachment.
094    *
095    * @param id The terminal id.
096    * @param req The request.
097    * @param res The response.
098    * @throws IOException If the response could not be written.
099    */
100   @RestGet(path=RAW_PATH, summary="Terminal raw log", swagger=@OpSwagger(ignore=true))
101   default void terminalRaw(@Path("id") String id, RestRequest req, RestResponse res) throws IOException {
102      TerminalEndpoints.raw(terminalSource(TerminalEndpoints.checkId(id), req), id, res);
103   }
104
105   /**
106    * [GET /juneau-terminal.js] &mdash; the terminal runtime.
107    *
108    * @return The script.
109    */
110   @RestGet(path=JS_PATH, summary="Juneau terminal runtime", swagger=@OpSwagger(ignore=true))
111   default HttpResource terminalScript() {
112      return TerminalEndpoints.script();
113   }
114
115   /**
116    * [GET /juneau-terminal.css] &mdash; the terminal stylesheet.
117    *
118    * @return The stylesheet.
119    */
120   @RestGet(path=CSS_PATH, summary="Juneau terminal stylesheet", swagger=@OpSwagger(ignore=true))
121   default HttpResource terminalStylesheet() {
122      return TerminalEndpoints.stylesheet();
123   }
124
125   /**
126    * The absolute URL of a terminal asset; the toolkit pack resolver for the {@code terminal} pack.
127    *
128    * @param req The current request.
129    * @param path {@link #JS_PATH} or {@link #CSS_PATH}.
130    * @return The asset URL with its cache-buster.
131    */
132   static String terminalAssetUrl(RestRequest req, String path) {
133      return TerminalEndpoints.terminalAssetUrl(req, path);
134   }
135}