ソースを参照

wallet: update python API for new property system rewrite

rsx 2 年 前
コミット
8332a3648c

+ 27 - 12
bin/darkwallet/gui/__init__.py

@@ -271,18 +271,33 @@ def resize_rounded_box():
     #api.set_property_buffer(mesh_id, "faces", face(0, 2, 1) + face(1, 2, 3))
 
 def main():
-    node_id = api.add_node("foo", SceneNodeType.WINDOW)
-    prop = Property(
-        "myprop", PropertyType.FLOAT32, PropertySubType.NULL,
-        None,
-        "myprop", "",
-        False, 2, None, None, []
-    )
-    api.add_property(1, prop)
-    api.link_node(node_id, 0)
-    api.set_property_f32(1, "myprop", 0, 4.0)
-    api.set_property_f32(1, "myprop", 1, 110.0)
-    print(api.get_property_value(1, "myprop"))
+    if True:
+        node_id = api.add_node("foo", SceneNodeType.WINDOW)
+        prop = Property(
+            "myprop", PropertyType.FLOAT32, PropertySubType.NULL,
+            None,
+            "myprop", "",
+            False, 2, None, None, []
+        )
+        api.add_property(1, prop)
+        api.link_node(node_id, 0)
+        api.set_property_f32(1, "myprop", 0, 4.0)
+        api.set_property_f32(1, "myprop", 1, 110.0)
+    print("val =", api.get_property_value(1, "myprop"))
+    for prop in api.get_properties(1):
+        print("Property:")
+        print(f"  name = {prop.name}")
+        print(f"  type = {prop.type}")
+        print(f"  subtype = {prop.subtype}")
+        print(f"  defaults = {prop.defaults}")
+        print(f"  ui_name = {prop.ui_name}")
+        print(f"  desc = {prop.desc}")
+        print(f"  is_null_allowed = {prop.is_null_allowed}")
+        print(f"  array_len = {prop.array_len}")
+        print(f"  min_val = {prop.min_val}")
+        print(f"  max_val = {prop.max_val}")
+        print(f"  enum_items = {prop.enum_items}")
+        print()
     print_tree()
     #garbage_collect()
 

+ 57 - 23
bin/darkwallet/pydrk/api.py

@@ -103,6 +103,11 @@ class PropertySubType:
             case PropertySubType.PIXEL:
                 return "pixel"
 
+class PropertyStatus:
+    OK = 0
+    UNSET = 1
+    NULL = 2
+
 class ErrorCode:
     INVALID_SCENE_PATH = 1
     NODE_NOT_FOUND = 2
@@ -321,48 +326,77 @@ class Api:
         cur = self._make_request(Command.GET_PROPERTIES, req)
         props_len = serial.decode_varint(cur)
         props = []
+
+        prop_read_fn = lambda cur: Api.read_prop_val(cur, prop_type)
+        enum_read_fn = lambda cur: serial.decode_arr(cur, serial.decode_str)
+
         for _ in range(props_len):
             prop_name = serial.decode_str(cur)
+            # We need prop_type below
             prop_type = serial.read_u8(cur)
-            props.append((prop_name, prop_type))
+            prop = Property(
+                prop_name,
+                prop_type,
+                # subtype 
+                serial.read_u8(cur),
+                # defaults 
+                serial.decode_arr(cur, prop_read_fn),
+                # ui_name 
+                serial.decode_str(cur),
+                # desc 
+                serial.decode_str(cur),
+                # is_null_allowed 
+                bool(serial.read_u8(cur)),
+                # array_len 
+                serial.read_u32(cur),
+                # min_val 
+                serial.decode_opt(cur, prop_read_fn),
+                # max_val 
+                serial.decode_opt(cur, prop_read_fn),
+                # enum_items 
+                serial.decode_opt(cur, enum_read_fn)
+            )
+            props.append(prop)
         return props
 
