src/Pure/Tools/server.scala
changeset 72163 f5722290a4d0
parent 71747 1dd514c8c1df
child 72763 3cc73d00553c
equal deleted inserted replaced
72162:5894859c5c84 72163:f5722290a4d0
    58   }
    58   }
    59 
    59 
    60 
    60 
    61   /* input command */
    61   /* input command */
    62 
    62 
    63   object Command
    63   type Command_Body = PartialFunction[(Context, Any), Any]
    64   {
    64 
    65     type T = PartialFunction[(Context, Any), Any]
    65   abstract class Command(val command_name: String)
    66 
    66   {
    67     private val table: Map[String, T] =
    67     def command_body: Command_Body
    68       Map(
    68     override def toString: String = command_name
    69         "help" -> { case (_, ()) => table.keySet.toList.sorted },
    69   }
    70         "echo" -> { case (_, t) => t },
    70 
    71         "shutdown" -> { case (context, ()) => context.server.shutdown() },
    71   class Commands(commands: Command*) extends Isabelle_System.Service
    72         "cancel" ->
    72   {
    73           { case (context, Server_Commands.Cancel(args)) => context.cancel_task(args.task) },
    73     def entries: List[Command] = commands.toList
    74         "session_build" ->
    74   }
    75           { case (context, Server_Commands.Session_Build(args)) =>
    75 
    76               context.make_task(task =>
    76   private lazy val command_table: Map[String, Command] =
    77                 Server_Commands.Session_Build.command(args, progress = task.progress)._1)
    77     (Map.empty[String, Command] /: Isabelle_System.make_services(classOf[Commands]).flatMap(_.entries))(
    78           },
    78       { case (cmds, cmd) =>
    79         "session_start" ->
    79           val name = cmd.command_name
    80           { case (context, Server_Commands.Session_Start(args)) =>
    80           if (cmds.isDefinedAt(name)) error("Duplicate Isabelle server command: " + quote(name))
    81               context.make_task(task =>
    81           else cmds + (name -> cmd)
    82                 {
    82       })
    83                   val (res, entry) =
       
    84                     Server_Commands.Session_Start.command(
       
    85                       args, progress = task.progress, log = context.server.log)
       
    86                   context.server.add_session(entry)
       
    87                   res
       
    88                 })
       
    89           },
       
    90         "session_stop" ->
       
    91           { case (context, Server_Commands.Session_Stop(id)) =>
       
    92               context.make_task(_ =>
       
    93                 {
       
    94                   val session = context.server.remove_session(id)
       
    95                   Server_Commands.Session_Stop.command(session)._1
       
    96                 })
       
    97           },
       
    98         "use_theories" ->
       
    99           { case (context, Server_Commands.Use_Theories(args)) =>
       
   100               context.make_task(task =>
       
   101                 {
       
   102                   val session = context.server.the_session(args.session_id)
       
   103                   Server_Commands.Use_Theories.command(
       
   104                     args, session, id = task.id, progress = task.progress)._1
       
   105                 })
       
   106           },
       
   107         "purge_theories" ->
       
   108           { case (context, Server_Commands.Purge_Theories(args)) =>
       
   109               val session = context.server.the_session(args.session_id)
       
   110               Server_Commands.Purge_Theories.command(args, session)._1
       
   111           })
       
   112 
       
   113     def unapply(name: String): Option[T] = table.get(name)
       
   114   }
       
   115 
    83 
   116 
    84 
   117   /* output reply */
    85   /* output reply */
   118 
    86 
   119   class Error(val message: String, val json: JSON.Object.T = JSON.Object.empty)
    87   class Error(val message: String, val json: JSON.Object.T = JSON.Object.empty)
   209 
   177 
   210   class Context private[Server](val server: Server, connection: Connection)
   178   class Context private[Server](val server: Server, connection: Connection)
   211     extends AutoCloseable
   179     extends AutoCloseable
   212   {
   180   {
   213     context =>
   181     context =>
       
   182 
       
   183     def command_list: List[String] = command_table.keys.toList.sorted
   214 
   184 
   215     def reply(r: Reply.Value, arg: Any) { connection.reply(r, arg) }
   185     def reply(r: Reply.Value, arg: Any) { connection.reply(r, arg) }
   216     def notify(arg: Any) { connection.notify(arg) }
   186     def notify(arg: Any) { connection.notify(arg) }
   217     def message(kind: String, msg: String, more: JSON.Object.Entry*): Unit =
   187     def message(kind: String, msg: String, more: JSON.Object.Entry*): Unit =
   218       notify(Reply.message(msg, kind = kind) ++ more)
   188       notify(Reply.message(msg, kind = kind) ++ more)
   560           connection.read_message() match {
   530           connection.read_message() match {
   561             case None => finished = true
   531             case None => finished = true
   562             case Some("") => context.notify("Command 'help' provides list of commands")
   532             case Some("") => context.notify("Command 'help' provides list of commands")
   563             case Some(msg) =>
   533             case Some(msg) =>
   564               val (name, argument) = Server.Argument.split(msg)
   534               val (name, argument) = Server.Argument.split(msg)
   565               name match {
   535               Server.command_table.get(name) match {
   566                 case Server.Command(cmd) =>
   536                 case Some(cmd) =>
   567                   argument match {
   537                   argument match {
   568                     case Server.Argument(arg) =>
   538                     case Server.Argument(arg) =>
   569                       if (cmd.isDefinedAt((context, arg))) {
   539                       if (cmd.command_body.isDefinedAt((context, arg))) {
   570                         Exn.capture { cmd((context, arg)) } match {
   540                         Exn.capture { cmd.command_body((context, arg)) } match {
   571                           case Exn.Res(task: Server.Task) =>
   541                           case Exn.Res(task: Server.Task) =>
   572                             connection.reply_ok(JSON.Object(task.ident))
   542                             connection.reply_ok(JSON.Object(task.ident))
   573                             task.start
   543                             task.start
   574                           case Exn.Res(res) => connection.reply_ok(res)
   544                           case Exn.Res(res) => connection.reply_ok(res)
   575                           case Exn.Exn(exn) =>
   545                           case Exn.Exn(exn) =>
   585                     case _ =>
   555                     case _ =>
   586                       connection.reply_error_message(
   556                       connection.reply_error_message(
   587                         "Malformed argument for command " + Library.single_quote(name),
   557                         "Malformed argument for command " + Library.single_quote(name),
   588                         "argument" -> argument)
   558                         "argument" -> argument)
   589                   }
   559                   }
   590                 case _ => connection.reply_error("Bad command " + Library.single_quote(name))
   560                 case None => connection.reply_error("Bad command " + Library.single_quote(name))
   591               }
   561               }
   592           }
   562           }
   593         }
   563         }
   594       }
   564       }
   595     })
   565     })