{"action":"created","comment":{"url":"https://api.github.com/repos/ros2/rcl/pulls/comments/234356203","pull_request_review_id":175991650,"id":234356203,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzNDM1NjIwMw==","diff_hunk":"@@ -0,0 +1,759 @@\n+// Copyright 2018 Open Source Robotics Foundation, Inc.\n+//\n+// Licensed under the Apache License, Version 2.0 (the \"License\");\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+//     http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \"AS IS\" BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n+\n+#ifdef __cplusplus\n+extern \"C\"\n+{\n+#endif\n+\n+#include \"rcl_action/action_server.h\"\n+\n+#include \"rcl_action/default_qos.h\"\n+#include \"rcl_action/goal_handle.h\"\n+#include \"rcl_action/names.h\"\n+#include \"rcl_action/types.h\"\n+\n+#include \"rcl/error_handling.h\"\n+#include \"rcl/rcl.h\"\n+#include \"rcl/time.h\"\n+\n+#include \"rcutils/logging_macros.h\"\n+#include \"rcutils/strdup.h\"\n+\n+#include \"rmw/rmw.h\"\n+\n+/// Internal rcl_action implementation struct.\n+typedef struct rcl_action_server_impl_t\n+{\n+  rcl_service_t goal_service;\n+  rcl_service_t cancel_service;\n+  rcl_service_t result_service;\n+  rcl_publisher_t feedback_publisher;\n+  rcl_publisher_t status_publisher;\n+  char * action_name;\n+  rcl_action_server_options_t options;\n+  // Array of goal handles\n+  rcl_action_goal_handle_t ** goal_handles;\n+  size_t num_goal_handles;\n+  // Clock\n+  rcl_clock_t clock;\n+} rcl_action_server_impl_t;\n+\n+rcl_action_server_t\n+rcl_action_get_zero_initialized_server(void)\n+{\n+  static rcl_action_server_t null_action_server = {0};\n+  return null_action_server;\n+}\n+\n+#define SERVICE_INIT(Type) \\\n+  char * Type ## _service_name = NULL; \\\n+  ret = rcl_action_get_ ## Type ## _service_name(action_name, allocator, &Type ## _service_name); \\\n+  if (RCL_RET_OK != ret) { \\\n+    RCL_SET_ERROR_MSG(\"failed to get \" #Type \" service name\"); \\\n+    if (RCL_RET_BAD_ALLOC == ret) { \\\n+      ret = RCL_RET_BAD_ALLOC; \\\n+    } else { \\\n+      ret = RCL_RET_ERROR; \\\n+    } \\\n+    goto fail; \\\n+  } \\\n+  rcl_service_options_t Type ## _service_options = { \\\n+    .qos = options->Type ## _service_qos, .allocator = allocator \\\n+  }; \\\n+  action_server->impl->Type ## _service = rcl_get_zero_initialized_service(); \\\n+  ret = rcl_service_init( \\\n+    &action_server->impl->Type ## _service, \\\n+    node, \\\n+    type_support->Type ## _service_type_support, \\\n+    Type ## _service_name, \\\n+    &Type ## _service_options); \\\n+  allocator.deallocate(Type ## _service_name, allocator.state); \\\n+  if (RCL_RET_OK != ret) { \\\n+    if (RCL_RET_BAD_ALLOC == ret) { \\\n+      ret = RCL_RET_BAD_ALLOC; \\\n+    } else if (RCL_RET_SERVICE_NAME_INVALID == ret) { \\\n+      ret = RCL_RET_ACTION_NAME_INVALID; \\\n+    } else { \\\n+      ret = RCL_RET_ERROR; \\\n+    } \\\n+    goto fail; \\\n+  }\n+\n+#define PUBLISHER_INIT(Type) \\\n+  char * Type ## _topic_name = NULL; \\\n+  ret = rcl_action_get_ ## Type ## _topic_name(action_name, allocator, &Type ## _topic_name); \\\n+  if (RCL_RET_OK != ret) { \\\n+    RCL_SET_ERROR_MSG(\"failed to get \" #Type \" topic name\"); \\\n+    if (RCL_RET_BAD_ALLOC == ret) { \\\n+      ret = RCL_RET_BAD_ALLOC; \\\n+    } else { \\\n+      ret = RCL_RET_ERROR; \\\n+    } \\\n+    goto fail; \\\n+  } \\\n+  rcl_publisher_options_t Type ## _publisher_options = { \\\n+    .qos = options->Type ## _topic_qos, .allocator = allocator \\\n+  }; \\\n+  action_server->impl->Type ## _publisher = rcl_get_zero_initialized_publisher(); \\\n+  ret = rcl_publisher_init( \\\n+    &action_server->impl->Type ## _publisher, \\\n+    node, \\\n+    type_support->Type ## _message_type_support, \\\n+    Type ## _topic_name, \\\n+    &Type ## _publisher_options); \\\n+  allocator.deallocate(Type ## _topic_name, allocator.state); \\\n+  if (RCL_RET_OK != ret) { \\\n+    if (RCL_RET_BAD_ALLOC == ret) { \\\n+      ret = RCL_RET_BAD_ALLOC; \\\n+    } else if (RCL_RET_TOPIC_NAME_INVALID == ret) { \\\n+      ret = RCL_RET_ACTION_NAME_INVALID; \\\n+    } else { \\\n+      ret = RCL_RET_ERROR; \\\n+    } \\\n+    goto fail; \\\n+  }\n+\n+rcl_ret_t\n+rcl_action_server_init(\n+  rcl_action_server_t * action_server,\n+  rcl_node_t * node,\n+  const rosidl_action_type_support_t * type_support,\n+  const char * action_name,\n+  const rcl_action_server_options_t * options)\n+{\n+  RCL_CHECK_ARGUMENT_FOR_NULL(action_server, RCL_RET_INVALID_ARGUMENT);\n+  if (!rcl_node_is_valid(node)) {\n+    return RCL_RET_NODE_INVALID;  // error already set\n+  }\n+  RCL_CHECK_ARGUMENT_FOR_NULL(type_support, RCL_RET_INVALID_ARGUMENT);\n+  RCL_CHECK_ARGUMENT_FOR_NULL(action_name, RCL_RET_INVALID_ARGUMENT);\n+  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);\n+  rcl_allocator_t allocator = options->allocator;\n+  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, \"invalid allocator\", return RCL_RET_INVALID_ARGUMENT);\n+\n+  RCUTILS_LOG_DEBUG_NAMED(\n+    ROS_PACKAGE_NAME, \"Initializing action server for action name '%s'\", action_name);\n+  if (action_server->impl) {\n+    RCL_SET_ERROR_MSG(\"action server already initialized, or memory was unintialized\");\n+    return RCL_RET_ALREADY_INIT;\n+  }\n+\n+  // Allocate for action server\n+  action_server->impl = (rcl_action_server_impl_t *)allocator.allocate(\n+    sizeof(rcl_action_server_impl_t), allocator.state);\n+  RCL_CHECK_FOR_NULL_WITH_MSG(\n+    action_server->impl, \"allocating memory failed\", return RCL_RET_BAD_ALLOC);\n+\n+  // Initialize clock\n+  rcl_ret_t ret = rcl_clock_init(options->clock_type, &action_server->impl->clock, &allocator);\n+  if (RCL_RET_OK != ret) {\n+    return RCL_RET_ERROR;\n+  }\n+\n+  // Initialize services\n+  SERVICE_INIT(goal);\n+  SERVICE_INIT(cancel);\n+  SERVICE_INIT(result);\n+\n+  // Initialize publishers\n+  PUBLISHER_INIT(feedback);\n+  PUBLISHER_INIT(status);\n+\n+  // Copy action name\n+  action_server->impl->action_name = rcutils_strdup(action_name, allocator);\n+  if (NULL == action_server->impl->action_name) {\n+    ret = RCL_RET_BAD_ALLOC;\n+    goto fail;\n+  }\n+\n+  // Copy options\n+  action_server->impl->options = *options;\n+\n+  // Initialize goal handle array\n+  action_server->impl->goal_handles = NULL;\n+  action_server->impl->num_goal_handles = 0;\n+\n+  return RCL_RET_OK;\n+fail:\n+  {\n+    // Finalize any services/publishers that were initialized and deallocate action_server->impl\n+    rcl_ret_t ret_throwaway = rcl_action_server_fini(action_server, node);\n+    // Since there is already a failure, it is likely that finalize will error on one or more of\n+    // the action servers members\n+    (void)ret_throwaway;\n+  }\n+  return ret;\n+}\n+\n+rcl_ret_t\n+rcl_action_server_fini(rcl_action_server_t * action_server, rcl_node_t * node)\n+{\n+  RCL_CHECK_ARGUMENT_FOR_NULL(action_server, RCL_RET_ACTION_SERVER_INVALID);\n+  if (!rcl_node_is_valid(node)) {\n+    return RCL_RET_NODE_INVALID;  // error already set\n+  }\n+\n+  rcl_ret_t ret = RCL_RET_OK;\n+  if (action_server->impl) {\n+    // Finalize clock\n+    if (rcl_clock_fini(&action_server->impl->clock) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    // Finalize services\n+    if (rcl_service_fini(&action_server->impl->goal_service, node) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    if (rcl_service_fini(&action_server->impl->cancel_service, node) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    if (rcl_service_fini(&action_server->impl->result_service, node) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    // Finalize publishers\n+    if (rcl_publisher_fini(&action_server->impl->feedback_publisher, node) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    if (rcl_publisher_fini(&action_server->impl->status_publisher, node) != RCL_RET_OK) {\n+      ret = RCL_RET_ERROR;\n+    }\n+    // Deallocate struct\n+    rcl_allocator_t allocator = action_server->impl->options.allocator;\n+    allocator.deallocate(action_server->impl, allocator.state);\n+    action_server->impl = NULL;\n+  }\n+  return ret;\n+}\n+\n+rcl_action_server_options_t\n+rcl_action_server_get_default_options(void)\n+{\n+  // !!! MAKE SURE THAT CHANGES TO THESE DEFAULTS ARE REFLECTED IN THE HEADER DOC STRING\n+  static rcl_action_server_options_t default_options;\n+  default_options.goal_service_qos = rmw_qos_profile_services_default;\n+  default_options.cancel_service_qos = rmw_qos_profile_services_default;\n+  default_options.result_service_qos = rmw_qos_profile_services_default;\n+  default_options.feedback_topic_qos = rmw_qos_profile_default;\n+  default_options.status_topic_qos = rcl_action_qos_profile_status_default;\n+  default_options.allocator = rcl_get_default_allocator();\n+  default_options.clock_type = RCL_ROS_TIME;\n+  default_options.result_timeout.nanoseconds = (rcl_duration_value_t)9e11;  // 15 minutes\n+  return default_options;\n+}\n+\n+#define TAKE_SERVICE_REQUEST(Type) \\\n+  if (!rcl_action_server_is_valid(action_server)) { \\\n+    return RCL_RET_ACTION_SERVER_INVALID;  /* error already set */ \\\n+  } \\\n+  RCL_CHECK_ARGUMENT_FOR_NULL(ros_ ## Type ## _request, RCL_RET_INVALID_ARGUMENT); \\\n+  rmw_request_id_t request_header;  /* ignored */ \\\n+  rcl_ret_t ret = rcl_take_request( \\\n+    &action_server->impl->Type ## _service, &request_header, ros_ ## Type ## _request); \\\n+  if (RCL_RET_OK != ret) { \\\n+    if (RCL_RET_BAD_ALLOC == ret) { \\\n+      return RCL_RET_BAD_ALLOC;  /* error already set */ \\\n+    } \\\n+    if (RCL_RET_SERVICE_TAKE_FAILED == ret) { \\\n+      return RCL_RET_ACTION_SERVER_TAKE_FAILED; \\\n+    } \\\n+    return RCL_RET_ERROR;  /* error already set */ \\\n+  } \\\n+  return RCL_RET_OK; \\\n+\n+#define SEND_SERVICE_RESPONSE(Type) \\\n+  if (!rcl_action_server_is_valid(action_server)) { \\\n+    return RCL_RET_ACTION_SERVER_INVALID;  /* error already set */ \\\n+  } \\\n+  RCL_CHECK_ARGUMENT_FOR_NULL(ros_ ## Type ## _response, RCL_RET_INVALID_ARGUMENT); \\\n+  rmw_request_id_t request_header;  /* ignored */ \\\n+  rcl_ret_t ret = rcl_send_response( \\\n+    &action_server->impl->Type ## _service, &request_header, ros_ ## Type ## _response); \\\n+  if (RCL_RET_OK != ret) { \\\n+    return RCL_RET_ERROR;  /* error already set */ \\\n+  } \\\n+  return RCL_RET_OK; \\\n+\n+rcl_ret_t\n+rcl_action_take_goal_request(\n+  const rcl_action_server_t * action_server,\n+  void * ros_goal_request)\n+{\n+  TAKE_SERVICE_REQUEST(goal);\n+}\n+\n+rcl_ret_t\n+rcl_action_send_goal_response(\n+  const rcl_action_server_t * action_server,\n+  void * ros_goal_response)\n+{\n+  SEND_SERVICE_RESPONSE(goal);\n+}\n+\n+// Implementation only\n+static int64_t\n+_goal_info_stamp_to_nanosec(const rcl_action_goal_info_t * goal_info)\n+{\n+  assert(goal_info);\n+  return (int64_t)(goal_info->stamp.sec * 1e9) + (int64_t)goal_info->stamp.nanosec;\n+}\n+\n+// Implementation only\n+static void\n+_nanosec_to_goal_info_stamp(const int64_t * nanosec, rcl_action_goal_info_t * goal_info)\n+{\n+  assert(nanosec);\n+  assert(goal_info);\n+  goal_info->stamp.sec = (int32_t) (*nanosec / (int64_t)1e9);\n+  goal_info->stamp.nanosec = (uint32_t)(*nanosec - (int64_t)(goal_info->stamp.sec * 1e9));\n+}\n+\n+rcl_action_goal_handle_t *\n+rcl_action_accept_new_goal(\n+  rcl_action_server_t * action_server,\n+  const rcl_action_goal_info_t * goal_info)\n+{\n+  if (!rcl_action_server_is_valid(action_server)) {\n+    return NULL;  // error already set\n+  }\n+  RCL_CHECK_ARGUMENT_FOR_NULL(goal_info, NULL);\n+\n+  // Check if goal with same ID already exists\n+  if (rcl_action_server_goal_exists(action_server, goal_info)) {\n+    RCL_SET_ERROR_MSG(\"goal ID already exists\");\n+    return NULL;\n+  }\n+\n+  // Allocate space in the goal handle pointer array\n+  rcl_allocator_t allocator = action_server->impl->options.allocator;\n+  rcl_action_goal_handle_t ** goal_handles = action_server->impl->goal_handles;\n+  const size_t num_goal_handles = action_server->impl->num_goal_handles;\n+  // TODO(jacobperron): Don't allocate for every accepted goal handle,\n+  //                    instead double the memory allocated if needed.\n+  const size_t new_num_goal_handles = num_goal_handles + 1;\n+  void * tmp_ptr = allocator.reallocate(\n+    goal_handles, new_num_goal_handles * sizeof(rcl_action_goal_handle_t *), allocator.state);\n+  if (!tmp_ptr) {\n+    RCL_SET_ERROR_MSG(\"memory allocation failed for goal handle pointer\");\n+    return NULL;\n+  }\n+  goal_handles = (rcl_action_goal_handle_t **)tmp_ptr;\n+\n+  // Allocate space for a new goal handle\n+  tmp_ptr = allocator.allocate(sizeof(rcl_action_goal_handle_t), allocator.state);\n+  if (!tmp_ptr) {\n+    RCL_SET_ERROR_MSG(\"memory allocation failed for new goal handle\");\n+    return NULL;\n+  }\n+  goal_handles[num_goal_handles] = (rcl_action_goal_handle_t *) tmp_ptr;\n+\n+  // Re-stamp goal info with current time\n+  rcl_action_goal_info_t goal_info_stamp_now = rcl_action_get_zero_initialized_goal_info();\n+  goal_info_stamp_now = *goal_info;\n+  rcl_time_point_value_t now_time_point;\n+  rcl_ret_t ret = rcl_clock_get_now(&action_server->impl->clock, &now_time_point);\n+  if (RCL_RET_OK != ret) {\n+    return NULL;  // Error already set\n+  }\n+  _nanosec_to_goal_info_stamp(&now_time_point, &goal_info_stamp_now);\n+\n+  // Create a new goal handle\n+  *goal_handles[num_goal_handles] = rcl_action_get_zero_initialized_goal_handle();\n+  ret = rcl_action_goal_handle_init(\n+    goal_handles[num_goal_handles], &goal_info_stamp_now, allocator);\n+  if (RCL_RET_OK != ret) {\n+    RCL_SET_ERROR_MSG(\"failed to initialize goal handle\");\n+    return NULL;\n+  }\n+\n+  action_server->impl->goal_handles = goal_handles;\n+  action_server->impl->num_goal_handles = new_num_goal_handles;\n+  return goal_handles[num_goal_handles];\n+}\n+\n+rcl_ret_t\n+rcl_action_publish_feedback(\n+  const rcl_action_server_t * action_server,\n+  void * ros_feedback)\n+{\n+  if (!rcl_action_server_is_valid(action_server)) {\n+    return RCL_RET_ACTION_SERVER_INVALID;  // error already set\n+  }\n+  RCL_CHECK_ARGUMENT_FOR_NULL(ros_feedback, RCL_RET_INVALID_ARGUMENT);\n+\n+  rcl_ret_t ret = rcl_publish(&action_server->impl->feedback_publisher, ros_feedback);\n+  if (RCL_RET_OK != ret) {\n+    return RCL_RET_ERROR;  // error already set\n+  }\n+  return RCL_RET_OK;\n+}\n+\n+rcl_ret_t\n+rcl_action_get_goal_status_array(\n+  const rcl_action_server_t * action_server,\n+  rcl_action_goal_status_array_t * status_message)\n+{\n+  if (!rcl_action_server_is_valid(action_server)) {\n+    return RCL_RET_ACTION_SERVER_INVALID;  // error already set\n+  }\n+  RCL_CHECK_ARGUMENT_FOR_NULL(status_message, RCL_RET_INVALID_ARGUMENT);\n+\n+  // If number of goals is zero, then we don't need to do any allocation\n+  size_t num_goals = action_server->impl->num_goal_handles;\n+  if (0 == num_goals) {\n+    status_message->msg.status_list.size = 0u;\n+    return RCL_RET_OK;\n+  }\n+\n+  // Allocate status array\n+  rcl_allocator_t allocator = action_server->impl->options.allocator;\n+  rcl_ret_t ret = rcl_action_goal_status_array_init(status_message, num_goals, allocator);\n+  if (RCL_RET_OK != ret) {\n+    if (RCL_RET_BAD_ALLOC == ret) {\n+      return RCL_RET_BAD_ALLOC;\n+    }\n+    return RCL_RET_ERROR;\n+  }\n+\n+  // Populate status array\n+  for (size_t i = 0; i < num_goals; ++i) {\n+    ret = rcl_action_goal_handle_get_info(\n+      action_server->impl->goal_handles[i], &status_message->msg.status_list.data[i].goal_info);\n+    if (RCL_RET_OK != ret) {\n+      return RCL_RET_ERROR;\n+    }\n+    ret = rcl_action_goal_handle_get_status(\n+      action_server->impl->goal_handles[i], &status_message->msg.status_list.data[i].status);\n+    if (RCL_RET_OK != ret) {\n+      return RCL_RET_ERROR;\n+    }\n+  }\n+  return RCL_RET_OK;\n+}\n+\n+rcl_ret_t\n+rcl_action_publish_status(\n+  const rcl_action_server_t * action_server,\n+  const void * status_message)\n+{\n+  if (!rcl_action_server_is_valid(action_server)) {\n+    return RCL_RET_ACTION_SERVER_INVALID;  // error already set\n+  }\n+  RCL_CHECK_ARGUMENT_FOR_NULL(status_message, RCL_RET_INVALID_ARGUMENT);\n+\n+  rcl_ret_t ret = rcl_publish(&action_server->impl->status_publisher, status_message);\n+  if (RCL_RET_OK != ret) {\n+    return RCL_RET_ERROR;  // error already set\n+  }\n+  return RCL_RET_OK;\n+}\n+\n+rcl_ret_t\n+rcl_action_take_result_request(\n+  const rcl_action_server_t * action_server,\n+  void * ros_result_request)\n+{\n+  TAKE_SERVICE_REQUEST(result);\n+}\n+\n+rcl_ret_t\n+rcl_action_send_result_response(\n+  const rcl_action_server_t * action_server,\n+  void * ros_result_response)\n+{\n+  SEND_SERVICE_RESPONSE(result);\n+}\n+\n+rcl_ret_t\n+rcl_action_clear_expired_goals(\n+  const rcl_action_server_t * action_server,\n+  size_t * num_expired)","path":"rcl_action/src/rcl_action/action_server.c","position":490,"original_position":480,"commit_id":"7028e3f169de90c3bb5e09acffe9fde5bfa4d2d3","original_commit_id":"7903df9cde00a99f5521aa39225d2e1869a38dad","user":{"login":"jacobperron","id":1218431,"node_id":"MDQ6VXNlcjEyMTg0MzE=","avatar_url":"https://avatars1.githubusercontent.com/u/1218431?v=4","gravatar_id":"","url":"https://api.github.com/users/jacobperron","html_url":"https://github.com/jacobperron","followers_url":"https://api.github.com/users/jacobperron/followers","following_url":"https://api.github.com/users/jacobperron/following{/other_user}","gists_url":"https://api.github.com/users/jacobperron/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobperron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobperron/subscriptions","organizations_url":"https://api.github.com/users/jacobperron/orgs","repos_url":"https://api.github.com/users/jacobperron/repos","events_url":"https://api.github.com/users/jacobperron/events{/privacy}","received_events_url":"https://api.github.com/users/jacobperron/received_events","type":"User","site_admin":false},"body":"The client library can call `rcl_action_server_goal_exists()` to check if a previously accepted goal has expired.","created_at":"2018-11-16T21:41:17Z","updated_at":"2018-11-16T21:41:17Z","html_url":"https://github.com/ros2/rcl/pull/323#discussion_r234356203","pull_request_url":"https://api.github.com/repos/ros2/rcl/pulls/323","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/ros2/rcl/pulls/comments/234356203"},"html":{"href":"https://github.com/ros2/rcl/pull/323#discussion_r234356203"},"pull_request":{"href":"https://api.github.com/repos/ros2/rcl/pulls/323"}},"in_reply_to_id":233646405},"pull_request":{"url":"https://api.github.com/repos/ros2/rcl/pulls/323","id":229467537,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI5NDY3NTM3","html_url":"https://github.com/ros2/rcl/pull/323","diff_url":"https://github.com/ros2/rcl/pull/323.diff","patch_url":"https://github.com/ros2/rcl/pull/323.patch","issue_url":"https://api.github.com/repos/ros2/rcl/issues/323","number":323,"state":"open","locked":false,"title":"Action server implementation","user":{"login":"jacobperron","id":1218431,"node_id":"MDQ6VXNlcjEyMTg0MzE=","avatar_url":"https://avatars1.githubusercontent.com/u/1218431?v=4","gravatar_id":"","url":"https://api.github.com/users/jacobperron","html_url":"https://github.com/jacobperron","followers_url":"https://api.github.com/users/jacobperron/followers","following_url":"https://api.github.com/users/jacobperron/following{/other_user}","gists_url":"https://api.github.com/users/jacobperron/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobperron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobperron/subscriptions","organizations_url":"https://api.github.com/users/jacobperron/orgs","repos_url":"https://api.github.com/users/jacobperron/repos","events_url":"https://api.github.com/users/jacobperron/events{/privacy}","received_events_url":"https://api.github.com/users/jacobperron/received_events","type":"User","site_admin":false},"body":"First iteration of implementation.\r\n\r\nConnects to #306 \r\nDepends on ros2/rcl_interfaces#47\r\nDepends on ros2/rosidl#310","created_at":"2018-11-08T18:36:39Z","updated_at":"2018-11-16T21:41:17Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d59d13587afcea8d84abe9c809d611104d0a544b","assignee":{"login":"jacobperron","id":1218431,"node_id":"MDQ6VXNlcjEyMTg0MzE=","avatar_url":"https://avatars1.githubusercontent.com/u/1218431?v=4","gravatar_id":"","url":"https://api.github.com/users/jacobperron","html_url":"https://github.com/jacobperron","followers_url":"https://api.github.com/users/jacobperron/followers","following_url":"https://api.github.com/users/jacobperron/following{/other_user}","gists_url":"https://api.github.com/users/jacobperron/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobperron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobperron/subscriptions","organizations_url":"https://api.github.com/users/jacobperron/orgs","repos_url":"https://api.github.com/users/jacobperron/repos","events_url":"https://api.github.com/users/jacobperron/events{/privacy}","received_events_url":"https://api.github.com/users/jacobperron/received_events","type":"User","site_admin":false},"assignees":[{"login":"jacobperron","id":1218431,"node_id":"MDQ6VXNlcjEyMTg0MzE=","avatar_url":"https://avatars1.githubusercontent.com/u/1218431?v=4","gravatar_id":"","url":"https://api.github.com/users/jacobperron","html_url":"https://github.com/jacobperron","followers_url":"https://api.github.com/users/jacobperron/followers","following_url":"https://api.github.com/users/jacobperron/following{/other_user}","gists_url":"https://api.github.com/users/jacobperron/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobperron/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobperron/subscriptions","organizations_url":"https://api.github.com/users/jacobperron/orgs","repos_url":"https://api.github.com/users/jacobperron/repos","events_url":"https://api.github.com/users/jacobperron/events{/privacy}","received_events_url":"https://api.github.com/users/jacobperron/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":180241238,"node_id":"MDU6TGFiZWwxODAyNDEyMzg=","url":"https://api.github.com/repos/ros2/rcl/labels/in%20review","name":"in review","color":"388be2","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/ros2/rcl/pulls/323/commits","review_comments_url":"https://api.github.com/repos/ros2/rcl/pulls/323/comments","review_comment_url":"https://api.github.com/repos/ros2/rcl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ros2/rcl/issues/323/comments","statuses_url":"https://api.github.com/repos/ros2/rcl/statuses/7028e3f169de90c3bb5e09acffe9fde5bfa4d2d3","head":{"label":"ros2:jacob/action_server","ref":"jacob/action_server","sha":"7028e3f169de90c3bb5e09acffe9fde5bfa4d2d3","user":{"login":"ros2","id":3979232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5NzkyMzI=","avatar_url":"https://avatars1.githubusercontent.com/u/3979232?v=4","gravatar_id":"","url":"https://api.github.com/users/ros2","html_url":"https://github.com/ros2","followers_url":"https://api.github.com/users/ros2/followers","following_url":"https://api.github.com/users/ros2/following{/other_user}","gists_url":"https://api.github.com/users/ros2/gists{/gist_id}","starred_url":"https://api.github.com/users/ros2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ros2/subscriptions","organizations_url":"https://api.github.com/users/ros2/orgs","repos_url":"https://api.github.com/users/ros2/repos","events_url":"https://api.github.com/users/ros2/events{/privacy}","received_events_url":"https://api.github.com/users/ros2/received_events","type":"Organization","site_admin":false},"repo":{"id":31091419,"node_id":"MDEwOlJlcG9zaXRvcnkzMTA5MTQxOQ==","name":"rcl","full_name":"ros2/rcl","private":false,"owner":{"login":"ros2","id":3979232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5NzkyMzI=","avatar_url":"https://avatars1.githubusercontent.com/u/3979232?v=4","gravatar_id":"","url":"https://api.github.com/users/ros2","html_url":"https://github.com/ros2","followers_url":"https://api.github.com/users/ros2/followers","following_url":"https://api.github.com/users/ros2/following{/other_user}","gists_url":"https://api.github.com/users/ros2/gists{/gist_id}","starred_url":"https://api.github.com/users/ros2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ros2/subscriptions","organizations_url":"https://api.github.com/users/ros2/orgs","repos_url":"https://api.github.com/users/ros2/repos","events_url":"https://api.github.com/users/ros2/events{/privacy}","received_events_url":"https://api.github.com/users/ros2/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/ros2/rcl","description":"Library to support implementation of language specific ROS Client Libraries.","fork":false,"url":"https://api.github.com/repos/ros2/rcl","forks_url":"https://api.github.com/repos/ros2/rcl/forks","keys_url":"https://api.github.com/repos/ros2/rcl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ros2/rcl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ros2/rcl/teams","hooks_url":"https://api.github.com/repos/ros2/rcl/hooks","issue_events_url":"https://api.github.com/repos/ros2/rcl/issues/events{/number}","events_url":"https://api.github.com/repos/ros2/rcl/events","assignees_url":"https://api.github.com/repos/ros2/rcl/assignees{/user}","branches_url":"https://api.github.com/repos/ros2/rcl/branches{/branch}","tags_url":"https://api.github.com/repos/ros2/rcl/tags","blobs_url":"https://api.github.com/repos/ros2/rcl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ros2/rcl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ros2/rcl/git/refs{/sha}","trees_url":"https://api.github.com/repos/ros2/rcl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ros2/rcl/statuses/{sha}","languages_url":"https://api.github.com/repos/ros2/rcl/languages","stargazers_url":"https://api.github.com/repos/ros2/rcl/stargazers","contributors_url":"https://api.github.com/repos/ros2/rcl/contributors","subscribers_url":"https://api.github.com/repos/ros2/rcl/subscribers","subscription_url":"https://api.github.com/repos/ros2/rcl/subscription","commits_url":"https://api.github.com/repos/ros2/rcl/commits{/sha}","git_commits_url":"https://api.github.com/repos/ros2/rcl/git/commits{/sha}","comments_url":"https://api.github.com/repos/ros2/rcl/comments{/number}","issue_comment_url":"https://api.github.com/repos/ros2/rcl/issues/comments{/number}","contents_url":"https://api.github.com/repos/ros2/rcl/contents/{+path}","compare_url":"https://api.github.com/repos/ros2/rcl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ros2/rcl/merges","archive_url":"https://api.github.com/repos/ros2/rcl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ros2/rcl/downloads","issues_url":"https://api.github.com/repos/ros2/rcl/issues{/number}","pulls_url":"https://api.github.com/repos/ros2/rcl/pulls{/number}","milestones_url":"https://api.github.com/repos/ros2/rcl/milestones{/number}","notifications_url":"https://api.github.com/repos/ros2/rcl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ros2/rcl/labels{/name}","releases_url":"https://api.github.com/repos/ros2/rcl/releases{/id}","deployments_url":"https://api.github.com/repos/ros2/rcl/deployments","created_at":"2015-02-21T00:06:40Z","updated_at":"2018-11-16T19:11:33Z","pushed_at":"2018-11-16T20:25:26Z","git_url":"git://github.com/ros2/rcl.git","ssh_url":"git@github.com:ros2/rcl.git","clone_url":"https://github.com/ros2/rcl.git","svn_url":"https://github.com/ros2/rcl","homepage":null,"size":1148,"stargazers_count":22,"watchers_count":22,"language":"C","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":27,"mirror_url":null,"archived":false,"open_issues_count":42,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":27,"open_issues":42,"watchers":22,"default_branch":"master"}},"base":{"label":"ros2:master","ref":"master","sha":"e59c14638dcf8a681144634a81be67ad5d57b274","user":{"login":"ros2","id":3979232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5NzkyMzI=","avatar_url":"https://avatars1.githubusercontent.com/u/3979232?v=4","gravatar_id":"","url":"https://api.github.com/users/ros2","html_url":"https://github.com/ros2","followers_url":"https://api.github.com/users/ros2/followers","following_url":"https://api.github.com/users/ros2/following{/other_user}","gists_url":"https://api.github.com/users/ros2/gists{/gist_id}","starred_url":"https://api.github.com/users/ros2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ros2/subscriptions","organizations_url":"https://api.github.com/users/ros2/orgs","repos_url":"https://api.github.com/users/ros2/repos","events_url":"https://api.github.com/users/ros2/events{/privacy}","received_events_url":"https://api.github.com/users/ros2/received_events","type":"Organization","site_admin":false},"repo":{"id":31091419,"node_id":"MDEwOlJlcG9zaXRvcnkzMTA5MTQxOQ==","name":"rcl","full_name":"ros2/rcl","private":false,"owner":{"login":"ros2","id":3979232,"node_id":"MDEyOk9yZ2FuaXphdGlvbjM5NzkyMzI=","avatar_url":"https://avatars1.githubusercontent.com/u/3979232?v=4","gravatar_id":"","url":"https://api.github.com/users/ros2","html_url":"https://github.com/ros2","followers_url":"https://api.github.com/users/ros2/followers","following_url":"https://api.github.com/users/ros2/following{/other_user}","gists_url":"https://api.github.com/users/ros2/gists{/gist_id}","starred_url":"https://api.github.com/users/ros2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ros2/subscriptions","organizations_url":"https://api.github.com/users/ros2/orgs","repos_url":"https://api.github.com/users/ros2/repos","events_url":"https://api.github.com/users/ros2/events{/privacy}","received_events_url":"https://api.github.com/users/ros2/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/ros2/rcl","description":"Library to support implementation of language specific ROS Client Libraries.","fork":false,"url":"https://api.github.com/repos/ros2/rcl","forks_url":"https://api.github.com/repos/ros2/rcl/forks","keys_url":"https://api.github.com/repos/ros2/rcl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ros2/rcl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ros2/rcl/teams","hooks_url":"https://api.github.com/repos/ros2/rcl/hooks","issue_events_url":"https://api.github.com/repos/ros2/rcl/issues/events{/number}","events_url":"https://api.github.com/repos/ros2/rcl/events","assignees_url":"https://api.github.com/repos/ros2/rcl/assignees{/user}","branches_url":"https://api.github.com/repos/ros2/rcl/branches{/branch}","tags_url":"https://api.github.com/repos/ros2/rcl/tags","blobs_url":"https://api.github.com/repos/ros2/rcl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ros2/rcl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ros2/rcl/git/refs{/sha}","trees_url":"https://api.github.com/repos/ros2/rcl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ros2/rcl/statuses/{sha}","languages_url":"https://api.github.com/repos/ros2/rcl/languages","stargazers_url":"https://api.github.com/repos/ros2/rcl/stargazers","contributors_url":"https://api.github.com/repos/ros2/rcl/contributors","subscribers_url":"https://api.github.com/repos/ros2/rcl/subscribers","subscription_url":"https://api.github.com/repos/ros2/rcl/subscription","commits_url":"https://api.github.com/repos/ros2/rcl/commits{/sha}","git_commits_url":"https://api.github.com/repos/ros2/rcl/git/commits{/sha}","comments_url":"https://api.github.com/repos/ros2/rcl/comments{/number}","issue_comment_url":"https://api.github.com/repos/ros2/rcl/issues/comments{/number}","contents_url":"https://api.github.com/repos/ros2/rcl/contents/{+path}","compare_url":"https://api.github.com/repos/ros2/rcl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ros2/rcl/merges","archive_url":"https://api.github.com/repos/ros2/rcl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ros2/rcl/downloads","issues_url":"https://api.github.com/repos/ros2/rcl/issues{/number}","pulls_url":"https://api.github.com/repos/ros2/rcl/pulls{/number}","milestones_url":"https://api.github.com/repos/ros2/rcl/milestones{/number}","notifications_url":"https://api.github.com/repos/ros2/rcl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ros2/rcl/labels{/name}","releases_url":"https://api.github.com/repos/ros2/rcl/releases{/id}","deployments_url":"https://api.github.com/repos/ros2/rcl/deployments","created_at":"2015-02-21T00:06:40Z","updated_at":"2018-11-16T19:11:33Z","pushed_at":"2018-11-16T20:25:26Z","git_url":"git://github.com/ros2/rcl.git","ssh_url":"git@github.com:ros2/rcl.git","clone_url":"https://github.com/ros2/rcl.git","svn_url":"https://github.com/ros2/rcl","homepage":null,"size":1148,"stargazers_count":22,"watchers_count":22,"language":"C","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":27,"mirror_url":null,"archived":false,"open_issues_count":42,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":27,"open_issues":42,"watchers":22,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ros2/rcl/pulls/323"},"html":{"href":"https://github.com/ros2/rcl/pull/323"},"issue":{"href":"https://api.github.com/repos/ros2/rcl/issues/323"},"comments":{"href":"https://api.github.com/repos/ros2/rcl/issues/323/comments"},"review_comments":{"href":"https://api.github.com/repos/ros2/rcl/pulls/323/comments"},"review_comment":{"href":"https://api.github.com/repos/ros2/rcl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ros2/rcl/pulls/323/commits"},"statuses":{"href":"https://api.github.com/repos/ros2/rcl/statuses/7028e3f169de90c3bb5e09acffe9fde5bfa4d2d3"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"jacobperron"}}