src/Pure/Tools/server.scala
changeset 66929 c19b17b72777
parent 66927 153d7b68e8f8
child 67178 70576478bda9
equal deleted inserted replaced
66928:33f9133bed7c 66929:c19b17b72777
    13 
    13 
    14 
    14 
    15 object Server
    15 object Server
    16 {
    16 {
    17   /* protocol */
    17   /* protocol */
       
    18 
       
    19   val commands: Map[String, PartialFunction[JSON.T, JSON.T]] =
       
    20     Map(
       
    21       "help" -> { case JSON.empty => commands.keySet.toList.sorted },
       
    22       "echo" -> { case t => t })
    18 
    23 
    19   object Reply extends Enumeration
    24   object Reply extends Enumeration
    20   {
    25   {
    21     val OK, ERROR = Value
    26     val OK, ERROR = Value
    22   }
    27   }
   150   private def handle_connection(socket: Socket)
   155   private def handle_connection(socket: Socket)
   151   {
   156   {
   152     val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, UTF8.charset))
   157     val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, UTF8.charset))
   153     val writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream, UTF8.charset))
   158     val writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream, UTF8.charset))
   154 
   159 
   155     val Blank_Line = """^\s*$""".r
       
   156     val Command_Line = """^(\S+)\s*(.*)$""".r
       
   157 
       
   158     def reply_line(msg: String)
   160     def reply_line(msg: String)
   159     {
   161     {
   160       require(split_lines(msg).length <= 1)
   162       require(split_lines(msg).length <= 1)
   161       writer.write(msg)
   163       writer.write(msg)
   162       writer.newLine()
   164       writer.newLine()
   168       reply_line(if (t == JSON.empty) r.toString else r.toString + " " + JSON.Format(t))
   170       reply_line(if (t == JSON.empty) r.toString else r.toString + " " + JSON.Format(t))
   169     }
   171     }
   170 
   172 
   171     def reply_ok(t: JSON.T) { reply(Server.Reply.OK, t) }
   173     def reply_ok(t: JSON.T) { reply(Server.Reply.OK, t) }
   172     def reply_error(t: JSON.T) { reply(Server.Reply.ERROR, t) }
   174     def reply_error(t: JSON.T) { reply(Server.Reply.ERROR, t) }
       
   175     def reply_error_message(message: String, more: (String, JSON.T)*): Unit =
       
   176       reply_error(Map("message" -> message) ++ more)
       
   177 
       
   178     val Command_Line = """^(\S+)\s*(.*)$""".r
   173 
   179 
   174     reader.readLine() match {
   180     reader.readLine() match {
   175       case null =>
   181       case null =>
   176       case bad if bad != password => reply_error("Bad password -- connection closed")
   182       case bad if bad != password => reply_error("Bad password -- connection closed")
   177       case _ =>
   183       case _ =>
   178         var finished = false
   184         var finished = false
   179         while (!finished) {
   185         while (!finished) {
   180           reader.readLine() match {
   186           reader.readLine() match {
   181             case null => finished = true
   187             case null => finished = true
   182             case Blank_Line() =>
   188             case Command_Line(cmd, input) =>
   183             case Command_Line(cmd, arg) =>
   189               Server.commands.get(cmd) match {
   184               proper_string(arg) getOrElse "{}" match {
   190                 case None => reply_error("Unknown command " + quote(cmd))
   185                 case JSON.Format(json) =>
   191                 case Some(body) =>
   186                   reply_ok(Map("command" -> cmd, "argument" -> json))
   192                   proper_string(input) getOrElse "{}" match {
   187                 case _ =>
   193                     case JSON.Format(arg) =>
   188                   reply_error(
   194                       if (body.isDefinedAt(arg)) {
   189                     Map("message" -> "Malformed command", "command" -> cmd, "input" -> arg))
   195                         try { reply_ok(body(arg)) }
       
   196                         catch { case ERROR(msg) => reply_error(msg) }
       
   197                       }
       
   198                       else {
       
   199                         reply_error_message(
       
   200                           "Bad argument for command", "command" -> cmd, "argument" -> arg)
       
   201                       }
       
   202                     case _ =>
       
   203                       reply_error_message(
       
   204                         "Malformed command-line", "command" -> cmd, "input" -> input)
       
   205                   }
   190               }
   206               }
   191             case _ =>
   207             case _ =>
   192           }
   208           }
   193         }
   209         }
   194     }
   210     }