-    def get_property_value(self, node_id, prop_name):
-        req = bytearray()
-        serial.write_u32(req, node_id)
-        serial.encode_str(req, prop_name)
-        cur = self._make_request(Command.GET_PROPERTY_VALUE, req)
-        prop_type = serial.read_u8(cur)
-        prop_len = serial.decode_varint(cur)
-        vals = []
-
-        def read_array(read_fn):
-            for _ in range(prop_len):
-                is_some = serial.read_u8(cur)
-                if is_some:
-                    val = read_fn()
-                    vals.append(val)
-
+    @staticmethod
+    def read_prop_val(cur, prop_type):
         match prop_type:
             case PropertyType.NULL:
                 return None
             case PropertyType.BOOL:
-                read_array(lambda: bool(serial.read_u8(cur)))
+                return bool(serial.read_u8(cur))
             case PropertyType.UINT32:
-                read_array(lambda: serial.read_u32(cur))
+                return serial.read_u32(cur)
             case PropertyType.FLOAT32:
-                read_array(lambda: serial.read_f32(cur))
+                return serial.read_f32(cur)
             case PropertyType.STR:
-                read_array(lambda: serial.decode_str(cur))
+                return serial.decode_str(cur)
             case PropertyType.ENUM:
-                read_array(lambda: serial.decode_str(cur))
+                return serial.decode_str(cur)
             case PropertyType.BUFFER:
                 pass
             case PropertyType.SCENE_NODE_ID:
-                read_array(lambda: serial.read_u32(cur))
+                return serial.read_u32(cur)
             case _:
                 raise Exception("unknown property type returned")
 
+    def get_property_value(self, node_id, prop_name):
+        req = bytearray()
+        serial.write_u32(req, node_id)
+        serial.encode_str(req, prop_name)
+        cur = self._make_request(Command.GET_PROPERTY_VALUE, req)
+        prop_type = serial.read_u8(cur)
+
+        def prop_read_fn(cur):
+            prop_status = serial.read_u8(cur)
+            match prop_status:
+                case PropertyStatus.NULL:
+                    return None
+                case PropertyStatus.UNSET | PropertyStatus.OK:
+                    return Api.read_prop_val(cur, prop_type)
+
+        vals = serial.decode_arr(cur, prop_read_fn)
         return vals
 
     def add_node(self, node_name, node_type):

+ 13 - 0
bin/darkwallet/pydrk/serial.py

@@ -109,3 +109,16 @@ def decode_buf(cur):
     size = decode_varint(cur)
     return cur.read(size)
 
+def decode_opt(cur, read_fn):
+    is_some = bool(read_u8(cur))
+    if is_some:
+        return read_fn(cur)
+    else:
+        return None
+
+def decode_arr(cur, read_fn):
+    arr_len = decode_varint(cur)
+    vals = []
+    for _ in range(arr_len):
+        vals.append(read_fn(cur))
+    return vals

+ 23 - 83
bin/darkwallet/src/net.rs

@@ -165,11 +165,20 @@ impl ZeroMQAdapter {
                 debug!(target: "req", "{:?}({})", cmd, node_id);
 
                 let node = scene_graph.get_node(node_id).ok_or(Error::NodeNotFound)?;
-                //let mut props = vec![];
+                VarInt(node.props.len() as u64).encode(&mut reply).unwrap();
                 for prop in &node.props {
-                    //props.push((prop.name.clone(), prop.get_type() as u8));
+                    prop.name.encode(&mut reply).unwrap();
+                    prop.typ.encode(&mut reply).unwrap();
+                    prop.subtype.encode(&mut reply).unwrap();
+                    prop.defaults.encode(&mut reply).unwrap();
+                    prop.ui_name.encode(&mut reply).unwrap();
+                    prop.desc.encode(&mut reply).unwrap();
+                    prop.is_null_allowed.encode(&mut reply).unwrap();
+                    (prop.array_len as u32).encode(&mut reply).unwrap();
+                    prop.min_val.encode(&mut reply).unwrap();
+                    prop.max_val.encode(&mut reply).unwrap();
+                    prop.enum_items.encode(&mut reply).unwrap();
                 }
-                //props.encode(&mut reply).unwrap();
             }
             Command::GetPropertyValue => {
                 let node_id = SceneNodeId::decode(&mut cur).unwrap();
@@ -180,86 +189,17 @@ impl ZeroMQAdapter {
                 let prop = node.get_property(&prop_name).ok_or(Error::PropertyNotFound)?;
                 prop.typ.encode(&mut reply).unwrap();
                 VarInt(prop.get_len() as u64).encode(&mut reply).unwrap();
-                match prop.typ {
-                    PropertyType::Null => {}
-                    PropertyType::Bool => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_bool_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
-                    }
-                    PropertyType::Uint32 => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_u32_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
-                    }
-                    PropertyType::Float32 => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_f32_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
-                    }
-                    PropertyType::Str => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_str_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
-                    }
-                    PropertyType::Enum => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_enum_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
-                    }
-                    PropertyType::Buffer => {}
-                    PropertyType::SceneNodeId => {
-                        for i in 0..prop.get_len() {
-                            match prop.get_node_id_opt(i).unwrap() {
-                                Some(v) => {
-                                    true.encode(&mut reply).unwrap();
-                                    v.encode(&mut reply).unwrap();
-                                }
-                                None => {
-                                    false.encode(&mut reply).unwrap();
-                                }
-                            }
-                        }
+                for i in 0..prop.get_len() {
+                    let val = prop.get_raw_value(i)?;
+                    if val.is_unset() {
+                        1u8.encode(&mut reply).unwrap();
+                        let default = &prop.defaults[i];
+                        default.encode(&mut reply).unwrap();
+                    } else if val.is_null() {
+                        2u8.encode(&mut reply).unwrap();
+                    } else {
+                        0u8.encode(&mut reply).unwrap();
+                        val.encode(&mut reply).unwrap();
                     }
                 }
             }

