api.py 15 KB

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