StartOzServer.oz 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. %%% *************************************************************
  2. %%% Copyright (C) 2009-2013 Torsten Anders (www.torsten-anders.de)
  3. %%% This program is free software; you can redistribute it and/or
  4. %%% modify it under the terms of the GNU General Public License
  5. %%% as published by the Free Software Foundation; either version 2
  6. %%% of the License, or (at your option) any later version.
  7. %%% This program is distributed in the hope that it will be useful,
  8. %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. %%% GNU General Public License for more details.
  11. %%% *************************************************************
  12. %%
  13. %% This code implements the Oz-side of the Org-babel Oz interface. It
  14. %% creates a socket server (to which org-babel-oz.el then
  15. %% connects). Any input to this socket must be an Oz expression. The
  16. %% input is fed to the OPI oz compiler, and the results are send back
  17. %% via the socket.
  18. %%
  19. declare
  20. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  21. %%
  22. %% Accessing the OPI compiler
  23. %%
  24. MyCompiler = Emacs.condSend.compiler
  25. /* % testing
  26. %% Feed an expression (result browsed)
  27. {MyCompiler enqueue(setSwitch(expression true))}
  28. {Browse
  29. {MyCompiler enqueue(feedVirtualString("1 + 2" return(result: $)))}}
  30. {MyCompiler enqueue(setSwitch(expression false))}
  31. %% It is really the OPI: I can use declare!
  32. {MyCompiler enqueue(setSwitch(expression false))}
  33. {MyCompiler enqueue(feedVirtualString("declare X=3\n{Browse X*X}"))}
  34. %% Note: expressions starting with keyword declare need keyword in
  35. {MyCompiler enqueue(setSwitch(expression true))}
  36. {Browse
  37. {MyCompiler enqueue(feedVirtualString("declare X=3\nin X*X" return(result: $)))}}
  38. {MyCompiler enqueue(setSwitch(expression false))}
  39. %% Alternatively you use a session with multiple feeds: first declare (statement), and then feed an expression
  40. {MyCompiler enqueue(setSwitch(expression false))}
  41. {MyCompiler enqueue(feedVirtualString("declare X=7" return))}
  42. {MyCompiler enqueue(setSwitch(expression true))}
  43. {Browse
  44. {MyCompiler enqueue(feedVirtualString("X*X" return(result: $)))}}
  45. {MyCompiler enqueue(setSwitch(expression false))}
  46. %% !!?? does not work?
  47. %% return nil in case of any error (division by 0)
  48. {MyCompiler enqueue(setSwitch(expression true))}
  49. {Browse
  50. {MyCompiler enqueue(feedVirtualString(
  51. {Accum ["try\n"
  52. % "skip\n" % do something in any case..
  53. "1 div 0" % my code
  54. % "1" % my code
  55. "\ncatch E then {Error.printException E}\n"
  56. "error\n" % always return nil
  57. "end\n"]
  58. List.append}
  59. return(result: $)))}}
  60. {MyCompiler enqueue(setSwitch(expression false))}
  61. %% !! catching some exceptions does not work??
  62. %% exception is not catched
  63. try {Bla} catch E then {Error.printException E} {Browse nil} end
  64. %% exception is catched
  65. try {Browse 1 div 0} catch E then {Error.printException E} {Browse nil} end
  66. {Browse ok}
  67. */
  68. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  69. %%
  70. %% Socket interface
  71. %%
  72. %%
  73. %% Create socket
  74. %%
  75. MyPort = 6001
  76. /** %% Creates a TCP socket server. Expects a Host (e.g., 'localhost') and a PortNo and returns a server plus its corresponding client. This client is an instance of Open.socket, and is the interface for reading and writing into the socket.
  77. %% MakeServer blocks until the server listens. However, waiting until a connection has been accepted happens in its own thread (i.e. MakeServer does only block until the server listens).
  78. %% NB: A port can be used only once, so assign it carefully. In case this postnnumber was shortly used before, you may need to wait a bit before reusing it.
  79. %% */
  80. %% !! Alternatively, let it assign automatically and output the port number..
  81. %%
  82. %% NOTE: for supporting multiple connections see http://www.mozart-oz.org/documentation/op/node13.html#section.sockets.accept
  83. proc {MakeServer Host PortNo ?MyServer ?MyClient}
  84. proc {Accept MyClient}
  85. thread H in % P
  86. %% suspends until a connection has been accepted
  87. {MyServer accept(host:H
  88. acceptClass:Open.socket
  89. accepted:?MyClient)}
  90. % {Myserver accept(host:H port:P)} % suspends until a connection has been accepted
  91. %% !!?? port number of client is usually created randomly..
  92. {System.showInfo "% connection accepted from host "#H}
  93. end
  94. %% !!???
  95. %% If Accept is called recursively, then server accepts multiple connections. These share the same compiler instance (e.g. variable bindings are shared). For multiple independent compiler instances call the OzServer application multiple times.
  96. %% However, how shall the output for multiple connections be sorted?? Would using the different client sockets created with the Server accept method work?
  97. %% NB: The number of clients accepted concurrently must be limited to the number set by {MyServer listen}
  98. % {Accept}
  99. end
  100. in
  101. MyServer = {New Open.socket init}
  102. %% To avoid problems with portnumbers, the port could be assigned automatically and then output..
  103. %%{MyServer bind(port:PortNo)}
  104. {MyServer bind(host:Host takePort:PortNo)}
  105. {MyServer listen}
  106. {System.showInfo "% OzServer started at host "#Host#" and port "#PortNo}
  107. MyClient = {Accept}
  108. end
  109. %%
  110. MySocket = {MakeServer localhost MyPort _/*MyServer*/}
  111. %%
  112. %% Read socket input
  113. %%
  114. declare
  115. %% Copied from OzServer/source/Socket.oz
  116. local
  117. proc {Aux Socket Size Stream}
  118. In = {Socket read(list:$
  119. size:Size)}
  120. in
  121. {Wait In}
  122. %% !! Is this the right way to stop the processing??
  123. %%
  124. %% abort condition when client stream ended (i.e. nothing was sent)
  125. if In == nil
  126. then {System.showInfo "socket stream ended"}
  127. Stream = nil
  128. else Stream = In | {Aux Socket Size}
  129. end
  130. end
  131. in
  132. /** %% The socket Server returns a stream of the strings it receives. The Server always waits until someone writes something into the socket, then the input is immediately written to a stream and the Server waits again.
  133. %% */
  134. proc {ReadToStream Socket Size Xs}
  135. thread {Aux Socket Size Xs} end
  136. end
  137. end
  138. /* % test
  139. MyStream = {ReadToStream MySocket 1024}
  140. */
  141. /* % test
  142. %% writing
  143. {MySocket write(vs:"this is a test")}
  144. */
  145. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  146. %%
  147. %% Send socket input to compiler and send results back to socket
  148. %%
  149. %% NOTE: Input code must be expression
  150. thread
  151. {ForAll {ReadToStream MySocket 1024}
  152. proc {$ Code}
  153. Result
  154. %% Catch any exception (so the will not cause blocking) and return nil in that case
  155. FullCode = {Accum ["try\n"
  156. % "skip\n" % do something in any case..
  157. Code
  158. "\ncatch E then {Error.printException E}\n"
  159. "error\n" % in case of an error, return 'error'
  160. "end\n"]
  161. List.append}
  162. in
  163. %% ?? Should I make setting switches etc atomic?
  164. {MyCompiler enqueue(setSwitch(expression true))}
  165. {MyCompiler enqueue(feedVirtualString(FullCode return(result: ?Result)))}
  166. {MyCompiler enqueue(setSwitch(expression false))}
  167. %%
  168. {Wait Result}
  169. {MySocket write(vs: if {VirtualString.is Result}
  170. then Result
  171. else {Value.toVirtualString Result 1000 1000}
  172. end)}
  173. {Show 'Org-babel result: '#Result}
  174. end}
  175. end
  176. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  177. %%
  178. %% Aux defs
  179. %%
  180. /** %% Binds the accumulation of the binary function Fn on all neighbors in Xs to Y. E.g., Accum returns the sum in Xs if Fn is Number.'+'.
  181. %% */
  182. proc {Accum Xs Fn Y}
  183. {List.foldL Xs.2 Fn Xs.1 Y}
  184. end