+ 34 - 16
bin/darkwallet/src/prop.rs

@@ -1,8 +1,9 @@
 use crate::error::{Error, Result};
 use atomic_float::AtomicF32;
-use darkfi_serial::{SerialDecodable, SerialEncodable};
+use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable, WriteExt};
 use std::{
     fmt,
+    io::Write,
     str::FromStr,
     sync::{
         atomic::{AtomicBool, AtomicU32, Ordering},
@@ -81,14 +82,14 @@ impl PropertyValue {
         }
     }
 
-    fn is_unset(&self) -> bool {
+    pub fn is_unset(&self) -> bool {
         match self {
             Self::Unset => true,
             _ => false,
         }
     }
 
-    fn is_null(&self) -> bool {
+    pub fn is_null(&self) -> bool {
         match self {
             Self::Null => true,
             _ => false,
@@ -139,6 +140,23 @@ impl PropertyValue {
     }
 }
 
+impl Encodable for PropertyValue {
+    fn encode<S: Write>(&self, mut s: S) -> std::result::Result<usize, std::io::Error> {
+        match self {
+            Self::Unset | Self::Null | Self::Buffer(_) => {
+                // do nothing
+                Ok(0)
+            }
+            Self::Bool(v) => v.encode(s),
+            Self::Uint32(v) => v.encode(s),
+            Self::Float32(v) => v.encode(s),
+            Self::Str(v) => v.encode(s),
+            Self::Enum(v) => v.encode(s),
+            Self::SceneNodeId(v) => v.encode(s),
+        }
+    }
+}
+
 pub struct Property {
     pub name: String,
     pub typ: PropertyType,
@@ -232,19 +250,6 @@ impl Property {
         Ok(())
     }
 
-    pub fn get_len(&self) -> usize {
-        // Avoid locking unless we need to
-        // If array len is nonzero, then vals len should be the same.
-        if !self.is_bounded() {
-            return self.vals.lock().unwrap().len()
-        }
-        self.array_len
-    }
-
-    fn is_bounded(&self) -> bool {
-        self.array_len != 0
-    }
-
     /// This will clear all values, resetting them to the default
     pub fn clear_values(&self) {
         let vals = &mut self.vals.lock().unwrap();
@@ -391,6 +396,19 @@ impl Property {
 
     // Get
 
+    fn is_bounded(&self) -> bool {
+        self.array_len != 0
+    }
+
+    pub fn get_len(&self) -> usize {
+        // Avoid locking unless we need to
+        // If array len is nonzero, then vals len should be the same.
+        if !self.is_bounded() {
+            return self.vals.lock().unwrap().len()
+        }
+        self.array_len
+    }
+
     pub fn is_unset(&self, i: usize) -> Result<bool> {
         let val = self.get_raw_value(i)?;
         Ok(val.is_unset())