# # # add_file "json_msgs.cc" # content [f7262e44e2fba14e5e8290ecffac79f8bd039cf4] # # add_file "json_msgs.hh" # content [bec4ebb4a8903ea34c0feb53430b5e6ff0d6b165] # # patch "Makefile.am" # from [6f447accf75920caed5092841638835d59a429d9] # to [6c2d4e6faff8812b27176ce16ec35244653b4420] # # patch "cmd_scgi.cc" # from [18ff8d191dfc47514b90fd910d811a25284b0266] # to [4b111b0c791f43e187fc457fd3dfe82ce75922de] # # patch "gsync.cc" # from [5a5e7367916f54b940c3ff3db7f5e55da0c43a52] # to [aa2d92f5428843bfd168e7d1e3832a8f7f95907d] # # patch "http_client.cc" # from [04067dcf693ff4f61072c778668e58c69d728fe6] # to [01ad87bb1795c9e9c66a9c6f108671fb6eb2eaff] # ============================================================ --- json_msgs.cc f7262e44e2fba14e5e8290ecffac79f8bd039cf4 +++ json_msgs.cc f7262e44e2fba14e5e8290ecffac79f8bd039cf4 @@ -0,0 +1,330 @@ +// Copyright (C) 2008 Graydon Hoare +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + + +#include "base.hh" +#include "json_io.hh" +#include "json_msgs.hh" + +#include +#include +#include + +using std::map; +using std::set; +using std::string; +using std::pair; + +using json_io::json_value_t; +using json_io::json_array_t; +using json_io::json_object_t; + + +namespace +{ + namespace syms + { + // cset symbols + symbol const delete_node("delete"); + symbol const rename("rename"); + symbol const content("content"); + symbol const add_file("add_file"); + symbol const add_dir("add_dir"); + symbol const patch("patch"); + symbol const from("from"); + symbol const to("to"); + symbol const clear("clear"); + symbol const set("set"); + symbol const attr("attr"); + symbol const value("value"); + + // revision symbols + symbol const old_revision("old_revision"); + symbol const new_manifest("new_manifest"); + symbol const edges("edges"); + + // file delta / data symbols + symbol const id("id"); + symbol const src_id("src_id"); + symbol const dst_id("dst_id"); + symbol const delta("delta"); + symbol const data("data"); + + // command symbols + symbol const type("type"); + symbol const vers("vers"); + symbol const revs("revs"); + symbol const error("error"); + + symbol const inquire("inquire"); + symbol const confirm("confirm"); + + symbol const get_descendants("get_descendants"); + symbol const descendants("descendants"); + + symbol const get_rev("get_rev"); + symbol const get_full_rev("get_full_rev"); + symbol const get_file_data("get_file_data"); + symbol const get_file_delta("get_file_delta"); + + symbol const rev("rev"); + symbol const full_rev("full_rev"); + symbol const file_data("file_data"); + symbol const file_delta("file_delta"); + } +} + +///////////////////////////////////////////////////////////////////// +// message type 'error' +///////////////////////////////////////////////////////////////////// + +json_value_t +encode_msg_error(string const & note) +{ + json_io::builder b; + b[syms::error].str(note); + return b.v; +} + +bool +decode_msg_error(json_value_t val, + std::string & note) +{ + json_io::query q(val); + note.clear(); + return q[syms::error].get(note); +} + + +///////////////////////////////////////////////////////////////////// +// message type 'inquire' +///////////////////////////////////////////////////////////////////// + +json_value_t +encode_msg_inquire(set const & revs) +{ + json_io::builder b; + b[syms::type].str(syms::inquire()); + b[syms::vers].str("1"); + json_io::builder r = b[syms::revs].arr(); + for (set::const_iterator i = revs.begin(); i != revs.end(); ++i) + r.add_str(i->inner()()); + return b.v; +} + +bool +decode_msg_inquire(json_value_t val, + set & revs) +{ + string type, vers; + json_io::query q(val); + if (q[syms::type].get(type) && + type == syms::inquire() && + q[syms::vers].get(vers) && + vers == "1") + { + size_t nargs = 0; + if (q[syms::revs].len(nargs)) + { + std::string s; + for (size_t i = 0; i < nargs; ++i) + if (q[syms::revs][i].get(s)) + revs.insert(revision_id(s)); + return true; + } + } + return false; +} + + +///////////////////////////////////////////////////////////////////// +// message type 'confirm' +///////////////////////////////////////////////////////////////////// + +json_value_t +encode_msg_confirm(set const & revs) +{ + json_io::builder b; + b[syms::type].str(syms::confirm()); + b[syms::vers].str("1"); + json_io::builder r = b[syms::revs].arr(); + for (set::const_iterator i = revs.begin(); + i != revs.end(); ++i) + { + r.add_str(i->inner()()); + } + return b.v; +} + +bool +decode_msg_confirm(json_value_t val, + set & revs) +{ + string type, vers; + json_io::query q(val); + if (q[syms::type].get(type) && + type == syms::confirm() && + q[syms::vers].get(vers) && + vers == "1") + { + size_t nrevs = 0; + string tmp; + json_io::query r = q[syms::revs]; + if (r.len(nrevs)) + for (size_t i = 0; i < nrevs; ++i) + if (r[i].get(tmp)) + revs.insert(revision_id(tmp)); + return true; + } + return false; +} + +///////////////////////////////////////////////////////////////////// +// message type 'get_descendants' +///////////////////////////////////////////////////////////////////// + +json_value_t +encode_msg_get_descendants(set const & revs); +bool +decode_msg_get_descendants(json_value_t val, + set & revs); + + +///////////////////////////////////////////////////////////////////// +// message type 'descendants' +///////////////////////////////////////////////////////////////////// + +json_value_t +encode_msg_descendants(rev_ancestry_map const & parent_to_child_map); +bool +decode_msg_descendants(json_value_t val, + rev_ancestry_map & parent_to_child_map); + + +///////////////////////////////////////////////////////////////////// +// message type 'rev' +///////////////////////////////////////////////////////////////////// + + +static void +cset_to_json(json_io::builder b, cset const & cs) +{ + for (set::const_iterator i = cs.nodes_deleted.begin(); + i != cs.nodes_deleted.end(); ++i) + { + b.add_obj()[syms::delete_node].str(i->as_internal()); + } + + for (map::const_iterator i = cs.nodes_renamed.begin(); + i != cs.nodes_renamed.end(); ++i) + { + json_io::builder tmp = b.add_obj(); + tmp[syms::rename].str(i->first.as_internal()); + tmp[syms::to].str(i->second.as_internal()); + } + + for (set::const_iterator i = cs.dirs_added.begin(); + i != cs.dirs_added.end(); ++i) + { + b.add_obj()[syms::add_dir].str(i->as_internal()); + } + + for (map::const_iterator i = cs.files_added.begin(); + i != cs.files_added.end(); ++i) + { + json_io::builder tmp = b.add_obj(); + tmp[syms::add_file].str(i->first.as_internal()); + tmp[syms::content].str(i->second.inner()()); + } + + for (map >::const_iterator i = cs.deltas_applied.begin(); + i != cs.deltas_applied.end(); ++i) + { + json_io::builder tmp = b.add_obj(); + tmp[syms::patch].str(i->first.as_internal()); + tmp[syms::from].str(i->second.first.inner()()); + tmp[syms::to].str(i->second.second.inner()()); + } + + for (set >::const_iterator i = cs.attrs_cleared.begin(); + i != cs.attrs_cleared.end(); ++i) + { + json_io::builder tmp = b.add_obj(); + tmp[syms::clear].str(i->first.as_internal()); + tmp[syms::attr].str(i->second()); + } + + for (map, attr_value>::const_iterator i = cs.attrs_set.begin(); + i != cs.attrs_set.end(); ++i) + { + json_io::builder tmp = b.add_obj(); + tmp[syms::set].str(i->first.first.as_internal()); + tmp[syms::attr].str(i->first.second()); + tmp[syms::value].str(i->second()); + } +} + +json_value_t +encode_msg_rev(revision_t const & rev) +{ + json_io::builder b; + b[syms::type].str(syms::rev()); + b[syms::vers].str("1"); + b[syms::new_manifest].str(rev.new_manifest.inner()()); + json_io::builder edges = b[syms::edges].arr(); + for (edge_map::const_iterator e = rev.edges.begin(); + e != rev.edges.end(); ++e) + { + json_io::builder edge = edges.add_obj(); + edge[syms::old_revision].str(edge_old_revision(e).inner()()); + cset_to_json(edge, edge_changes(e)); + } + return b.v; +} + + + + +json_value_t +encode_msg_full_rev(revision_id const & rid, + revision_t const & rev, + set const & deltas, + set const & datas) +{ + json_io::builder b; + b[syms::type].str(syms::full_rev()); + b[syms::vers].str("1"); + json_io::builder rev_builder = b[syms::rev]; + return b.v; +} + +bool +decode_msg_full_rev(json_value_t val, + revision_id & rid, + revision_t & rev, + set & deltas, + set & datas) +{ + json_io::builder b; + b[syms::type].str(syms::full_rev()); + b[syms::vers].str("1"); + b[syms::rev] = encode_msg_rev(rev); + return b.v; +} + + + + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- json_msgs.hh bec4ebb4a8903ea34c0feb53430b5e6ff0d6b165 +++ json_msgs.hh bec4ebb4a8903ea34c0feb53430b5e6ff0d6b165 @@ -0,0 +1,101 @@ +#ifndef __JSON_MSGS_HH__ +#define __JSON_MSGS_HH__ + +// Copyright (C) 2008 Graydon Hoare +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +// This file holds all the JSON message structuring and destructuring +// facilities. It's used by the client and server sides of any +// JSON-speaking bulk I/O interface, to avoid cluttering them up and +// ensure that both sides of an interface make common assumptions +// about message structure. + +#include "base.hh" +#include "graph.hh" +#include "json_io.hh" +#include "revision.hh" +#include "vocab.hh" + +json_io::json_value_t encode_msg_error(std::string const & note); +bool decode_msg_error(json_io::json_value_t val, std::string & note); + +json_io::json_value_t encode_msg_inquire(std::set const & revs); +bool decode_msg_inquire(json_io::json_value_t val, + std::set & revs); + +json_io::json_value_t encode_msg_confirm(std::set const & revs); +bool decode_msg_confirm(json_io::json_value_t val, + std::set & revs); + +json_io::json_value_t encode_msg_get_descendants(std::set const & start); +bool decode_msg_get_descendants(json_io::json_value_t val, + std::set & start); + +json_io::json_value_t encode_msg_descendants(rev_ancestry_map const & parent_to_child_map); +bool decode_msg_descendants(json_io::json_value_t val, + rev_ancestry_map & parent_to_child_map); + +json_io::json_value_t encode_msg_get_file_data(file_id const & fid); +bool decode_msg_get_file_data(json_io::json_value_t val, file_id & fid); + +json_io::json_value_t encode_msg_get_file_delta(file_id const & src_id, + file_id const & dst_id); +bool decode_msg_get_file_delta(json_io::json_value_t val, + file_id & src_id, + file_id & dst_id); + +json_io::json_value_t encode_msg_get_rev(revision_id const & rid); +bool decode_msg_get_rev(json_io::json_value_t val, revision_id & rid); + +json_io::json_value_t encode_msg_get_full_rev(revision_id const & rid); +bool decode_msg_get_full_rev(json_io::json_value_t val, revision_id & rid); + +struct +file_delta_record +{ + file_id src; + file_id dst; + file_delta del; +}; + +struct +file_data_record +{ + file_id id; + file_data dat; +}; + +json_io::json_value_t encode_msg_file_data(file_data_record const & fr); +bool decode_msg_file_data(json_io::json_value_t val, file_data_record & fr); + +json_io::json_value_t encode_msg_file_delta(file_delta_record const & fr); +bool decode_msg_file_delta(json_io::json_value_t val, file_delta_record & fr); + +json_io::json_value_t encode_msg_rev(revision_t const & rev); +bool decode_msg_rev(json_io::json_value_t val, revision_t & rev); + +json_io::json_value_t encode_msg_full_rev(revision_id const & rid, + revision_t const & rev, + std::set const & deltas, + std::set const & datas); +bool decode_msg_full_rev(json_io::json_value_t val, + revision_id & rid, + revision_t & rev, + std::set & deltas, + std::set & datas); + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: + +#endif // __JSON_MSGS_HH__ ============================================================ --- Makefile.am 6f447accf75920caed5092841638835d59a429d9 +++ Makefile.am 6c2d4e6faff8812b27176ce16ec35244653b4420 @@ -20,7 +20,7 @@ LUAEXT_SOURCES = \ luaext_guess_binary.cc luaext_platform.cc luaext_globish.cc \ lua.cc lua.hh mkstemp.cc mkstemp.hh file_io.cc file_io.hh \ globish.cc globish.hh basic_io.cc basic_io.hh json_io.cc \ - json_io.hh + json_io.hh json_msgs.cc json_msgs.hh MOST_SOURCES = \ $(SANITY_CORE_SOURCES) $(LUAEXT_SOURCES) platform-wrapped.hh \ ============================================================ --- cmd_scgi.cc 18ff8d191dfc47514b90fd910d811a25284b0266 +++ cmd_scgi.cc 4b111b0c791f43e187fc457fd3dfe82ce75922de @@ -17,6 +17,7 @@ #include "constants.hh" #include "globish.hh" #include "json_io.hh" +#include "json_msgs.hh" #include "keys.hh" #include "lexical_cast.hh" #include "lua.hh" @@ -145,85 +146,25 @@ parse_scgi(istream & in, string & data) return (content_length == 0); } -namespace syms -{ - symbol const status("status"); - symbol const vers("vers"); - symbol const cmd("cmd"); - symbol const args("args"); - symbol const inquire("inquire"); - symbol const confirm("confirm"); - symbol const revs("revs"); - symbol const type("type"); -}; - -static json_io::json_object_t -bad_req() -{ - json_io::builder b; - - b[syms::status].str("bad"); - - return b.as_obj(); -} - -static json_io::json_object_t +static json_io::json_value_t do_cmd(app_state & app, json_io::json_object_t cmd_obj) { + set revs; - string type, vers; - json_io::query q(cmd_obj); - - if (! q[syms::type].get(type)) - return bad_req(); - - L(FL("read JSON command type: %s") % type); - - if (type == "ping" && - q[syms::vers].get(vers) && - vers == "1") + if (decode_msg_inquire(cmd_obj, revs)) { - json_io::builder b; - json_io::builder args = b[syms::args].arr(); - - size_t nargs = 0; - if (q[syms::args].len(nargs)) - { - for (size_t i = 0; i < nargs; ++i) - args.add(q[syms::args][i].get()); - } - return b.as_obj(); + app.db.ensure_open(); + set confirmed; + for (set::const_iterator i = revs.begin(); + i != revs.end(); ++i) + if (app.db.revision_exists(*i)) + confirmed.insert(*i); + return encode_msg_confirm(confirmed); } - else if (type == syms::inquire() && - q[syms::vers].get(vers) && - vers == "1") - { - json_io::builder b; - b[syms::type].str(syms::confirm()); - b[syms::vers].str("1"); - json_io::builder revs = b[syms::revs].arr(); - - size_t nargs = 0; - if (q[syms::revs].len(nargs)) - { - app.db.ensure_open(); - std::string s; - for (size_t i = 0; i < nargs; ++i) - { - if (q[syms::revs][i].get(s)) - { - if (app.db.revision_exists(revision_id(s))) - revs.add_str(s); - } - } - } - return b.as_obj(); - } else { - return bad_req(); + return encode_msg_error("request not understood"); } - return cmd_obj; } @@ -247,7 +188,7 @@ process_scgi_transaction(app_state & app transaction_guard guard(app.db); L(FL("read JSON object")); - json_io::json_object_t res = do_cmd(app, obj); + json_io::json_value_t res = do_cmd(app, obj); if (static_cast(res)) { json_io::printer out_data; @@ -259,7 +200,7 @@ process_scgi_transaction(app_state & app << "Content-Type: application/jsonrequest\r\n" << "\r\n"; - out.write(out_data.buf.data(), out_data.buf.size()); + out.write(out_data.buf.data(), out_data.buf.size()); out << "\n"; out.flush(); return; ============================================================ --- gsync.cc 5a5e7367916f54b940c3ff3db7f5e55da0c43a52 +++ gsync.cc aa2d92f5428843bfd168e7d1e3832a8f7f95907d @@ -19,6 +19,7 @@ #include "globish.hh" #include "http_client.hh" #include "json_io.hh" +#include "json_msgs.hh" #include "revision.hh" #include "sanity.hh" #include "lexical_cast.hh" @@ -84,121 +85,6 @@ using boost::lexical_cast; using boost::lexical_cast; ///////////////////////////////////////////////////////////////////// -// monotone <-> json conversions -///////////////////////////////////////////////////////////////////// - - -namespace -{ - namespace syms - { - // cset symbols - symbol const delete_node("delete"); - symbol const rename("rename"); - symbol const content("content"); - symbol const add_file("add_file"); - symbol const add_dir("add_dir"); - symbol const patch("patch"); - symbol const from("from"); - symbol const to("to"); - symbol const clear("clear"); - symbol const set("set"); - symbol const attr("attr"); - symbol const value("value"); - - // revision symbols - symbol const old_revision("old_revision"); - symbol const new_manifest("new_manifest"); - symbol const edges("edges"); - - // command symbols - symbol const type("type"); - symbol const vers("vers"); - symbol const revision("revision"); - symbol const inquire("inquire"); - symbol const confirm("confirm"); - symbol const revs("revs"); - - } -} - -static void -cset_to_json(json_io::builder b, cset const & cs) -{ - for (set::const_iterator i = cs.nodes_deleted.begin(); - i != cs.nodes_deleted.end(); ++i) - { - b.add_obj()[syms::delete_node].str(i->as_internal()); - } - - for (map::const_iterator i = cs.nodes_renamed.begin(); - i != cs.nodes_renamed.end(); ++i) - { - json_io::builder tmp = b.add_obj(); - tmp[syms::rename].str(i->first.as_internal()); - tmp[syms::to].str(i->second.as_internal()); - } - - for (set::const_iterator i = cs.dirs_added.begin(); - i != cs.dirs_added.end(); ++i) - { - b.add_obj()[syms::add_dir].str(i->as_internal()); - } - - for (map::const_iterator i = cs.files_added.begin(); - i != cs.files_added.end(); ++i) - { - json_io::builder tmp = b.add_obj(); - tmp[syms::add_file].str(i->first.as_internal()); - tmp[syms::content].str(i->second.inner()()); - } - - for (map >::const_iterator i = cs.deltas_applied.begin(); - i != cs.deltas_applied.end(); ++i) - { - json_io::builder tmp = b.add_obj(); - tmp[syms::patch].str(i->first.as_internal()); - tmp[syms::from].str(i->second.first.inner()()); - tmp[syms::to].str(i->second.second.inner()()); - } - - for (set >::const_iterator i = cs.attrs_cleared.begin(); - i != cs.attrs_cleared.end(); ++i) - { - json_io::builder tmp = b.add_obj(); - tmp[syms::clear].str(i->first.as_internal()); - tmp[syms::attr].str(i->second()); - } - - for (map, attr_value>::const_iterator i = cs.attrs_set.begin(); - i != cs.attrs_set.end(); ++i) - { - json_io::builder tmp = b.add_obj(); - tmp[syms::set].str(i->first.first.as_internal()); - tmp[syms::attr].str(i->first.second()); - tmp[syms::value].str(i->second()); - } -} - -static json_value_t -revision_to_json(revision_t const & rev) -{ - json_io::builder b; - b[syms::type].str(syms::revision()); - b[syms::vers].str("1"); - b[syms::new_manifest].str(rev.new_manifest.inner()()); - json_io::builder edges = b[syms::edges].arr(); - for (edge_map::const_iterator e = rev.edges.begin(); - e != rev.edges.end(); ++e) - { - json_io::builder edge = edges.add_obj(); - edge[syms::old_revision].str(edge_old_revision(e).inner()()); - cset_to_json(edge, edge_changes(e)); - } - return b.v; -} - -///////////////////////////////////////////////////////////////////// // core logic of gsync algorithm ///////////////////////////////////////////////////////////////////// @@ -226,34 +112,11 @@ inquire_about_revs(http_client & h, set const & query_set, set & theirs) { - theirs.clear(); - - json_io::builder b; - b[syms::type].str(syms::inquire()); - b[syms::vers].str("1"); - json_io::builder revs = b[syms::revs].arr(); - for (set::const_iterator i = query_set.begin(); - i != query_set.end(); ++i) - revs.add_str(i->inner()()); - - json_value_t response = h.transact_json(b.v); - - string type, vers; - json_io::query q(response); - - if (q[syms::type].get(type) && - type == syms::confirm() && - q[syms::vers].get(vers) && - vers == "1") - { - size_t nrevs = 0; - string tmp; - json_io::query revs = q[syms::revs]; - if (revs.len(nrevs)) - for (size_t i = 0; i < nrevs; ++i) - if (revs[i].get(tmp)) - theirs.insert(revision_id(tmp)); - } + theirs.clear(); + json_value_t query = encode_msg_inquire(query_set); + json_value_t response = h.transact_json(query); + E(decode_msg_confirm(response, theirs), + F("received unexpected reply to 'inquire' message")); } static void ============================================================ --- http_client.cc 04067dcf693ff4f61072c778668e58c69d728fe6 +++ http_client.cc 01ad87bb1795c9e9c66a9c6f108671fb6eb2eaff @@ -172,7 +172,7 @@ http_client::parse_http_response(std::st while (io->good() && content_length > 0) { - data += static_cast(io->get()); + data += static_cast(io->get());; content_length--; }