Skip to content

Commit

Permalink
started docs on ipython_protocol. need to finish
Browse files Browse the repository at this point in the history
  • Loading branch information
daemacles committed Mar 18, 2015
1 parent 52f560f commit b873e78
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 33 deletions.
6 changes: 5 additions & 1 deletion src/cpp_plot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ std::string LoadFile(std::string filename);
*
* The NumpyArray is named at construction with the name of the python
* variable into which its data will be placed. The name is immutable, but
* the data held by this array is not.
* the data held by this array is not. The data must be of type
* NumpyArray::dtype.
*
* Usage:
\code
Expand All @@ -38,6 +39,9 @@ std::string LoadFile(std::string filename);
*/
class NumpyArray {
public:
/** The type expected by numpy when reading the raw data buffer. The data
* passed to NumpyArray must be of this type.
*/
typedef double dtype;

//--------------------------------------------------
Expand Down
24 changes: 14 additions & 10 deletions src/ipython_protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

#include "ipython_protocol.hpp"

/// Delimeter used by the iPython messaging protocol to separate ZMQ
/// identities from message data.
static const std::string DELIM{"<IDS|MSG>"};

std::string GetUuid (void) {
uuid_t uuid;
char uuid_str[37] = {'\0'};
Expand Down Expand Up @@ -49,21 +53,21 @@ IPyKernelConfig::IPyKernelConfig (const std::string &jsonConfigFile) {


std::vector<Json::Value> IPythonMessage::GetMessageParts (void) const {
return {header_, parent_, metadata_, content_};
return {header, parent, metadata, content};
}


IPythonMessage MessageBuilder::BuildExecuteRequest (
const std::string &code) const {
IPythonMessage message{ident_};

message.header_["msg_type"] = "execute_request";
message.content_["code"] = code;
message.content_["silent"] = false;
message.content_["store_history"] = true;
message.content_["user_variables"] = Json::Value(Json::arrayValue);
message.content_["user_expressions"] = Json::Value(Json::objectValue);
message.content_["allow_stdin"] = false;
message.header["msg_type"] = "execute_request";
message.content["code"] = code;
message.content["silent"] = false;
message.content["store_history"] = true;
message.content["user_variables"] = Json::Value(Json::arrayValue);
message.content["user_expressions"] = Json::Value(Json::objectValue);
message.content["allow_stdin"] = false;

return message;
}
Expand Down Expand Up @@ -141,9 +145,9 @@ void ShellConnection::RunCode (const std::string &code) {

bool ShellConnection::HasVariable (const std::string &variable_name) {
IPythonMessage command = message_builder_.BuildExecuteRequest("None");
command.content_["user_variables"].append(variable_name);
command.content["user_variables"].append(variable_name);
IPythonMessage response = Send(command);
return response.content_["user_variables"][variable_name]["status"]
return response.content["user_variables"][variable_name]["status"]
.asString() == "ok";
}

Expand Down
131 changes: 109 additions & 22 deletions src/ipython_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,161 @@ extern "C" {

struct IPyKernelConfig; // forward def

/// Function object that computes an HMAC hash from a vector of JSON values.
typedef std::function<std::string(std::vector<Json::Value>)> HmacFn;
enum class PortType {SHELL, IOPUB, STDIN, HB};

const std::string DELIM{"<IDS|MSG>"};
/// The different kinds of socket ports that an iPython kernel listens on.
enum class PortType {SHELL, IOPUB, STDIN, HB};

//--------------------------------------------------
/** \brief Generates a new UUID
*/
std::string GetUuid(void);


//--------------------------------------------------
/** \brief Returns a string URI like "tcp://hostname:port" from its args.
*
* \param config Config containing hostname and transport type.
* \param port Port the host is listening on.
*/
std::string BuildUri(const IPyKernelConfig &config, PortType port);


//======================================================================
/** \brief Configuration values for connecting to an iPython kernel. See
* http://ipython.org/ipython-doc/1/development/messaging.html for more
* details.
*/
struct IPyKernelConfig {
/// The port the shell socket is listening on
size_t shell_port;

/// The port the iopub socket is listening on
size_t iopub_port;

/// The port the stdin socket is listening on
size_t stdin_port;

/// The port the shell is listening on
size_t hb_port;

/// The IP address the kernel is listening on
std::string ip;

/// The transport used by the kernel, e.g., "tcp"
std::string transport;

/// \brief The hash function used to generate HMACs. Only sha-256 is
/// supported at this time.
std::string signature_scheme;

/// The key used for HMAC generation
std::string key;

//--------------------------------------------------
/** \brief Constructs a new IPyKernelConfig from a JSON file on disk, such
* as the one generated by \code ipython kernel --pylab \endcode.
*/
IPyKernelConfig (const std::string &jsonConfigFile);
};


class IPythonMessage {
public:
Json::Value header_;
Json::Value parent_;
Json::Value metadata_;
Json::Value content_;
//======================================================================
/** \brief Struct that wraps up the different data (i.e. not metadata like
* HMAC) fields for an IPython ZMQ General Message Format. See
* http://ipython.org/ipython-doc/1/development/messaging.html#general-message-format
* for more detail.
*/
struct IPythonMessage {
/// The header = {'msg_id', 'username', 'session', 'msg_type'}
Json::Value header;

/// The header of this message's parent. To associate response with request
Json::Value parent;

/// Metadata for this message. Seems to be unused?
Json::Value metadata;

/// Content payload for this message. msg_type dependant.
Json::Value content;

//--------------------------------------------------
/** \brief Constructs an empty message for a specific session.
*
* \param ident identity of the session this message belongs to.
*/
explicit IPythonMessage(const std::string &ident)
: header_{Json::objectValue},
parent_{Json::objectValue},
metadata_{Json::objectValue},
content_{Json::objectValue}
: header{Json::objectValue},
parent{Json::objectValue},
metadata{Json::objectValue},
content{Json::objectValue}
{
char username[80];
getlogin_r(username, 80);
header_["username"] = std::string(username);
header_["session"] = ident;
header_["msg_id"] = GetUuid();
header["username"] = std::string(username);
header["session"] = ident;
header["msg_id"] = GetUuid();
}

//--------------------------------------------------
/** \brief Constructs a message with predefined fields.
*
* \param message_parts A vector of JSON objects to assign to each of the
* fields. It assumes the elements will be in order
* [header, parent_header, metadata, content].
*/
explicit IPythonMessage(const std::vector<Json::Value> &message_parts)
: header_(message_parts[0]),
parent_(message_parts[1]),
metadata_(message_parts[2]),
content_(message_parts[3])
: header(message_parts[0]),
parent(message_parts[1]),
metadata(message_parts[2]),
content(message_parts[3])
{}

std::vector<Json::Value> GetMessageParts(void) const;
};


//======================================================================
/** \brief Class of factory methods for constructing various kinds of
* IPythonMessages associated with a particular session.
*
* Usage:
\code
MessageBuilder builder("my_session_id");
IPythonMessage command = builder.BuildExecuteRequest("print 'Hello!'");
\endcode
*/
class MessageBuilder {
public:
MessageBuilder(const std::string &ident) : ident_(ident) {}

//--------------------------------------------------
/** \brief Constructs a new MessageBuilder associated with a specific
* session.
*
* \param ident the identity of the session, any arbitrary string, but .
*/
explicit MessageBuilder(const std::string &ident) : ident_(ident) {}

//--------------------------------------------------
/** \brief Returns a new ExecuteRequest message.
*
* \param code The code to be run in an iPython kernel.
*/
IPythonMessage BuildExecuteRequest (const std::string &code) const ;

private:
const std::string ident_;
};


//======================================================================
/** \brief A connection to the shell socket of an iPython kernel.
*
* TODO fill this out!
*/
class ShellConnection {
public:
//
ShellConnection(const IPyKernelConfig &config, zmq::context_t &context,
const HmacFn &hmac_fn)
: hmac_fn_{hmac_fn},
Expand All @@ -113,7 +200,7 @@ class ShellConnection {

class IPythonSession {
public:
IPythonSession (const IPyKernelConfig &config)
explicit IPythonSession (const IPyKernelConfig &config)
: config_{config},
zmq_context_{1},
hmac_fn_{std::bind(&IPythonSession::ComputeHMAC_, this,
Expand Down

0 comments on commit b873e78

Please sign in to comment.