| 53 | return self._lock.locked() |
| 54 | |
| 55 | async def update(self, modes: Iterable[mode_specs.ProxyMode]) -> bool: |
| 56 | all_ok = True |
| 57 | |
| 58 | async with self._lock: |
| 59 | new_instances: dict[mode_specs.ProxyMode, ServerInstance] = {} |
| 60 | |
| 61 | start_tasks = [] |
| 62 | if ctx.options.server: |
| 63 | # Create missing modes and keep existing ones. |
| 64 | for spec in modes: |
| 65 | if spec in self._instances: |
| 66 | instance = self._instances[spec] |
| 67 | else: |
| 68 | instance = ServerInstance.make(spec, self._manager) |
| 69 | start_tasks.append(instance.start()) |
| 70 | new_instances[spec] = instance |
| 71 | |
| 72 | # Shutdown modes that have been removed from the list. |
| 73 | stop_tasks = [ |
| 74 | s.stop() |
| 75 | for spec, s in self._instances.items() |
| 76 | if spec not in new_instances |
| 77 | ] |
| 78 | |
| 79 | if not start_tasks and not stop_tasks: |
| 80 | return ( |
| 81 | True # nothing to do, so we don't need to trigger `self.changed`. |
| 82 | ) |
| 83 | |
| 84 | self._instances = new_instances |
| 85 | # Notify listeners about the new not-yet-started servers. |
| 86 | await self.changed.send() |
| 87 | |
| 88 | # We first need to free ports before starting new servers. |
| 89 | for ret in await asyncio.gather(*stop_tasks, return_exceptions=True): |
| 90 | if ret: |
| 91 | all_ok = False |
| 92 | logger.error(str(ret)) |
| 93 | for ret in await asyncio.gather(*start_tasks, return_exceptions=True): |
| 94 | if ret: |
| 95 | all_ok = False |
| 96 | logger.error(str(ret)) |
| 97 | |
| 98 | await self.changed.send() |
| 99 | return all_ok |
| 100 | |
| 101 | def __len__(self) -> int: |
| 102 | return len(self._instances) |