src/Pure/System/web_app.scala
author nipkow
Tue, 17 Jun 2025 14:11:40 +0200
changeset 82733 8b537e1af2ec
parent 80648 572b096c889a
permissions -rw-r--r--
reinstated intersection of lists as inter_list_set
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     1
/*  Title:      Pure/System/web_app.scala
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     2
    Author:     Fabian Huch, TU Muenchen
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     3
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     4
Technical layer for web apps using server-side rendering with HTML forms.
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     5
 */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     6
package isabelle
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     7
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     8
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     9
import scala.annotation.tailrec
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    10
import scala.collection.immutable.SortedMap
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    11
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    12
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    13
object Web_App {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    14
  /* form html elements */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    15
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    16
  object More_HTML {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    17
    import HTML._
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    18
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    19
    def css(s: String): Attribute = new Attribute("style", s)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    20
    def name(n: String): Attribute = new Attribute("name", n)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    21
    def value(v: String): Attribute = new Attribute("value", v)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    22
    def placeholder(p: String): Attribute = new Attribute("placeholder", p)
80648
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    23
    def rowspan(n: Int): Attribute = new Attribute("rowspan", n.toString)
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    24
80257
96cb31f0bbdf more page elements;
Fabian Huch <huch@in.tum.de>
parents: 80256
diff changeset
    25
    val nav = new Operator("nav")
96cb31f0bbdf more page elements;
Fabian Huch <huch@in.tum.de>
parents: 80256
diff changeset
    26
    val header = new Operator("header")
96cb31f0bbdf more page elements;
Fabian Huch <huch@in.tum.de>
parents: 80256
diff changeset
    27
    val footer = new Operator("footer")
96cb31f0bbdf more page elements;
Fabian Huch <huch@in.tum.de>
parents: 80256
diff changeset
    28
    val main = new Operator("main")
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    29
    val fieldset = new Operator("fieldset")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    30
    val button = new Operator("button")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    31
80648
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    32
    val table = new Operator("table")
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    33
    val th = new Operator("th")
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    34
    val tr = new Operator("tr")
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    35
    val td = new Operator("td")
572b096c889a add tables to web_app;
Fabian Huch <huch@in.tum.de>
parents: 80494
diff changeset
    36
80315
a82db14570cd add favicon to web app;
Fabian Huch <huch@in.tum.de>
parents: 80257
diff changeset
    37
    def icon(href: String): XML.Elem =
a82db14570cd add favicon to web app;
Fabian Huch <huch@in.tum.de>
parents: 80257
diff changeset
    38
      XML.Elem(Markup("link", List("rel" -> "icon", "type" -> "image/x-icon", "href" -> href)), Nil)
a82db14570cd add favicon to web app;
Fabian Huch <huch@in.tum.de>
parents: 80257
diff changeset
    39
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    40
    def legend(txt: String): XML.Elem = XML.Elem(Markup("legend", Nil), text(txt))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    41
    def input(typ: String): XML.Elem = XML.Elem(Markup("input", List("type" -> typ)), Nil)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    42
    def hidden(k: Params.Key, v: String): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    43
      id(k.print)(name(k.print)(value(v)(input("hidden"))))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    44
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    45
    def textfield(i: Params.Key, p: String, v: String): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    46
      id(i.print)(name(i.print)(value(v)(placeholder(p)(input("text")))))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    47
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    48
    def browse(i: Params.Key, accept: List[String]): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    49
      id(i.print)(name(i.print)(input("file"))) + ("accept" -> accept.mkString(","))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    50
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    51
    def label(`for`: Params.Key, txt: String): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    52
      XML.Elem(Markup("label", List("for" -> `for`.print)), text(txt))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    53
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    54
    def option(k: String, v: String): XML.Elem = value(k)(XML.elem("option", text(v)))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    55
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    56
    def optgroup(txt: String, opts: XML.Body): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    57
      XML.Elem(Markup("optgroup", List("label" -> txt)), opts)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    58
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    59
    def select(i: Params.Key, opts: XML.Body): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    60
      id(i.print)(name(i.print)(XML.elem("select", opts)))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    61
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    62
    def textarea(i: Params.Key, v: String): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    63
      id(i.print)(name(i.print)(value(v)(XML.elem("textarea", text(v + "\n")))))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    64
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    65
    def radio(i: Params.Key, v: Params.Key, values: List[(Params.Key, String)]): XML.Elem = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    66
      def to_option(k: Params.Key): XML.Elem = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    67
        val elem = id(i.print + k)(name(i.print)(value(k.print)(input("radio"))))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    68
        if (v == k) elem + ("checked" -> "checked") else elem
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    69
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    70
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    71
      span(values.map { case (k, v) => span(List(label(i + k, v), to_option(k))) })
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    72
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    73
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    74
    def selection(i: Params.Key, selected: Option[String], opts: XML.Body): XML.Elem = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    75
      def sel(elem: XML.Tree): XML.Tree = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    76
        selected match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    77
          case Some(value) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    78
            val Value = new Properties.String("value")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    79
            elem match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    80
              case XML.Elem(Markup("optgroup", props), body) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    81
                XML.Elem(Markup("optgroup", props), body.map(sel))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    82
              case e@XML.Elem(Markup("option", Value(v)), _) if v == value =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    83
                e + ("selected" -> "selected")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    84
              case e => e
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    85
            }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    86
          case None => elem
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    87
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    88
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    89
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    90
      def is_empty_group(elem: XML.Tree): Boolean = elem match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    91
        case XML.Elem(Markup("optgroup", _), body) if body.isEmpty => true
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    92
        case _ => false
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    93
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    94
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    95
      val default = if (selected.isEmpty) List(option("", "") + ("hidden" -> "hidden")) else Nil
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    96
      select(i, default ::: opts.filterNot(is_empty_group).map(sel))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    97
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    98
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    99
    def api_button(call: String, label: String): XML.Elem =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   100
      button(text(label)) + ("formaction" -> call) + ("type" -> "submit")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   101
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   102
    def submit_form(endpoint: String, body: XML.Body): XML.Elem = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   103
      val default_button = css("display: none")(input("submit") + ("formaction" -> endpoint))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   104
      val attrs =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   105
        List("method" -> "post", "target" -> "iframe", "enctype" -> "multipart/form-data")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   106
      XML.Elem(Markup("form", attrs), default_button :: body)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   107
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   108
  }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   109
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   110
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   111
  /* form http handling */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   112
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   113
  object Multi_Part {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   114
    abstract class Data(name: String)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   115
    case class Param(name: String, value: String) extends Data(name)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   116
    case class File(name: String, file_name: String, content: Bytes) extends Data(name)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   117
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   118
    def parse(body: Bytes): List[Data] = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   119
      /* Seq for text with embedded bytes */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   120
      case class Seq(text: String, bytes: Bytes) {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   121
        def split_one(sep: String): Option[(Seq, Seq)] = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   122
          val text_i = text.indexOf(sep)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   123
          if (text_i >= 0 && sep.nonEmpty) {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   124
            val (before_text, at_text) = text.splitAt(text_i)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   125
            val after_text = at_text.substring(sep.length)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   126
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   127
            // text might be shorter than bytes because of misinterpreted characters
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   128
            var found = false
80353
52154fef991d clarified signature: discontinue somewhat misleading Bytes <: CharSequence;
wenzelm
parents: 80315
diff changeset
   129
            var bytes_i = 0L
52154fef991d clarified signature: discontinue somewhat misleading Bytes <: CharSequence;
wenzelm
parents: 80315
diff changeset
   130
            while (!found && bytes_i < bytes.size) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   131
              var sep_ok = true
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   132
              var sep_i = 0
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   133
              while (sep_ok && sep_i < sep.length) {
80494
d1240adc30ce clarified signature, following 43323d886ea3;
wenzelm
parents: 80396
diff changeset
   134
                if (bytes.char(bytes_i + sep_i) == sep(sep_i)) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   135
                  sep_i += 1
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   136
                } else {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   137
                  bytes_i += 1
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   138
                  sep_ok = false
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   139
                }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   140
              }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   141
              if (sep_ok) found = true
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   142
            }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   143
80353
52154fef991d clarified signature: discontinue somewhat misleading Bytes <: CharSequence;
wenzelm
parents: 80315
diff changeset
   144
            val before_bytes = bytes.slice(0, bytes_i)
52154fef991d clarified signature: discontinue somewhat misleading Bytes <: CharSequence;
wenzelm
parents: 80315
diff changeset
   145
            val after_bytes = bytes.slice(bytes_i + sep.length, bytes.size)
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   146
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   147
            Some(Seq(before_text, before_bytes), Seq(after_text, after_bytes))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   148
          } else None
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   149
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   150
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   151
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   152
      val s = Seq(body.text, body)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   153
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   154
      def perhaps_unprefix(pfx: String, s: Seq): Seq =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   155
        Library.try_unprefix(pfx, s.text) match {
80353
52154fef991d clarified signature: discontinue somewhat misleading Bytes <: CharSequence;
wenzelm
parents: 80315
diff changeset
   156
          case Some(text) => Seq(text, s.bytes.slice(pfx.length, s.bytes.size))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   157
          case None => s
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   158
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   159
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   160
      val Separator = """--(.*)""".r
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   161
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   162
      s.split_one(HTTP.NEWLINE) match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   163
        case Some(Seq(Separator(sep), _), rest) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   164
          val Param = """Content-Disposition: form-data; name="([^"]+)"""".r
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   165
          val File = """Content-Disposition: form-data; name="([^"]+)"; filename="([^"]+)"""".r
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   166
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   167
          def parts(body: Seq): Option[List[Data]] =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   168
            for {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   169
              (first_line, more) <- body.split_one(HTTP.NEWLINE)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   170
              more1 = perhaps_unprefix(HTTP.NEWLINE, more)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   171
              (value, rest) <- more1.split_one(HTTP.NEWLINE + "--" + sep)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   172
              rest1 = perhaps_unprefix(HTTP.NEWLINE, rest)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   173
            } yield first_line.text match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   174
              case Param(name) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   175
                Multi_Part.Param(name, Line.normalize(value.text)) :: parts(rest1).getOrElse(Nil)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   176
              case File(name, file_name) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   177
                value.split_one(HTTP.NEWLINE + HTTP.NEWLINE) match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   178
                  case Some(_, content) =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   179
                    Multi_Part.File(name, file_name, content.bytes) :: parts(rest1).getOrElse(Nil)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   180
                  case _ => parts(rest1).getOrElse(Nil)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   181
                }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   182
              case _ => Nil
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   183
            }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   184
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   185
          parts(rest).getOrElse(Nil)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   186
        case _ => Nil
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   187
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   188
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   189
  }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   190
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   191
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   192
  /* request parameters as structured data */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   193
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   194
  object Params {
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   195
    def key(s: String): Key = Key(List(Key.elem(s)))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   196
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   197
    object Key {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   198
      sealed trait Elem { def print: String }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   199
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   200
      class Nested_Elem private[Key](val rep: String) extends Elem {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   201
        override def equals(that: Any): Boolean =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   202
          that match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   203
            case other: Nested_Elem => rep == other.rep
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   204
            case _ => false
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   205
          }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   206
        override def hashCode(): Int = rep.hashCode
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   207
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   208
        def print: String = rep
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   209
        override def toString: String = print
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   210
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   211
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   212
      class List_Elem private[Key](val rep: Int) extends Elem {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   213
        override def equals(that: Any): Boolean =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   214
          that match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   215
            case other: List_Elem => rep == other.rep
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   216
            case _ => false
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   217
          }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   218
        override def hashCode(): Int = rep.hashCode
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   219
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   220
        def print: String = rep.toString
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   221
        override def toString: String = print
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   222
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   223
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   224
      def elem(s: String): Elem =
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   225
        if (s.contains('/')) error("Illegal separator in " + quote(s))
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   226
        else {
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   227
          for {
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   228
            c <- s
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   229
            if Symbol.is_ascii_blank(c)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   230
          } error("Illegal blank character " + c.toInt + " in " + quote(s))
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   231
          s match {
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   232
            case Value.Int(i) => new List_Elem(i)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   233
            case s => new Nested_Elem(s)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   234
          }
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   235
        }
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   236
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   237
      def elem(i: Int): List_Elem = if (i < 0) error("Illegal list element") else new List_Elem(i)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   238
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   239
      def is_blank(es: List[Elem]): Boolean = es.length <= 1 && es.forall(_.print.isBlank)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   240
      def apply(es: List[Elem]): Key = if (is_blank(es)) error("Empty key") else new Key(es)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   241
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   242
      def explode(s: String): Key = Key(space_explode('/', s).map(elem))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   243
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   244
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   245
      /* ordering */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   246
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   247
      object Ordering extends scala.math.Ordering[Key] {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   248
        def compare(key1: Key, key2: Key): Int = key1.print.compareTo(key2.print)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   249
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   250
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   251
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   252
    class Key(private val rep: List[Key.Elem]) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   253
      def +(elem: Key.Elem): Key = Key(rep :+ elem)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   254
      def +(i: Int): Key = this + Key.elem(i)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   255
      def +(s: String): Key = this + Key.elem(s)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   256
      def +(key: Key) = Key(rep ++ key.rep)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   257
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   258
      def num: Option[Int] =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   259
        rep match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   260
          case (e: Key.List_Elem) :: _ => Some(e.rep)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   261
          case _ => None
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   262
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   263
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   264
      def get(key: Key): Option[Key] =
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   265
        if (!rep.startsWith(key.rep)) None
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   266
        else {
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   267
          val rest = rep.drop(key.rep.length)
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   268
          if (Key.is_blank(rest)) None
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   269
          else Some(Key(rest))
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   270
        }
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   271
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   272
      def print = rep.map(_.print).mkString("/")
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   273
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   274
      override def toString: String = print
80104
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   275
      override def equals(that: Any): Boolean =
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   276
        that match {
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   277
          case other: Key => rep == other.rep
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   278
          case _ => false
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   279
        }
138b5172c7f8 clarified web app parameters: more flexible, using HTML5 id specification (nonempty unicode string with no spaces);
Fabian Huch <huch@in.tum.de>
parents: 80059
diff changeset
   280
      override def hashCode(): Int = rep.hashCode()
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   281
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   282
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   283
    def indexed[A, B](key: Key, xs: List[A], f: (Key, A) => B): List[B] =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   284
      for ((x, i) <- xs.zipWithIndex) yield f(key + i, x)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   285
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   286
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   287
    object Data {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   288
      def from_multipart(parts: List[Multi_Part.Data]): Data = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   289
        val files = parts.collect { case f: Multi_Part.File => f }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   290
        val params =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   291
          parts.collect { case Multi_Part.Param(name, value) => Key.explode(name) -> value }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   292
        val file_params = files.map(file => Key.explode(file.name) -> file.file_name)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   293
        val file_files = files.map(file => Key.explode(file.name) -> file.content)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   294
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   295
        new Data(
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   296
          SortedMap.from(params ++ file_params)(Key.Ordering),
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   297
          SortedMap.from(file_files)(Key.Ordering))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   298
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   299
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   300
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   301
    class Data private(params: SortedMap[Key, String], files: SortedMap[Key, Bytes]) {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   302
      override def toString: String = "Data(" + params.toString() + "," + files.toString() + ")"
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   303
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   304
      def get(key: Key): Option[String] = params.get(key)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   305
      def apply(key: Key): String = get(key).getOrElse("")
80347
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   306
      def list(key: Key): List[Key] = {
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   307
        val indexes =
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   308
          for {
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   309
            key1 <- params.keys.toList
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   310
            key2 <- key1.get(key)
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   311
            i <- key2.num
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   312
          } yield i
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   313
        indexes.distinct.sorted.map(key + _)
613ac8c77a84 sort web app parameters in list;
Fabian Huch <huch@in.tum.de>
parents: 80315
diff changeset
   314
      }
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   315
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   316
      def file(key: Key): Option[Bytes] = files.get(key)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   317
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   318
  }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   319
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   320
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   321
  /* API with backend base path, and application url (e.g. for frontend links). */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   322
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   323
  case class Paths(
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   324
    frontend: Url,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   325
    api_base: Path,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   326
    serve_frontend: Boolean = false,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   327
    landing: Path = Path.current
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   328
  ) {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   329
    def api_path(path: Path, external: Boolean = true): Path =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   330
      (if (serve_frontend) Path.explode("backend") else Path.current) +
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   331
        (if (external) api_base else Path.current) + path
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   332
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   333
    def route(path: Path, params: Properties.T = Nil): String = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   334
      def param(p: Properties.Entry): String = Url.encode(p._1) + "=" + Url.encode(p._2)
80206
3cf3ad092e3e clarify routes: absolute in api and relative for frontend;
Fabian Huch <huch@in.tum.de>
parents: 80205
diff changeset
   335
      if (params.isEmpty) path.implode else path.implode + "?" + params.map(param).mkString("&")
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   336
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   337
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   338
    def api_route(path: Path, params: Properties.T = Nil, external: Boolean = true): String =
80206
3cf3ad092e3e clarify routes: absolute in api and relative for frontend;
Fabian Huch <huch@in.tum.de>
parents: 80205
diff changeset
   339
      "/" + route(api_path(path, external = external), params)
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   340
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   341
    def frontend_url(path: Path, params: Properties.T = Nil): Url =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   342
      frontend.resolve(route(path, params))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   343
  }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   344
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   345
  abstract class Server[A](
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   346
    paths: Paths,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   347
    port: Int = 0,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   348
    verbose: Boolean = false,
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   349
    progress: Progress = new Progress(),
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   350
  ) {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   351
    def render(model: A): XML.Body
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   352
    val error_model: A
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   353
    val endpoints: List[API_Endpoint]
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   354
    val head: XML.Body
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   355
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   356
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   357
    /* public-facing endpoints */
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   358
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   359
    sealed abstract class Endpoint(path: Path, method: String = "GET")
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   360
      extends HTTP.Service(path.implode, method) {
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   361
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   362
      def reply(request: HTTP.Request): HTTP.Response
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   363
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   364
      def html(head: XML.Elem, body: XML.Elem): HTTP.Response =
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   365
        HTTP.Response.html(
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   366
          cat_lines(
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   367
            List(
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   368
              HTML.header,
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   369
              HTML.output(head, hidden = true, structural = true),
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   370
              HTML.output(body, hidden = true, structural = true),
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   371
              HTML.footer)))
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   372
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   373
      final def apply(request: HTTP.Request): Option[HTTP.Response] =
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   374
        Exn.capture(reply(request)) match {
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   375
          case Exn.Res(res) => Some(res)
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   376
          case Exn.Exn(exn) =>
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   377
            val id = UUID.random_string()
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   378
            progress.echo_error_message("Internal error <" + id + ">: " + exn)
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   379
            error("Internal server error. ID: " + id)
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   380
        }
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   381
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   382
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   383
    class UI(path: Path) extends Endpoint(path, "GET") {
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   384
      def reply(request: HTTP.Request): HTTP.Response = {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   385
        progress.echo_if(verbose, "GET ui")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   386
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   387
        val on_load = """
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   388
(function() {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   389
  window.addEventListener('message', (event) => {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   390
    if (Number.isInteger(event.data)) {
80249
58881e1e4a75 web app: proper document height;
Fabian Huch <huch@in.tum.de>
parents: 80244
diff changeset
   391
      this.style.height=event.data + 'px'
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   392
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   393
  })
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   394
}).call(this)"""
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   395
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   396
        val set_src = """
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   397
const base = '""" + paths.frontend.toString.replace("/", "\\/") + """'
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   398
document.getElementById('iframe').src = base + '""" + paths.api_route(path).replace("/", "\\/") + """' + window.location.search"""
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   399
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   400
        html(
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   401
          XML.elem("head", HTML.head_meta :: head),
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   402
          XML.Elem(Markup("body", List("style" -> "height: fit-content")), List(
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   403
            XML.Elem(
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   404
              Markup(
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   405
                "iframe",
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   406
                List(
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   407
                  "id" -> "iframe",
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   408
                  "name" -> "iframe",
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   409
                  "style" -> "border-style: none; width: 100%",
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   410
                  "onload" -> on_load)),
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   411
              HTML.text("content")),
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   412
            HTML.script(set_src))))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   413
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   414
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   415
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   416
    sealed abstract class API_Endpoint(path: Path, method: String = "GET")
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   417
      extends Endpoint(paths.api_path(path, external = false), method) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   418
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   419
      def html_content(content: XML.Body, auto_reload: Boolean = false): HTTP.Response = {
80256
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   420
        val auto_reload_script = HTML.script("""
80244
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   421
var state = null
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   422
function heartbeat() {
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   423
  fetch(window.location, { method: "HEAD" }).then((http_res) => {
80244
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   424
    if (http_res.status === 200) {
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   425
      const new_state = http_res.headers.get("Content-Digest")
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   426
      if (state === null) state = new_state
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   427
      else if (state !== new_state) window.location.reload()
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   428
    }
80244
Fabian Huch <huch@in.tum.de>
parents: 80243
diff changeset
   429
    setTimeout(heartbeat, 1000)
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   430
  })
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   431
}
80256
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   432
heartbeat()""")
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   433
80256
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   434
        val resize_script = HTML.script("""
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   435
function post_height() {
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   436
  const scroll_bar_height = window.innerHeight - document.documentElement.clientHeight
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   437
  parent.postMessage(document.documentElement.scrollHeight + scroll_bar_height, '*')
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   438
}
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   439
window.addEventListener("resize", (event) => { post_height() })
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   440
""")
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   441
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   442
        val head1 = (if (auto_reload) List(auto_reload_script) else Nil) ::: resize_script :: head
80249
58881e1e4a75 web app: proper document height;
Fabian Huch <huch@in.tum.de>
parents: 80244
diff changeset
   443
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   444
        html(
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   445
          XML.elem("head", HTML.head_meta :: head1),
80256
df8fa0393127 web app: add automatic resize;
Fabian Huch <huch@in.tum.de>
parents: 80249
diff changeset
   446
          XML.Elem(Markup("body", List("onLoad" -> "post_height()")), content))
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   447
      }
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   448
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   449
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   450
    private def query_params(request: HTTP.Request): Properties.T = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   451
      def decode(s: String): Option[Properties.Entry] =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   452
        s match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   453
          case Properties.Eq(k, v) => Some(Url.decode(k) -> Url.decode(v))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   454
          case _ => None
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   455
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   456
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   457
      Library.try_unprefix(request.query, request.uri_name).toList.flatMap(params =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   458
        space_explode('&', params).flatMap(decode))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   459
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   460
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   461
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   462
    /* endpoint types */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   463
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   464
    class Get(val path: Path, description: String, get: Properties.T => Option[A])
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   465
      extends API_Endpoint(path) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   466
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   467
      def reply(request: HTTP.Request): HTTP.Response = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   468
        progress.echo_if(verbose, "GET " + description)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   469
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   470
        val params = query_params(request)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   471
        progress.echo_if(verbose, "params: " + params.toString())
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   472
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   473
        val model =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   474
          get(params) match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   475
            case Some(model) => model
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   476
            case None =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   477
              progress.echo_if(verbose, "Parsing failed")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   478
              error_model
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   479
          }
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   480
80205
fc2d791d28bd add auto-reload for more interactive web apps;
Fabian Huch <huch@in.tum.de>
parents: 80204
diff changeset
   481
        html_content(render(model), auto_reload = true)
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   482
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   483
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   484
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   485
    class Get_File(path: Path, description: String, download: Properties.T => Option[Path])
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   486
      extends API_Endpoint(path) {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   487
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   488
      def reply(request: HTTP.Request): HTTP.Response = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   489
        progress.echo_if(verbose, "DOWNLOAD " + description)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   490
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   491
        val params = query_params(request)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   492
        progress.echo_if(verbose, "params: " + params.toString())
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   493
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   494
        download(params) match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   495
          case Some(path) => HTTP.Response.content(HTTP.Content.read(path))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   496
          case None =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   497
            progress.echo_if(verbose, "Fetching file path failed")
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   498
            html_content(render(error_model))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   499
        }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   500
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   501
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   502
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   503
    class Post(path: Path, description: String, post: Params.Data => Option[A])
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   504
      extends API_Endpoint(path, method = "POST") {
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   505
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   506
      def reply(request: HTTP.Request): HTTP.Response = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   507
        progress.echo_if(verbose, "POST " + description)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   508
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   509
        val parts = Multi_Part.parse(request.input)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   510
        val params = Params.Data.from_multipart(parts)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   511
        progress.echo_if(verbose, "params: " + params.toString)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   512
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   513
        val model =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   514
          post(params) match {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   515
            case Some(model) => model
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   516
            case None =>
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   517
              progress.echo_if(verbose, "Parsing failed")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   518
              error_model
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   519
          }
80204
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   520
81f2fbf3975d clarified web app endpoints;
Fabian Huch <huch@in.tum.de>
parents: 80104
diff changeset
   521
        html_content(render(model))
80059
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   522
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   523
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   524
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   525
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   526
    /* server */
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   527
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   528
    private def ui_endpoints =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   529
      if (paths.serve_frontend) endpoints.collect { case page: Get => new UI(page.path) } else Nil
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   530
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   531
    private lazy val server =
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   532
      HTTP.server(port = port, name = "", services = endpoints ::: ui_endpoints)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   533
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   534
    def run(): Unit = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   535
      start()
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   536
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   537
      @tailrec
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   538
      def loop(): Unit = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   539
        Thread.sleep(Long.MaxValue)
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   540
        loop()
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   541
      }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   542
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   543
      Isabelle_Thread.interrupt_handler(_ => server.stop()) { loop() }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   544
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   545
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   546
    def start(): Unit = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   547
      server.start()
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   548
      progress.echo("Server started on " + paths.frontend_url(paths.landing))
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   549
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   550
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   551
    def stop(): Unit = {
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   552
      server.stop()
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   553
      progress.echo("Server stopped")
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   554
    }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   555
  }
37ea0727291f moved web_app module from AFP (e.g., for building web services for the distributed build);
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   556
}