diff --git a/ipython-profile/ipython_config.py b/ipython-profile/ipython_config.py index c399197..ec0bb70 100644 --- a/ipython-profile/ipython_config.py +++ b/ipython-profile/ipython_config.py @@ -1,3 +1,2 @@ c = get_config() -c.KernelManager.kernel_spec = [ "mono", r"%kexe", "{connection_file}"] c.NotebookApp.extra_static_paths = [ r"%kstatic" ] \ No newline at end of file diff --git a/paket.dependencies b/paket.dependencies index d7879a8..71b392d 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -2,7 +2,7 @@ source https://www.nuget.org/api/v2 nuget FSharp.Compiler.Service 3.0.0 framework: >= net451 nuget FSharp.Core.Microsoft.Signed 3.1.1.1 framework: >= net45 -nuget NetMQ 3.3.0.11 +nuget NetMQ 3.3.3.1 nuget Newtonsoft.Json 5.0.8 framework: >= net45 nuget FSharp.Charting 0.90.5 framework: >= net45 nuget FAKE diff --git a/paket.lock b/paket.lock index d85573d..e67c2fd 100644 --- a/paket.lock +++ b/paket.lock @@ -1,11 +1,13 @@ NUGET remote: https://www.nuget.org/api/v2 specs: + AsyncIO (0.1.18) FAKE (4.23.6) FSharp.Charting (0.90.5) - framework: >= net45 FSharp.Compiler.Service (3.0) - framework: >= net451 FSharp.Core.Microsoft.Signed (3.1.1.1) - framework: >= net45 - NetMQ (3.3.0.11) + NetMQ (3.3.3.1) + AsyncIO (>= 0.1.18) Newtonsoft.Json (5.0.8) - framework: >= net45 xunit (2.1) - framework: >= net451 xunit.assert (2.1) diff --git a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj index cdc8ec7..7ff32fc 100644 --- a/src/IfSharp.Kernel/IfSharp.Kernel.fsproj +++ b/src/IfSharp.Kernel/IfSharp.Kernel.fsproj @@ -122,6 +122,26 @@ --> + + + + + ..\..\packages\AsyncIO\lib\net35\AsyncIO.dll + True + True + + + + + + + ..\..\packages\AsyncIO\lib\net40\AsyncIO.dll + True + True + + + + @@ -145,6 +165,15 @@ + + + + ..\..\packages\NetMQ\lib\net35\NetMQ.dll + True + True + + + @@ -166,4 +195,4 @@ - + \ No newline at end of file diff --git a/src/IfSharp.Kernel/Kernel.fs b/src/IfSharp.Kernel/Kernel.fs index 4eaa42c..4ff16d7 100644 --- a/src/IfSharp.Kernel/Kernel.fs +++ b/src/IfSharp.Kernel/Kernel.fs @@ -16,26 +16,30 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = // startup 0mq stuff let context = NetMQContext.Create() - // heartbeat - let hbSocket = context.CreateRequestSocket() - do hbSocket.Bind(String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.hb_port)) - - // shell - let shellSocket = context.CreateRouterSocket() - do shellSocket.Bind(String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.shell_port)) + let hbSocket = context.CreateRouterSocket() + let hbSocketURL =String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.hb_port) + do hbSocket.Bind(hbSocketURL) // control let controlSocket = context.CreateRouterSocket() - do controlSocket.Bind(String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.control_port)) + let controlSocketURL = String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.control_port) + do controlSocket.Bind(controlSocketURL) // stdin let stdinSocket = context.CreateRouterSocket() - do stdinSocket.Bind(String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.stdin_port)) + let stdinSocketURL = String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.stdin_port) + do stdinSocket.Bind(stdinSocketURL) // iopub let ioSocket = context.CreatePublisherSocket() - do ioSocket.Bind(String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.iopub_port)) + let ioSocketURL = String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.iopub_port) + do ioSocket.Bind(ioSocketURL) + + // shell + let shellSocket = context.CreateRouterSocket() + let shellSocketURL =String.Format("{0}://{1}:{2}", connectionInformation.transport, connectionInformation.ip, connectionInformation.shell_port) + do shellSocket.Bind(shellSocketURL) let data = new List() let payload = new List() @@ -96,21 +100,20 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = ignore (hmac.TransformFinalBlock(Array.zeroCreate 0, 0, 0)) BitConverter.ToString(hmac.Hash).Replace("-", "").ToLower() - let recvAll (socket: NetMQSocket) = socket.ReceiveMessages() + let recvAll (socket: NetMQSocket) = socket.ReceiveMultipartBytes() /// Constructs an 'envelope' from the specified socket let recvMessage (socket: NetMQSocket) = // receive all parts of the message - let message = - recvAll (socket) - |> Seq.map decode - |> Seq.toArray + let message = (recvAll (socket)) |> Array.ofSeq + let asStrings = message |> Array.map decode // find the delimiter between IDS and MSG - let idx = Array.IndexOf(message, "") + let idx = Array.IndexOf(asStrings, "") + let idents = message.[0..idx - 1] - let messageList = message.[idx + 1..message.Length - 1] + let messageList = asStrings.[idx + 1..message.Length - 1] // detect a malformed message if messageList.Length < 4 then failwith ("Malformed message") @@ -172,7 +175,7 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = msg.Append(encode parent_header) msg.Append(encode "{}") msg.Append(encode content) - socket.SendMessage(msg) + socket.SendMultipartMessage(msg) /// Convenience method for sending the state of the kernel @@ -191,12 +194,25 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = let kernelInfoRequest(msg : KernelMessage) (content : KernelRequest) = let content = { - protocol_version = [| 4; 0 |]; - ipython_version = Some [| 1; 0; 0 |]; - language_version = [| 1; 0; 0 |]; + protocol_version = "4.0.0"; + implementation = "ifsharp"; + implementation_version = "4.0.0"; + banner = ""; + help_links = [||]; language = "fsharp"; + language_info = + { + name = "fsharp"; + version = "4.3.1.0"; + mimetype = "text/x-fsharp"; + file_extension = ".fs"; + pygments_lexer = ""; + codemirror_mode = ""; + nbconvert_exporter = ""; + }; } + sendStateBusy msg sendMessage shellSocket msg "kernel_info_reply" content /// Sends display data information immediately @@ -407,11 +423,12 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = /// Handles a 'shutdown_request' message let shutdownRequest (msg : KernelMessage) (content : ShutdownRequest) = - + logMessage "shutdown request" // TODO: actually shutdown let reply = { restart = true; } - sendMessage shellSocket msg "shutdown_reply" reply + sendMessage shellSocket msg "shutdown_reply" reply; + System.Environment.Exit(0) /// Handles a 'history_request' message let historyRequest (msg : KernelMessage) (content : HistoryRequest) = @@ -442,7 +459,6 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = logMessage (sbOut.ToString()) while true do - let msg = recvMessage (shellSocket) try @@ -456,16 +472,27 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = | HistoryRequest(r) -> historyRequest msg r | ObjectInfoRequest(r) -> objectInfoRequest msg r | InspectRequest(r) -> inspectRequest msg r - | _ -> logMessage (String.Format("Unknown content type. msg_type is `{0}`", msg.Header.msg_type)) + | _ -> logMessage (String.Format("Unknown content type on shell. msg_type is `{0}`", msg.Header.msg_type)) with | ex -> handleException ex + let doControl() = + while true do + let msg = recvMessage (controlSocket) + try + match msg.Content with + | ShutdownRequest(r) -> shutdownRequest msg r + | _ -> logMessage (String.Format("Unexpected content type on control. msg_type is `{0}`", msg.Header.msg_type)) + with + | ex -> handleException ex + /// Loops repeating message from the client let doHeartbeat() = try while true do - hbSocket.Send(hbSocket.Receive()) + let hb = hbSocket.ReceiveMultipartBytes() in + hbSocket.SendMultipartBytes(hb) with | ex -> handleException ex @@ -485,5 +512,6 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) = /// Starts the kernel asynchronously member __.StartAsync() = - Async.Start (async { doHeartbeat() } ) + //Async.Start (async { doHeartbeat() } ) Async.Start (async { doShell() } ) + Async.Start (async { doControl() } ) \ No newline at end of file diff --git a/src/IfSharp.Kernel/ShellMessages.fs b/src/IfSharp.Kernel/ShellMessages.fs index de11f12..e8b906d 100644 --- a/src/IfSharp.Kernel/ShellMessages.fs +++ b/src/IfSharp.Kernel/ShellMessages.fs @@ -334,30 +334,68 @@ type CommOpen = obj type KernelRequest = obj +type KernelReply_LanguageInfo = + { + // # Name of the programming language that the kernel implements. + // # Kernel included in IPython returns 'python'. + name: string; + + // # Language version number. + // # It is Python version number (e.g., '2.7.3') for the kernel + // # included in IPython. + version: string; + + // # mimetype for script files in this language + mimetype: string; + + // # Extension including the dot, e.g. '.py' + file_extension: string; + + // # Pygments lexer, for highlighting + // # Only needed if it differs from the 'name' field. + pygments_lexer: string; + + // # Codemirror mode, for for highlighting in the notebook. + // # Only needed if it differs from the 'name' field. + codemirror_mode: string; + + // # Nbconvert exporter, if notebooks written with this kernel should + // # be exported with something other than the general 'script' + // # exporter. + nbconvert_exporter: string; + } + +type KernelReply_HelpLink = { text: string; url: string; } + type KernelReply = { - // # Version of messaging protocol (mandatory). + // # Version of messaging protocol. // # The first integer indicates major version. It is incremented when // # there is any backward incompatible change. // # The second integer indicates minor version. It is incremented when // # there is any backward compatible change. - protocol_version: array; - - // # IPython version number (optional). - // # Non-python kernel backend may not have this version number. - // # The last component is an extra field, which may be 'dev' or - // # 'rc1' in development version. It is an empty string for - // # released version. - ipython_version: Option>; - - // # Language version number (mandatory). - // # It is Python version number (e.g., [2, 7, 3]) for the kernel - // # included in IPython. - language_version: array; - - // # Programming language in which kernel is implemented (mandatory). - // # Kernel included in IPython returns 'python'. - language: string + protocol_version: string; + + // # The kernel implementation name + // # (e.g. 'ipython' for the IPython kernel) + implementation: string; + + // # Implementation version number. + // # The version number of the kernel's implementation + // # (e.g. IPython.__version__ for the IPython kernel) + implementation_version: string; + + // # Information about the language of code for the kernel + language_info: KernelReply_LanguageInfo; + language: string; + + // # A banner of information about the kernel, + // # which may be desplayed in console environments. + banner : string; + + // # Optional: A list of dictionaries, each with keys 'text' and 'url'. + // # These will be displayed in the help menu in the notebook UI. + help_links: KernelReply_HelpLink array; } type KernelStatus = @@ -483,7 +521,7 @@ type Header = type KernelMessage = { - Identifiers: list; + Identifiers: list; HmacSignature: string; Header: Header; ParentHeader: Header; diff --git a/src/IfSharp.Kernel/app.config b/src/IfSharp.Kernel/app.config index bb9b825..3f0d0d2 100644 --- a/src/IfSharp.Kernel/app.config +++ b/src/IfSharp.Kernel/app.config @@ -6,6 +6,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/IfSharpConsole/IfSharpConsole.csproj b/src/IfSharpConsole/IfSharpConsole.csproj index 95d8766..aedd695 100644 --- a/src/IfSharpConsole/IfSharpConsole.csproj +++ b/src/IfSharpConsole/IfSharpConsole.csproj @@ -63,9 +63,6 @@ true - - ..\..\packages\NetMQ.3.3.0.11\lib\net40\NetMQ.dll - @@ -116,6 +113,26 @@ + + + + + ..\..\packages\AsyncIO\lib\net35\AsyncIO.dll + True + True + + + + + + + ..\..\packages\AsyncIO\lib\net40\AsyncIO.dll + True + True + + + + @@ -127,4 +144,24 @@ - + + + + + ..\..\packages\NetMQ\lib\net35\NetMQ.dll + True + True + + + + + + + ..\..\packages\NetMQ\lib\net40\NetMQ.dll + True + True + + + + + \ No newline at end of file diff --git a/src/IfSharpConsole/Program.cs b/src/IfSharpConsole/Program.cs index 3760510..2aa7ea0 100644 --- a/src/IfSharpConsole/Program.cs +++ b/src/IfSharpConsole/Program.cs @@ -7,6 +7,7 @@ class Program { static void Main(string[] args) { + //System.Diagnostics.Debugger.Launch(); CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; App.Start(args); diff --git a/tests/IfSharp.Kernel.Tests/IfSharp.Kernel.Tests.fsproj b/tests/IfSharp.Kernel.Tests/IfSharp.Kernel.Tests.fsproj index cfc2530..31f4e07 100644 --- a/tests/IfSharp.Kernel.Tests/IfSharp.Kernel.Tests.fsproj +++ b/tests/IfSharp.Kernel.Tests/IfSharp.Kernel.Tests.fsproj @@ -98,6 +98,26 @@ True + + + + + ..\..\packages\AsyncIO\lib\net35\AsyncIO.dll + True + True + + + + + + + ..\..\packages\AsyncIO\lib\net40\AsyncIO.dll + True + True + + + + @@ -121,6 +141,15 @@ + + + + ..\..\packages\NetMQ\lib\net35\NetMQ.dll + True + True + + +