diff --git a/Docs/ASLM/content/docs/ASLM/Models/AppData.md b/Docs/ASLM/content/docs/ASLM/Models/AppData.md index c2fad1a..d154450 100644 --- a/Docs/ASLM/content/docs/ASLM/Models/AppData.md +++ b/Docs/ASLM/content/docs/ASLM/Models/AppData.md @@ -15,7 +15,7 @@ draft: false | --- | --- | --- | | `firstRunCompleted` | `bool` | Setup wizard finished | | `user` | `AppUserData` | Display name | -| `ports` | `AppPortConfig` | Official / third-party port ranges | +| `ports` | `AppPortConfig` | Module start port | | `api` | `AppApiConfig` | Local API mirror server toggle | | `consoles` | `AppConsoleConfig` | Consoles page preferences | | `updates` | `AppUpdateSettings` | ASLM and module update policy | @@ -59,10 +59,11 @@ Port assignment is handled at runtime by **`PortRegistry`**, not stored here. | Property | JSON | Default | | --- | --- | --- | -| `OfficialStart` | `officialStart` | `20000` | -| `OfficialCount` | `officialCount` | `100` | -| `ThirdPartyStart` | `thirdPartyStart` | `21000` | -| `ThirdPartyCount` | `thirdPartyCount` | `1000` | +| `ModulesStart` | `modulesStart` | `20000` | + +#### `void Normalize()` + +**Purpose:** Migrates legacy official/third-party port settings and clamps the start port. --- diff --git a/Docs/ASLM/content/docs/ASLM/Pages/SettingsView.md b/Docs/ASLM/content/docs/ASLM/Pages/SettingsView.md index a6e1697..860277b 100644 --- a/Docs/ASLM/content/docs/ASLM/Pages/SettingsView.md +++ b/Docs/ASLM/content/docs/ASLM/Pages/SettingsView.md @@ -70,7 +70,7 @@ Style resource keys: `FooterButtonStyleKey`, `FooterPrimaryButtonStyleKey`, `Foo | `SettingsScroll` / `SettingsContentContainer` | Right pane scroll host | | `AslmSettingsContainer` | Profile + ports (account/ASLM categories) | | `UserProfileSection` | `UsernameEntry` | -| `PortsSection` | `OfficialPortEntry`, `ThirdPartyPortEntry`, `PortErrorLabel` | +| `PortsSection` | `ModulePortEntry`, `PortErrorLabel` | | `ModuleSettingsContainer` | Dynamic module / updates / personalization / Ollama content | | `EmptyCategoryState` / `EmptyCategoryLabel` | No settings placeholder | | `DefaultButton` | `OnDefaultClicked` | @@ -704,7 +704,7 @@ Lightweight switch used instead of native `Switch` for consistent sizing. --- -#### `private string GetCurrentOfficialPortDraft()` / `GetCurrentThirdPartyPortDraft()` +#### `private string GetCurrentPortStartDraft()` **Purpose:** Reads ports from visible entries or cached drafts. diff --git a/Docs/ASLM/content/docs/ASLM/Pages/SetupWizardPage.md b/Docs/ASLM/content/docs/ASLM/Pages/SetupWizardPage.md index 213b5ad..f47f45a 100644 --- a/Docs/ASLM/content/docs/ASLM/Pages/SetupWizardPage.md +++ b/Docs/ASLM/content/docs/ASLM/Pages/SetupWizardPage.md @@ -53,8 +53,8 @@ Three-row grid: **header** | **content** | **footer**. | `Step1Panel` | Display name | | `DisplayNameTitleLabel`, `UsernameEntry` | **`SettingsService.TryValidateDisplayName`** | | `Step2Panel` | Port ranges | -| `PortAllocationTitleLabel`, `OfficialPortsLabel`, `ThirdPartyPortsLabel` | | -| `OfficialPortEntry`, `ThirdPartyPortEntry`, `PortErrorLabel` | **`SettingsService.TryParsePorts`** | +| `PortAllocationTitleLabel`, `ModulePortLabel` | | +| `ModulePortEntry`, `PortErrorLabel` | **`SettingsService.TryParsePortStart`** | | `Step3Panel` | Module list + install UI | | `ModuleListScroll` / `ModuleList` | Dynamic checkboxes | | `InstallPanel` | Progress + log | @@ -148,7 +148,7 @@ Three-row grid: **header** | **content** | **footer**. #### `private bool ValidatePorts()` -**Purpose:** **`SettingsService.TryParsePorts`**; **`ShowPortError`** on failure. +**Purpose:** **`SettingsService.TryParsePortStart`**; **`ShowPortError`** on failure. --- diff --git a/Docs/ASLM/content/docs/ASLM/Services/AslmApiServer.md b/Docs/ASLM/content/docs/ASLM/Services/AslmApiServer.md index 7ec9055..f4c91ce 100644 --- a/Docs/ASLM/content/docs/ASLM/Services/AslmApiServer.md +++ b/Docs/ASLM/content/docs/ASLM/Services/AslmApiServer.md @@ -453,7 +453,7 @@ Converts a mirror-prefixed path back into the backend root-relative path. #### `private int GetAssignedPort()` -**Purpose:** Gets or reserves the ASLM API port from the shared official module pool. +**Purpose:** Gets or reserves the ASLM API port from the shared module port pool. --- diff --git a/Docs/ASLM/content/docs/ASLM/Services/AslmModuleInteropServer.md b/Docs/ASLM/content/docs/ASLM/Services/AslmModuleInteropServer.md index cb63d4e..add331c 100644 --- a/Docs/ASLM/content/docs/ASLM/Services/AslmModuleInteropServer.md +++ b/Docs/ASLM/content/docs/ASLM/Services/AslmModuleInteropServer.md @@ -166,7 +166,7 @@ Unknown routes → **404** JSON error. Unhandled exceptions → **500**. #### `private int GetAssignedPort()` -**Purpose:** **`PortRegistry.GetOrAssignInternalServicePort`** for interop service id/key. +**Purpose:** **`PortRegistry.GetOrAssignInternalServicePort`** and **`EnsurePortsAvailable`** for interop service id/key. --- diff --git a/Docs/ASLM/content/docs/ASLM/Services/ModuleRunner.md b/Docs/ASLM/content/docs/ASLM/Services/ModuleRunner.md index 41046a6..815aadb 100644 --- a/Docs/ASLM/content/docs/ASLM/Services/ModuleRunner.md +++ b/Docs/ASLM/content/docs/ASLM/Services/ModuleRunner.md @@ -29,7 +29,7 @@ Implements **`IDisposable`**. Subscribes to **`PortRegistry.PortsRedistributed`* #### `public async Task ExecuteRunAsync(ModuleConfig module, IProgress log, CancellationToken ct)` -**Purpose:** Synchronizes settings, starts each **`Commands.Run`** entry in background with **`trackProcess: true`**. +**Purpose:** Allocates and ensures ports are available, synchronizes settings, and starts each **`Commands.Run`** entry in background with **`trackProcess: true`**. --- diff --git a/Docs/ASLM/content/docs/ASLM/Services/PortRegistry.md b/Docs/ASLM/content/docs/ASLM/Services/PortRegistry.md index a8eed83..3641b14 100644 --- a/Docs/ASLM/content/docs/ASLM/Services/PortRegistry.md +++ b/Docs/ASLM/content/docs/ASLM/Services/PortRegistry.md @@ -48,9 +48,15 @@ Internal owners use id prefix **`__`**. --- +#### `public bool EnsurePortsAvailable(string ownerId)` + +**Purpose:** Verifies all assigned ports for an owner are free on the system, reallocating any that are in use and returning whether the map was changed. + +--- + #### `public int GetOrAssignInternalServicePort(string serviceId, string portKey)` -**Purpose:** Official-pool allocation for internal services (e.g. API mirror, interop). +**Purpose:** Shared-pool allocation for internal services (e.g. API mirror, interop). --- @@ -112,25 +118,25 @@ Internal owners use id prefix **`__`**. #### `private bool IsPortValid(string ownerId, int port)` -**Purpose:** In configured official/third-party range, or legacy **40000–49999** fallback band. +**Purpose:** Checks whether an assigned port is valid for the current start port. --- #### `private int AllocatePort(string ownerId)` -**Purpose:** Next free port in owner category using global used set. +**Purpose:** Allocates the next available port from the shared module pool. --- #### `private int AllocatePort(string ownerId, HashSet usedPorts)` -**Purpose:** Explicit used-port set for redistribution. +**Purpose:** Allocates using an explicit used-port set. --- -#### `private static int AllocatePort(string ownerId, HashSet usedPorts, int start, int count)` +#### `private static int AllocatePort(string ownerId, HashSet usedPorts, int start)` -**Purpose:** Linear scan in range, then deterministic **40000+** hash fallback; throws when exhausted. +**Purpose:** Linear scan from start port, then deterministic **40000+** hash fallback; throws when exhausted. --- diff --git a/Docs/ASLM/content/docs/ASLM/Services/SettingsService.md b/Docs/ASLM/content/docs/ASLM/Services/SettingsService.md index 563d08b..ae866a9 100644 --- a/Docs/ASLM/content/docs/ASLM/Services/SettingsService.md +++ b/Docs/ASLM/content/docs/ASLM/Services/SettingsService.md @@ -31,7 +31,7 @@ draft: false --- -#### `public sealed record AslmBaseline(string UserName, string OfficialPort, string ThirdPartyPort, bool ApiServerEnabled)` +#### `public sealed record AslmBaseline(string UserName, string PortStart, bool ApiServerEnabled)` **Purpose:** Stores the initial ASLM values loaded for the current page session. @@ -49,7 +49,7 @@ draft: false --- -#### `public sealed record AslmDraftSnapshot( string UserName, string OfficialPort, string ThirdPartyPort, bool ApiServerEnabled, ConsoleBaseline ConsoleBaseline, UpdateBaseline UpdateBaseline)` +#### `public sealed record AslmDraftSnapshot( string UserName, string PortStart, bool ApiServerEnabled, ConsoleBaseline ConsoleBaseline, UpdateBaseline UpdateBaseline)` **Purpose:** Snapshot of editable ASLM drafts derived from persisted app data and runtime state. @@ -89,7 +89,7 @@ draft: false --- -#### `public static PortParseResult TryParsePorts(string officialDraft, string thirdPartyDraft)` +#### `public static PortParseResult TryParsePortStart(string draft)` **Purpose:** Validates the port draft values and returns parsed integers when valid. @@ -119,7 +119,7 @@ draft: false --- -#### `public static void ApplyDraftsToAppData( AppDataStore appData, string userName, int officialPort, int thirdPartyPort, ConsoleBaseline consoleDraft, AppUpdateSettings updateSettings)` +#### `public static void ApplyDraftsToAppData( AppDataStore appData, string userName, int modulesStart, ConsoleBaseline consoleDraft, AppUpdateSettings updateSettings)` **Purpose:** Writes ASLM and update drafts to persisted app data. @@ -137,7 +137,7 @@ draft: false --- -#### `public static (string OfficialPort, string ThirdPartyPort, bool ApiServerEnabled, ConsoleBaseline ConsoleDefaults) BuildDefaultAslmDrafts()` +#### `public static (string PortStart, bool ApiServerEnabled, ConsoleBaseline ConsoleDefaults) BuildDefaultAslmDrafts()` **Purpose:** Builds ASLM defaults for ports, API and console sections. @@ -149,7 +149,7 @@ draft: false --- -#### `public static bool HasUnsavedPortChanges(string officialPort, string thirdPartyPort, AslmBaseline baseline)` +#### `public static bool HasUnsavedPortChanges(string portStart, AslmBaseline baseline)` **Purpose:** Checks whether ports draft differs from baseline. @@ -173,7 +173,7 @@ draft: false --- -#### `public static bool HasUnsavedAslmSettingsChanges( string officialPort, string thirdPartyPort, bool apiServerEnabled, ConsoleBaseline consoleDraft, UpdateBaseline updateDraft, AslmBaseline aslmBaseline, ConsoleBaseline consoleBaseline, UpdateBaseline updateBaseline)` +#### `public static bool HasUnsavedAslmSettingsChanges( string portStart, bool apiServerEnabled, ConsoleBaseline consoleDraft, UpdateBaseline updateDraft, AslmBaseline aslmBaseline, ConsoleBaseline consoleBaseline, UpdateBaseline updateBaseline)` **Purpose:** Checks whether non-account ASLM settings differ from baseline. diff --git a/Docs/ASLM/content/docs/ASLM/Tests/Services/PortRegistryTests.md b/Docs/ASLM/content/docs/ASLM/Tests/Services/PortRegistryTests.md index a1a0eaa..f796dbf 100644 --- a/Docs/ASLM/content/docs/ASLM/Tests/Services/PortRegistryTests.md +++ b/Docs/ASLM/content/docs/ASLM/Tests/Services/PortRegistryTests.md @@ -25,16 +25,29 @@ draft: false --- -#### `public void GetOrAssignPorts_allocates_within_official_range()` +#### `public void GetOrAssignPorts_allocates_from_modules_start()` -**Purpose:** Official module `http` port is allocated inside configured official range. +**Purpose:** Module `http` port is allocated starting from the configured modules start port. | Step | Action | | --- | --- | -| 1 | Layout + `AppDataStore`; set `OfficialStart = 25000`, `OfficialCount = 50` | -| 2 | `new PortRegistry(appData)`; module `id: "official-module"` | +| 1 | Layout + `AppDataStore`; set `ModulesStart = 25000` | +| 2 | `new PortRegistry(appData)`; module `id: "sample-module"` | | 3 | `GetOrAssignPorts(module)` | -| 4 | Assert `ports` contains `http` in range `25000`…`25049` | +| 4 | Assert `ports` contains `http` equal to `25000` | + +--- + +#### `public void EnsurePortsAvailable_keeps_free_ports_unchanged()` + +**Purpose:** Validates that already-free ports are kept when `EnsurePortsAvailable` is called. + +| Step | Action | +| --- | --- | +| 1 | Layout + `AppDataStore`; set `ModulesStart = 30000` | +| 2 | `new PortRegistry(appData)`; module `id: "availability-module"` | +| 3 | `GetOrAssignPorts(module)` | +| 4 | Assert `EnsurePortsAvailable(module.Id)` returns `false` | --- @@ -44,7 +57,7 @@ draft: false | Step | Action | | --- | --- | -| 1 | Layout + app data; `OfficialStart = 26000`, `OfficialCount = 100` | +| 1 | Layout + app data; `ModulesStart = 26000` | | 2 | Two calls with `AslmApiServiceId` / `AslmApiPortKey` | | 3 | Assert second equals first; `TryGetInternalServicePort` matches | diff --git a/Docs/ASLM/content/docs/ASLM/Tests/Services/SettingsServiceTests.md b/Docs/ASLM/content/docs/ASLM/Tests/Services/SettingsServiceTests.md index 9bee793..5269280 100644 --- a/Docs/ASLM/content/docs/ASLM/Tests/Services/SettingsServiceTests.md +++ b/Docs/ASLM/content/docs/ASLM/Tests/Services/SettingsServiceTests.md @@ -13,22 +13,22 @@ draft: false ## Test methods -#### `public void TryParsePorts_validates_ranges_and_overlap(string official, string thirdParty, bool expectedSuccess)` +#### `public void TryParsePortStart_validates_range(string draft, bool expectedSuccess)` -**Purpose:** Port draft strings must parse, sit in valid ranges, and not overlap official/third-party bands. +**Purpose:** Port start draft string must parse and sit in valid range. -| `official` | `thirdParty` | `expectedSuccess` | -| --- | --- | --- | -| `20000` | `30000` | `true` | -| `abc` | `30000` | `false` | -| `20000` | `99999` | `false` | -| `20050` | `20000` | `false` | +| `draft` | `expectedSuccess` | +| --- | --- | +| `20000` | `true` | +| `abc` | `false` | +| `99999` | `false` | +| `1023` | `false` | | Step | Action | | --- | --- | -| 1 | `TryParsePorts(official, thirdParty)` | +| 1 | `TryParsePortStart(draft)` | | 2 | Assert `Success == expectedSuccess` | -| 3 | On success: parsed ports match integers; on failure: non-empty `ErrorMessage` | +| 3 | On success: parsed port matches integer; on failure: non-empty `ErrorMessage` | --- @@ -89,8 +89,8 @@ draft: false | Step | Action | | --- | --- | -| 1 | `ApplyDraftsToAppData(store, "Bob", 22000, 32000, console, updates)` | -| 2 | Assert user name, port starts, console flags, `AutoCheckPeriodHours` | +| 1 | `ApplyDraftsToAppData(store, "Bob", 22000, console, updates)` | +| 2 | Assert user name, port start, console flags, `AutoCheckPeriodHours` | --- @@ -100,9 +100,9 @@ draft: false | Step | Action | | --- | --- | -| 1 | Baseline `AslmBaseline("Alice", "20000", "30000", true)` | +| 1 | Baseline `AslmBaseline("Alice", "20000", true)` | | 2 | `HasUnsavedAccountChanges("Bob", …)` → `true` | -| 3 | `HasUnsavedPortChanges("20001", "30000", …)` → `true` | +| 3 | `HasUnsavedPortChanges("20001", …)` → `true` | | 4 | `HasUnsavedApiServerChanges(false, …)` → `true` | ---