api.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. import zmq
  2. from . import serial
  3. from . import exc
  4. class Command:
  5. HELLO = 0
  6. ADD_NODE = 1
  7. REMOVE_NODE = 9
  8. RENAME_NODE = 23
  9. SCAN_DANGLING = 24
  10. LOOKUP_NODE_ID = 12
  11. ADD_PROPERTY = 11
  12. LINK_NODE = 2
  13. UNLINK_NODE = 8
  14. GET_INFO = 19
  15. GET_CHILDREN = 4
  16. GET_PARENTS = 5
  17. GET_PROPERTIES = 3
  18. GET_PROPERTY = 6
  19. SET_PROPERTY = 7
  20. GET_SIGNALS = 14
  21. REGISTER_SLOT = 15
  22. UNREGISTER_SLOT = 16
  23. LOOKUP_SLOT_ID = 17
  24. GET_SLOTS = 18
  25. GET_METHODS = 20
  26. GET_METHOD = 21
  27. CALL_METHOD = 22
  28. class SceneNodeType:
  29. NULL = 0
  30. ROOT = 1
  31. WINDOW = 2
  32. WINDOW_INPUT = 6
  33. KEYBOARD = 7
  34. MOUSE = 8
  35. RENDER_LAYER = 3
  36. RENDER_OBJECT = 4
  37. RENDER_MESH = 5
  38. RENDER_TEXT = 9
  39. RENDER_TEXTURE = 13
  40. FONTS = 10
  41. FONT = 11
  42. LINE_POSITION = 12
  43. class PropertyType:
  44. NULL = 0
  45. BUFFER = 1
  46. BOOL = 2
  47. UINT32 = 3
  48. FLOAT32 = 4
  49. STR = 5
  50. SCENE_NODE_ID = 6
  51. @staticmethod
  52. def to_str(prop_type):
  53. match prop_type:
  54. case PropertyType.NULL:
  55. return "null"
  56. case PropertyType.BUFFER:
  57. return "buffer"
  58. case PropertyType.BOOL:
  59. return "bool"
  60. case PropertyType.UINT32:
  61. return "uint32"
  62. case PropertyType.FLOAT32:
  63. return "float32"
  64. case PropertyType.STR:
  65. return "str"
  66. case PropertyType.SCENE_NODE_ID:
  67. return "scene_node_id"
  68. class ErrorCode:
  69. INVALID_SCENE_PATH = 2
  70. NODE_NOT_FOUND = 3
  71. CHILD_NODE_NOT_FOUND = 4
  72. PARENT_NODE_NOT_FOUND = 5
  73. PROPERTY_ALREADY_EXISTS = 6
  74. PROPERTY_NOT_FOUND = 7
  75. PROPERTY_WRONG_TYPE = 8
  76. SIGNAL_ALREADY_EXISTS = 9
  77. SIGNAL_NOT_FOUND = 10
  78. SLOT_NOT_FOUND = 11
  79. METHOD_NOT_FOUND = 12
  80. NODES_ARE_LINKED = 13
  81. NODES_NOT_LINKED = 14
  82. NODE_HAS_PARENTS = 15
  83. NODE_HAS_CHILDREN = 16
  84. NODE_PARENT_NAME_CONFLICT = 17
  85. NODE_CHILD_NAME_CONFLICT = 18
  86. NODE_SIBLING_NAME_CONFLICT = 19
  87. FILE_NOT_FOUND = 20
  88. @staticmethod
  89. def to_str(errc):
  90. match errc:
  91. case ErrorCode.INVALID_SCENE_PATH:
  92. return "invalid_scene_path"
  93. case ErrorCode.NODE_NOT_FOUND:
  94. return "node_not_found"
  95. case ErrorCode.CHILD_NODE_NOT_FOUND:
  96. return "child_node_not_found"
  97. case ErrorCode.PARENT_NODE_NOT_FOUND:
  98. return "parent_node_not_found"
  99. case ErrorCode.PROPERTY_ALREADY_EXISTS:
  100. return "property_already_exists"
  101. case ErrorCode.PROPERTY_NOT_FOUND:
  102. return "property_not_found"
  103. case ErrorCode.PROPERTY_WRONG_TYPE:
  104. return "property_wrong_type"
  105. case ErrorCode.SIGNAL_ALREADY_EXISTS:
  106. return "signal_already_exists"
  107. case ErrorCode.SIGNAL_NOT_FOUND:
  108. return "signal_not_found "
  109. case ErrorCode.SLOT_NOT_FOUND:
  110. return "slot_not_found "
  111. case ErrorCode.METHOD_NOT_FOUND:
  112. return "method_not_found "
  113. case ErrorCode.NODES_ARE_LINKED:
  114. return "nodes_are_linked "
  115. case ErrorCode.NODES_NOT_LINKED:
  116. return "nodes_not_linked "
  117. case ErrorCode.NODE_HAS_PARENTS:
  118. return "node_has_parents "
  119. case ErrorCode.NODE_HAS_CHILDREN:
  120. return "node_has_children "
  121. case ErrorCode.NODE_PARENT_NAME_CONFLICT:
  122. return "node_parent_name_conflict "
  123. case ErrorCode.NODE_CHILD_NAME_CONFLICT:
  124. return "node_child_name_conflict "
  125. case ErrorCode.NODE_SIBLING_NAME_CONFLICT:
  126. return "node_sibling_name_conflict "
  127. case ErrorCode.FILE_NOT_FOUND:
  128. return "file_not_found"
  129. def vertex(x, y, r, g, b, a, u, v):
  130. buf = bytearray()
  131. serial.write_f32(buf, x)
  132. serial.write_f32(buf, y)
  133. serial.write_f32(buf, r)
  134. serial.write_f32(buf, g)
  135. serial.write_f32(buf, b)
  136. serial.write_f32(buf, a)
  137. serial.write_f32(buf, u)
  138. serial.write_f32(buf, v)
  139. return buf
  140. def face(idx1, idx2, idx3):
  141. buf = bytearray()
  142. serial.write_u32(buf, idx1)
  143. serial.write_u32(buf, idx2)
  144. serial.write_u32(buf, idx3)
  145. return buf
  146. class Api:
  147. def __init__(self, addr="[::1]", port=9484):
  148. context = zmq.Context()
  149. self.socket = context.socket(zmq.REQ)
  150. self.socket.setsockopt(zmq.IPV6, True)
  151. self.socket.connect(f"tcp://{addr}:{port}")
  152. def _make_request(self, cmd, payload):
  153. req_cmd = bytearray()
  154. serial.write_u8(req_cmd, cmd)
  155. self.socket.send_multipart([req_cmd, payload])
  156. errc, reply = self.socket.recv_multipart()
  157. errc = int.from_bytes(errc, "little")
  158. cursor = serial.Cursor(reply)
  159. match errc:
  160. case 2:
  161. raise exc.RequestInvalidScenePath
  162. case 3:
  163. raise exc.RequestNodeNotFound
  164. case 4:
  165. raise exc.RequestChildNodeNotFound
  166. case 5:
  167. raise exc.RequestParentNodeNotFound
  168. case 6:
  169. raise exc.RequestPropertyAlreadyExists
  170. case 7:
  171. raise exc.RequestPropertyNotFound
  172. case 8:
  173. raise exc.RequestPropertyWrongType
  174. case 9:
  175. raise exc.RequestSignalAlreadyExists
  176. case 10:
  177. raise exc.RequestSignalNotFound
  178. case 11:
  179. raise exc.RequestSlotNotFound
  180. case 12:
  181. raise exc.RequestMethodNotFound
  182. case 13:
  183. raise exc.RequestNodesAreLinked
  184. case 14:
  185. raise exc.RequestNodesNotLinked
  186. case 15:
  187. raise exc.RequestNodeHasParents
  188. case 16:
  189. raise exc.RequestNodeHasChildren
  190. case 17:
  191. raise exc.RequestNodeParentNameConflict
  192. case 18:
  193. raise exc.RequestNodeChildNameConflict
  194. case 19:
  195. raise exc.RequestNodeSiblingNameConflict
  196. case 20:
  197. raise exc.RequestFileNotFound
  198. return cursor
  199. def hello(self):
  200. response = self._make_request(Command.HELLO, bytearray())
  201. return serial.decode_str(response)
  202. def get_info(self, node_id):
  203. req = bytearray()
  204. serial.write_u32(req, node_id)
  205. cur = self._make_request(Command.GET_INFO, req)
  206. name = serial.decode_str(cur)
  207. type = serial.read_u8(cur)
  208. return (name, type)
  209. def get_children(self, node_id):
  210. req = bytearray()
  211. serial.write_u32(req, node_id)
  212. cur = self._make_request(Command.GET_CHILDREN, req)
  213. children_len = serial.decode_varint(cur)
  214. children = []
  215. for _ in range(children_len):
  216. child_name = serial.decode_str(cur)
  217. child_id = serial.read_u32(cur)
  218. child_type = serial.read_u8(cur)
  219. children.append((child_name, child_id, child_type))
  220. return children
  221. def get_parents(self, node_id):
  222. req = bytearray()
  223. serial.write_u32(req, node_id)
  224. cur = self._make_request(Command.GET_PARENTS, req)
  225. parents_len = serial.decode_varint(cur)
  226. parents = []
  227. for _ in range(parents_len):
  228. parent_name = serial.decode_str(cur)
  229. parent_id = serial.read_u32(cur)
  230. parent_type = serial.read_u8(cur)
  231. parents.append((parent_name, parent_id, parent_type))
  232. return parents
  233. def get_properties(self, node_id):
  234. req = bytearray()
  235. serial.write_u32(req, node_id)
  236. cur = self._make_request(Command.GET_PROPERTIES, req)
  237. props_len = serial.decode_varint(cur)
  238. props = []
  239. for _ in range(props_len):
  240. prop_name = serial.decode_str(cur)
  241. prop_type = serial.read_u8(cur)
  242. props.append((prop_name, prop_type))
  243. return props
  244. def get_property(self, node_id, prop_name):
  245. req = bytearray()
  246. serial.write_u32(req, node_id)
  247. serial.encode_str(req, prop_name)
  248. cur = self._make_request(Command.GET_PROPERTY, req)
  249. prop_type = serial.read_u8(cur)
  250. match prop_type:
  251. case 0:
  252. return None
  253. case 1:
  254. return []
  255. case 3:
  256. val = serial.read_u8(cur)
  257. return bool(val)
  258. case 2:
  259. return serial.read_u32(cur)
  260. case 4:
  261. return serial.read_f32(cur)
  262. case 5:
  263. return serial.decode_str(cur)
  264. raise Exception("unknown property type returned")
  265. def add_node(self, node_name, node_type):
  266. req = bytearray()
  267. serial.encode_str(req, node_name)
  268. serial.write_u8(req, int(node_type))
  269. cur = self._make_request(Command.ADD_NODE, req)
  270. node_id = serial.read_u32(cur)
  271. return node_id
  272. def remove_node(self, node_id):
  273. req = bytearray()
  274. serial.write_u32(req, node_id)
  275. self._make_request(Command.REMOVE_NODE, req)
  276. def rename_node(self, node_id, node_name):
  277. req = bytearray()
  278. serial.write_u32(req, node_id)
  279. serial.encode_str(req, node_name)
  280. self._make_request(Command.RENAME_NODE, req)
  281. def scan_dangling(self):
  282. cur = self._make_request(Command.SCAN_DANGLING, bytearray())
  283. dangling_len = serial.decode_varint(cur)
  284. dangling = []
  285. for _ in range(dangling_len):
  286. node_id = serial.read_u32(cur)
  287. dangling.append(node_id)
  288. return dangling
  289. def lookup_node_id(self, node_path):
  290. req = bytearray()
  291. serial.encode_str(req, node_path)
  292. try:
  293. cur = self._make_request(Command.LOOKUP_NODE_ID, req)
  294. except exc.RequestNodeNotFound:
  295. return None
  296. return serial.read_u32(cur)
  297. def add_property(self, node_id, prop_name, prop_type):
  298. req = bytearray()
  299. serial.write_u32(req, node_id)
  300. serial.encode_str(req, prop_name)
  301. serial.write_u8(req, int(prop_type))
  302. self._make_request(Command.ADD_PROPERTY, req)
  303. def link_node(self, child_id, parent_id):
  304. req = bytearray()
  305. serial.write_u32(req, child_id)
  306. serial.write_u32(req, parent_id)
  307. self._make_request(Command.LINK_NODE, req)
  308. def unlink_node(self, child_id, parent_id):
  309. req = bytearray()
  310. serial.write_u32(req, child_id)
  311. serial.write_u32(req, parent_id)
  312. self._make_request(Command.UNLINK_NODE, req)
  313. def set_property_bool(self, node_id, prop_name, val):
  314. req = bytearray()
  315. serial.write_u32(req, node_id)
  316. serial.encode_str(req, prop_name)
  317. serial.write_u8(req, int(val))
  318. self._make_request(Command.SET_PROPERTY, req)
  319. def set_property_u32(self, node_id, prop_name, val):
  320. req = bytearray()
  321. serial.write_u32(req, node_id)
  322. serial.encode_str(req, prop_name)
  323. serial.write_u32(req, val)
  324. self._make_request(Command.SET_PROPERTY, req)
  325. def set_property_f32(self, node_id, prop_name, val):
  326. req = bytearray()
  327. serial.write_u32(req, node_id)
  328. serial.encode_str(req, prop_name)
  329. serial.write_f32(req, val)
  330. self._make_request(Command.SET_PROPERTY, req)
  331. def set_property_buffer(self, node_id, prop_name, buf):
  332. req = bytearray()
  333. serial.write_u32(req, node_id)
  334. serial.encode_str(req, prop_name)
  335. serial.encode_buf(req, buf)
  336. self._make_request(Command.SET_PROPERTY, req)
  337. def set_property_str(self, node_id, prop_name, val):
  338. req = bytearray()
  339. serial.write_u32(req, node_id)
  340. serial.encode_str(req, prop_name)
  341. serial.encode_str(req, val)
  342. self._make_request(Command.SET_PROPERTY, req)
  343. def get_signals(self, node_id):
  344. req = bytearray()
  345. serial.write_u32(req, node_id)
  346. cur = self._make_request(Command.GET_SIGNALS, req)
  347. sigs_len = serial.decode_varint(cur)
  348. sigs = []
  349. for _ in range(sigs_len):
  350. sigs.append(serial.decode_str(cur))
  351. return sigs
  352. def register_slot(self, node_id, sig_name, slot_name, user_data):
  353. req = bytearray()
  354. serial.write_u32(req, node_id)
  355. serial.encode_str(req, sig_name)
  356. serial.encode_str(req, slot_name)
  357. serial.encode_varint(req, len(user_data))
  358. req += user_data
  359. cur = self._make_request(Command.REGISTER_SLOT, req)
  360. slot_id = serial.read_u32(cur)
  361. return slot_id
  362. def unregister_slot(self, node_id, sig_name, slot_id):
  363. req = bytearray()
  364. serial.write_u32(req, node_id)
  365. serial.encode_str(req, sig_name)
  366. serial.write_u32(req, slot_id)
  367. self._make_request(Command.UNREGISTER_SLOT, req)
  368. def lookup_slot_id(self, node_id, sig_name, slot_name):
  369. req = bytearray()
  370. serial.write_u32(req, node_id)
  371. serial.encode_str(req, sig_name)
  372. serial.encode_str(req, slot_name)
  373. try:
  374. cur = self._make_request(Command.LOOKUP_SLOT_ID, req)
  375. except exc.RequestSlotNotFound:
  376. return None
  377. return serial.read_u32(cur)
  378. def get_slots(self, node_id, sig_name):
  379. req = bytearray()
  380. serial.write_u32(req, node_id)
  381. serial.encode_str(req, sig_name)
  382. cur = self._make_request(Command.GET_SLOTS, req)
  383. slots_len = serial.decode_varint(cur)
  384. slots = []
  385. for _ in range(slots_len):
  386. slot_name = serial.decode_str(cur)
  387. slot_id = serial.read_u32(cur)
  388. slots.append((slot_id, slot_name))
  389. return slots
  390. def get_methods(self, node_id):
  391. req = bytearray()
  392. serial.write_u32(req, node_id)
  393. cur = self._make_request(Command.GET_METHODS, req)
  394. methods_len = serial.decode_varint(cur)
  395. methods = []
  396. for _ in range(methods_len):
  397. method_name = serial.decode_str(cur)
  398. methods.append(method_name)
  399. return methods
  400. def get_method(self, node_id, method_name):
  401. req = bytearray()
  402. serial.write_u32(req, node_id)
  403. serial.encode_str(req, method_name)
  404. cur = self._make_request(Command.GET_METHOD, req)
  405. args_len = serial.decode_varint(cur)
  406. args = []
  407. for _ in range(args_len):
  408. arg_name = serial.decode_str(cur)
  409. arg_type = serial.read_u8(cur)
  410. args.append((arg_name, arg_type))
  411. results_len = serial.decode_varint(cur)
  412. results = []
  413. for _ in range(results_len):
  414. result_name = serial.decode_str(cur)
  415. result_type = serial.read_u8(cur)
  416. results.append((result_name, result_type))
  417. return (args, results)
  418. def call_method(self, node_id, method_name, arg_data):
  419. req = bytearray()
  420. serial.write_u32(req, node_id)
  421. serial.encode_str(req, method_name)
  422. serial.encode_buf(req, arg_data)
  423. cur = self._make_request(Command.CALL_METHOD, req)
  424. errc = serial.read_u8(cur)
  425. result = serial.decode_buf(cur)
  426. return (errc, result)