def packages_step() -> RespT: """Step to the next action. --- put: summary: Step to the next action. operationId: StepPackage tags: - Packages responses: 200: description: Ok 400: description: There is no paused package. 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ if not package_paused(): return Response(status=400) resp = call_rpc(rpc.StepAction.Request(id=get_id())) if resp.result: return Response(status=200) else: return jsonify(resp.messages), 500
def packages_resume() -> RespT: """Resumes running package. --- put: summary: Resumes execution of the given package. operationId: ResumePackage tags: - Packages responses: 200: description: Ok 400: description: There is no paused package. 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ if not package_paused(): return Response(status=400) resp = call_rpc(rpc.ResumePackage.Request(id=get_id())) if resp.result: return Response(status=200) else: return jsonify(resp.messages), 500
def package_debug(packageId: str) -> RespT: # noqa """Debug project --- put: summary: Start debugging of the execution package. operationId: DebugPackage tags: - Packages parameters: - in: path name: packageId schema: type: string required: true description: The unique identification of the package. - in: query name: breakOnFirstAction schema: type: boolean default: false description: The project execution is paused before the first Action (default value is false). responses: 200: description: The debugging process successfully started. 400: description: Another package is active (running or paused). 404: description: The package cannot be found. 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ if not package_exists(packageId): return Response(status=404) if package_run_state(): return Response(status=400) resp = call_rpc( rpc.RunPackage.Request( id=get_id(), args=rpc.RunPackage.Request.Args( packageId, request.args.get("breakOnFirstAction", default="false") == "true", breakpoints.get(packageId, None), ), )) if resp.result: return Response(status=200) else: return jsonify(resp.messages), 500
def unlock_object(ars: ARServer, obj_id: str) -> None: assert ars.call_rpc( rpc.lock.WriteUnlock.Request( get_id(), rpc.lock.WriteUnlock.Request.Args(obj_id)), rpc.lock.WriteUnlock.Response) event(ars, events.lk.ObjectsUnlocked)
def lock_object(ars: ARServer, obj_id: str, lock_tree: bool = False) -> None: assert ars.call_rpc( rpc.lock.WriteLock.Request( get_id(), rpc.lock.WriteLock.Request.Args(obj_id, lock_tree)), rpc.lock.WriteLock.Response, ).result event(ars, events.lk.ObjectsLocked)
async def run_temp_package(package_id: str, start_paused: bool = False, breakpoints: Optional[set[str]] = None) -> None: # TODO lock scene and project? assert glob.LOCK.scene assert glob.LOCK.project project_id = glob.LOCK.project.id glob.TEMPORARY_PACKAGE = True scene_online = scene_started() if scene_online: await stop_scene(glob.LOCK.scene) # the package will start it on its own await project.close_project(show_mainscreen_after_that=False) req = erpc.RunPackage.Request exe_req = req(get_id(), args=req.Args(package_id, start_paused, breakpoints)) exe_resp = await manager_request(exe_req) if not exe_resp.result: logger.warning(f"Execution of temporary package failed with: {exe_resp.messages}.") else: await server_events.package_started.wait() await server_events.package_stopped.wait() logger.info("Temporary package stopped, let's remove it and reopen project.") glob.TEMPORARY_PACKAGE = False await manager_request(erpc.DeletePackage.Request(get_id(), args=rpc.common.IdArgs(package_id))) await project.open_project(project_id) assert glob.LOCK.scene assert glob.LOCK.project await notif.broadcast_event( sevts.p.OpenProject(sevts.p.OpenProject.Data(glob.LOCK.scene.scene, glob.LOCK.project.project)) ) if scene_online: await start_scene(glob.LOCK.scene)
def ars() -> Iterator[ARServer]: with ARServer(ars_connection_str(), timeout=30, event_mapping=event_mapping) as ws: test_username = "******" assert ws.call_rpc( rpc.u.RegisterUser.Request( get_id(), rpc.u.RegisterUser.Request.Args(test_username)), rpc.u.RegisterUser.Response, ).result yield ws
def add_logic_item( ars: ARServer, start: str, end: str, condition: Optional[common.ProjectLogicIf] = None) -> common.LogicItem: assert ars.call_rpc( rpc.p.AddLogicItem.Request( get_id(), rpc.p.AddLogicItem.Request.Args(start, end, condition)), rpc.p.AddLogicItem.Response, ).result evt = event(ars, events.p.LogicItemChanged) assert evt.data return evt.data
def package_start(packageId: str) -> RespT: # noqa """Run project --- put: summary: Start execution of the execution package. operationId: StartPackage tags: - Packages parameters: - in: path name: packageId schema: type: string required: true description: Unique package Id responses: 200: description: Ok 400: description: Another package is active (running or paused). 404: description: Package not found 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ if not package_exists(packageId): return Response(status=404) if package_run_state(): return Response(status=400) resp = call_rpc( rpc.RunPackage.Request(id=get_id(), args=rpc.RunPackage.Request.Args(id=packageId))) if resp.result: breakpoints.pop(packageId, None) return Response(status=200) else: return jsonify(resp.messages), 500
def delete_package(packageId: str) -> RespT: # noqa """Delete package. --- delete: summary: Delete package. operationId: DeletePackage tags: - Packages parameters: - in: path name: packageId description: Unique package Id schema: type: string required: true description: unique ID responses: 200: description: Ok 404: description: Package not found 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ if not package_exists(packageId): return Response(status=404) resp = call_rpc( rpc.DeletePackage.Request(id=get_id(), args=arcor2_rpc.common.IdArgs(id=packageId))) if resp.result: breakpoints.pop(packageId, None) return Response(status=200) else: return jsonify(resp.messages), 500
async def build_and_upload_package(project_id: str, package_name: str) -> str: """Builds package and uploads it to the Execution unit. :param project_id: :param package_name: :return: generated package ID. """ package_id = common.uid("pkg") # call build service # TODO store data in memory async with tempfile.TemporaryDirectory() as tmpdirname: path = os.path.join(tmpdirname, "publish.zip") await hlp.run_in_executor( rest.download, f"{BUILD_URL}/project/{project_id}/publish", path, {"packageName": package_name}, ) async with aiofiles.open(path, "rb") as zip_file: b64_bytes = base64.b64encode(await zip_file.read()) b64_str = b64_bytes.decode() # send data to execution service exe_req = erpc.UploadPackage.Request(get_id(), args=erpc.UploadPackage.Request.Args(package_id, b64_str)) exe_resp = await manager_request(exe_req) if not exe_resp.result: if not exe_resp.messages: raise Arcor2Exception("Upload to the Execution unit failed.") raise Arcor2Exception("\n".join(exe_resp.messages)) return package_id
def get_packages() -> RespT: """Gets summary for all stored execution packages. --- get: summary: Gets summary for all stored execution packages. operationId: GetSummaryPackages tags: - Packages responses: 200: description: Summary of all packages on execution service. content: application/json: schema: type: array items: $ref: SummaryPackage """ resp = call_rpc(rpc.ListPackages.Request(id=get_id())) assert isinstance(resp, rpc.ListPackages.Response) ret: list[dict] = [] for pck in resp.data: sp = SummaryPackage(pck.id) sp.name = pck.package_meta.name sp.created = pck.package_meta.built sp.executed = pck.package_meta.executed if pck.project_meta: sp.project = SummaryProject(pck.project_meta.id, pck.project_meta.name, pck.project_meta.description) ret.append(sp.to_dict()) return jsonify(ret), 200
def __init__( self, ws_connection_str: str = "ws://0.0.0.0:6789", timeout: float = 3.0, event_mapping: Optional[dict[str, type[events.Event]]] = None, ): self._ws = websocket.WebSocket() self._logger = get_logger(__name__) self._event_queue: Queue[events.Event] = Queue() if event_mapping is None: event_mapping = {} self.event_mapping = event_mapping start_time = time.monotonic() while time.monotonic() < start_time + timeout: try: self._ws.connect(ws_connection_str) break except ConnectionRefusedError: time.sleep(0.25) if not self._ws.connected: raise ARServerClientException(f"Failed to connect to '{ws_connection_str}'.") self._ws.settimeout(timeout) system_info = self._call_rpc(srpc.c.SystemInfo.Request(get_id()), srpc.c.SystemInfo.Response).data if system_info is None: raise ARServerClientException("Failed to get SystemInfo.") self._logger.info(f"Connected to server version {system_info.version}.") self._supported_rpcs = system_info.supported_rpc_requests
def project(ars: ARServer, scene: common.Scene) -> common.Project: """Creates project with following objects: ap - global AP ap_ap - child of ap ap_ap_ap - child of ap_ap ori - ap_ap_ap orientation """ test = "Test project" assert ars.call_rpc( rpc.p.NewProject.Request( get_id(), rpc.p.NewProject.Request.Args(scene.id, test, test)), rpc.p.NewProject.Response, ).result project_evt = event(ars, events.p.OpenProject) assert project_evt.data event(ars, events.s.SceneState) assert ars.call_rpc( rpc.p.AddActionPoint.Request( get_id(), rpc.p.AddActionPoint.Request.Args("ap", common.Position(0, 0, 0))), rpc.p.AddActionPoint.Response, ).result ap_evt = event(ars, events.p.ActionPointChanged) assert ap_evt.data assert ars.call_rpc( rpc.p.AddActionPoint.Request( get_id(), rpc.p.AddActionPoint.Request.Args("ap_ap", common.Position(0, 0, 1), ap_evt.data.id)), rpc.p.AddActionPoint.Response, ).result ap_ap_evt = event(ars, events.p.ActionPointChanged) assert ap_ap_evt.data assert ars.call_rpc( rpc.p.AddActionPoint.Request( get_id(), rpc.p.AddActionPoint.Request.Args("ap_ap_ap", common.Position(0, 0, 2), ap_ap_evt.data.id)), rpc.p.AddActionPoint.Response, ).result ap_ap_ap_evt = event(ars, events.p.ActionPointChanged) assert ap_ap_ap_evt.data lock_object(ars, ap_ap_ap_evt.data.id) assert ars.call_rpc( rpc.p.AddActionPointOrientation.Request( get_id(), rpc.p.AddActionPointOrientation.Request.Args( ap_ap_ap_evt.data.id, common.Orientation(), "ori")), rpc.p.AddActionPointOrientation.Response, ).result ori_evt = event(ars, events.p.OrientationChanged) assert ori_evt.data unlock_object(ars, ap_ap_ap_evt.data.id) assert ars.call_rpc(rpc.p.SaveProject.Request(get_id()), rpc.p.SaveProject.Response).result event(ars, events.p.ProjectSaved) assert ars.call_rpc(rpc.p.CloseProject.Request(get_id()), rpc.p.CloseProject.Response).result event(ars, events.p.ProjectClosed) event(ars, events.c.ShowMainScreen) return project_evt.data.project
def put_package(packageId: str) -> RespT: # noqa """Put package --- put: summary: Adds the execution package. operationId: PutPackage tags: - Packages parameters: - in: path name: packageId schema: type: string required: true description: Unique package Id requestBody: content: multipart/form-data: schema: type: object required: - executionPackage properties: # 'file' will be the field name in this multipart request executionPackage: type: string format: binary responses: 200: description: Ok 500: description: Another error occurred. content: application/json: schema: type: array items: type: string """ file = request.files["executionPackage"] assert file.filename file_name = secure_filename(file.filename) with tempfile.TemporaryDirectory() as tmpdirname: file_path = os.path.join(tmpdirname, file_name) file.save(file_path) with open(file_path, "rb") as zip_file: b64_bytes = base64.b64encode(zip_file.read()) b64_str = b64_bytes.decode() resp = call_rpc( rpc.UploadPackage.Request(id=get_id(), args=rpc.UploadPackage.Request.Args( packageId, b64_str))) if resp.result: return Response(status=200) else: return jsonify(resp.messages), 500
def scene(ars: ARServer) -> common.Scene: assert isinstance(ars.get_event(), events.c.ShowMainScreen) test = "Test scene" assert ars.call_rpc( rpc.s.NewScene.Request(get_id(), rpc.s.NewScene.Request.Args(test, test)), rpc.s.NewScene.Response).result scene_evt = event(ars, events.s.OpenScene) assert scene_evt.data event(ars, events.s.SceneState) test_type = "TestType" assert ars.call_rpc( rpc.o.NewObjectType.Request( get_id(), objects.ObjectTypeMeta(test_type, base=Generic.__name__)), rpc.o.NewObjectType.Response, ).result tt_evt = event(ars, events.o.ChangedObjectTypes) assert len(tt_evt.data) == 1 assert not tt_evt.data[0].has_pose assert tt_evt.data[0].type == test_type assert tt_evt.data[0].base == Generic.__name__ assert ars.call_rpc( rpc.s.AddObjectToScene.Request( get_id(), rpc.s.AddObjectToScene.Request.Args("test_type", test_type)), rpc.s.AddObjectToScene.Response, ).result event(ars, events.s.SceneObjectChanged) test_type_with_pose = "TestTypeWithPose" assert ars.call_rpc( rpc.o.NewObjectType.Request( get_id(), objects.ObjectTypeMeta(test_type_with_pose, base=GenericWithPose.__name__)), rpc.o.NewObjectType.Response, ).result ttwp_evt = event(ars, events.o.ChangedObjectTypes) assert len(ttwp_evt.data) == 1 assert ttwp_evt.data[0].has_pose assert ttwp_evt.data[0].type == test_type_with_pose assert ttwp_evt.data[0].base == GenericWithPose.__name__ assert ars.call_rpc( rpc.s.AddObjectToScene.Request( get_id(), rpc.s.AddObjectToScene.Request.Args("test_type_with_pose", test_type)), rpc.s.AddObjectToScene.Response, ).result event(ars, events.s.SceneObjectChanged) assert ars.call_rpc(rpc.s.SaveScene.Request(get_id()), rpc.s.SaveScene.Response).result event(ars, events.s.SceneSaved) assert ars.call_rpc(rpc.s.CloseScene.Request(get_id()), rpc.s.CloseScene.Response).result event(ars, events.s.SceneClosed) event(ars, events.c.ShowMainScreen) return scene_evt.data.scene
def test_object_parameters(start_processes: None, ars: ARServer, scene: Scene) -> None: assert ars.call_rpc(rpc.s.OpenScene.Request(get_id(), IdArgs(scene.id)), rpc.s.OpenScene.Response).result event(ars, events.s.OpenScene) event(ars, events.s.SceneState) assert ars.call_rpc( rpc.s.AddObjectToScene.Request( get_id(), rpc.s.AddObjectToScene.Request.Args("ows", ObjectWithActions.__name__)), rpc.s.AddObjectToScene.Response, ).result obj = event(ars, events.s.SceneObjectChanged).data assert obj is not None assert ars.call_rpc( rpc.p.NewProject.Request( get_id(), rpc.p.NewProject.Request.Args(scene.id, "Project name")), rpc.p.NewProject.Response, ).result event(ars, events.s.SceneSaved) event(ars, events.p.OpenProject) event(ars, events.s.SceneState) assert ars.call_rpc( rpc.p.AddActionPoint.Request( get_id(), rpc.p.AddActionPoint.Request.Args("ap", Position())), rpc.p.AddActionPoint.Response, ).result ap = event(ars, events.p.ActionPointChanged).data assert ap is not None assert ars.call_rpc( rpc.p.AddAction.Request( get_id(), rpc.p.AddAction.Request.Args( ap.id, "a1", f"{obj.id}/{ObjectWithActions.bool_action.__name__}", [], [Flow(outputs=["bool_result"])], ), ), rpc.p.AddAction.Response, ).result a1 = event(ars, events.p.ActionChanged).data assert a1 is not None assert ars.call_rpc( rpc.p.AddAction.Request( get_id(), rpc.p.AddAction.Request.Args( ap.id, "a2", f"{obj.id}/{ObjectWithActions.str_action.__name__}", [], [Flow()], ), ), rpc.p.AddAction.Response, ).result a2 = event(ars, events.p.ActionChanged).data assert a2 is not None add_logic_item(ars, LogicItem.START, a1.id) event(ars, events.lk.ObjectsUnlocked) lock_object(ars, a1.id) add_logic_item( ars, a1.id, a2.id, ProjectLogicIf(f"{a1.id}/{FlowTypes.DEFAULT}/{0}", json.dumps(True))) event(ars, events.lk.ObjectsUnlocked) lock_object(ars, a2.id) add_logic_item(ars, a2.id, LogicItem.END) event(ars, events.lk.ObjectsUnlocked) lock_object(ars, a1.id) add_logic_item( ars, a1.id, LogicItem.END, ProjectLogicIf(f"{a1.id}/{FlowTypes.DEFAULT}/{0}", json.dumps(False))) event(ars, events.lk.ObjectsUnlocked) # TODO try to add some invalid connections here? save_project(ars)
def close_project(ars: ARServer) -> None: assert ars.call_rpc(rpc.p.CloseProject.Request(get_id()), rpc.p.CloseProject.Response).result event(ars, events.p.ProjectClosed)