chiark / gitweb /
bundles: Initial list-bundles
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 2 May 2021 01:03:03 +0000 (02:03 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 2 May 2021 01:03:03 +0000 (02:03 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/cmdlistener.rs
src/bin/otter.rs
src/bundles.rs
src/commands.rs
src/mgmtchannel.rs

index b437201d652e4a07f5d7b6a152ec73d1d3ce1def..5873b979dff43a9a907f67c0cc17cffcb3dade70 100644 (file)
@@ -62,6 +62,13 @@ enum PermissionCheckHow {
 
 type PCH = PermissionCheckHow;
 
+pub const TP_ACCESS_BUNDLES: &[TP] = &[
+  TP::ViewNotSecret,
+  TP::Play,
+  TP::ChangePieces,
+  TP::UploadBundles,
+];
+
 // ========== management API ==========
 
 // ---------- management command implementations
@@ -235,6 +242,16 @@ fn execute_and_respond<R,W>(cs: &mut CommandStreamData, cmd: MgmtCommand,
       };
       Fine
     }
+    MC::ListBundles { game } => {
+      let ag = AccountsGuard::lock();
+      let gref = Instance::lookup_by_name_unauth(&game)?;
+      let bundles = gref.lock_bundles();
+      let mut igu = gref.lock()?;
+      let (_ig, auth) = cs.check_acl(&ag, &mut igu, PCH::Instance,
+                                    TP_ACCESS_BUNDLES)?;
+      let bundles = bundles.by(auth);
+      MR::Bundles(bundles.list())
+    }
 
     MC::ListGames { all } => {
       let ag = AccountsGuard::lock();
index 48907cea0548f55537756df88696a24eba6756e5..f27fc961f4fe046ba5a130701ddabd3f459b155c 100644 (file)
@@ -1362,6 +1362,47 @@ mod upload_bundle {
   )}
 }
 
+//---------- list-bundle ----------
+
+mod list_bundles {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    table_name: String,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.table_name).required()
+      .add_argument("TABLE-NAME",Store,"table name");
+    ap
+  }
+
+  #[throws(AE)]
+  fn call(_sc: &Subcommand, ma: MainOpts, args: Vec<String>) {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let instance_name = ma.instance_name(&args.table_name);
+    let mut chan = access_game(&ma, &args.table_name)?;
+    let resp = chan.cmd(&MC::ListBundles {
+      game: instance_name.clone(),
+    })?;
+    if_let!{ MR::Bundles(bundles) = resp;
+             else throw!(anyhow!("unexpected {:?}", &resp)) };
+    for (index, note) in bundles.into_iter().enumerate() {
+      if_let!{ Some(note) = note; else continue; }
+      println!("{:05} {:?}", index, &note);
+    }
+  }
+
+  inventory::submit!{Subcommand(
+    "list-bundles",
+    "List bundles",
+    call,
+  )}
+}
+
 //---------- list-accounts ----------
 
 mod list_accounts {
index 0739692eb5a91a53131633ac56474596db163a0b..9e86f35b2aa584dd9a8e4c4dfb55ef795305a66b 100644 (file)
@@ -31,23 +31,25 @@ pub struct InstanceBundles {
   bundles: Vec<Option<Note>>,
 }
 
-#[derive(Debug,Clone)]
-struct Note {
-  kind: Kind,
-  state: State,
+pub type MgmtList = Vec<Option<Note>>;
+
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct Note {
+  pub kind: Kind,
+  pub state: State,
 }
 
 type BadBundle = String; // todo: make this a newtype
 
-#[derive(Debug,Clone)]
-enum State {
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub enum State {
   Uploading,
   BadBundle(BadBundle),
   Loaded(Loaded),
 }
 
-#[derive(Debug,Clone)]
-struct Loaded {
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct Loaded {
   meta: BundleMeta,
 }
 
@@ -147,6 +149,8 @@ fn incorporate_bundle(ib: &mut InstanceBundles, ig: &mut Instance,
 impl InstanceBundles {
   pub fn new() -> Self { InstanceBundles{ bundles: default() } }
 
+  pub fn list(&self) -> MgmtList { self.bundles.clone() }
+
   #[throws(IE)]
   pub fn load_game_bundles(ig: &mut Instance) -> Self {
     let bd = b_dir(&ig.name);
index 2d06892e5c81368b60e70cda1db3c787ab30de1b..6f1205eea0e77c00fcd36fc0cd8a179080b9824e 100644 (file)
@@ -46,10 +46,10 @@ pub enum MgmtCommand {
     hash: bundles::Hash,
     kind: bundles::Kind,
   },
-  /*
   ListBundles {
     game: InstanceName,
   },
+  /*
   DownloadBundle {
     game: InstanceName,
     index: bundles::Index,
@@ -92,6 +92,7 @@ pub enum MgmtResponse {
   AccountsList(Vec<Arc<AccountName>>),
   GamesList(Vec<Arc<InstanceName>>),
   LibraryItems(Vec<shapelib::ItemEnquiryData>),
+  Bundles(bundles::MgmtList),
 }
 
 #[derive(Debug,Serialize,Deserialize)]
index 04e7474a3582cd76c3dd5c8035f9437acb10017a..58a890ead9f60dee8b7b751b9dad22b4d98c0508 100644 (file)
@@ -80,7 +80,8 @@ impl MgmtChannel {
     wbulk.finish().context("finish sending command and data")?;
     let (resp, mut rbulk)= self.read.read_withbulk().context("read response")?;
     match &resp {
-      Fine | AccountsList{..} | GamesList{..} | LibraryItems(_) => { },
+      Fine | AccountsList{..} | GamesList{..} |
+      LibraryItems(_) | Bundles(..) => { },
       AlterGame { error: None, .. } => { },
       Error { error } => {
         Err(error.clone()).context(