mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-08-17 17:31:44 +08:00
Sync coding agent knowledge base
This commit is contained in:
@@ -322,7 +322,7 @@ The core-side stack uses:
|
||||
|
||||
The renderer-side stack uses:
|
||||
1. `GuiRemoteProtocolAsyncJsonChannelRenderer` when network packages can arrive before the native GacUI window is ready. It queues received packages until `SetInvokeInMainThread(...)` installs an `IGuiRemoteProtocolAsyncRendererInvoker`, then drains them on the renderer UI thread. Its message version prevents callbacks captured by an old reader from running after the reader is replaced.
|
||||
2. `GuiRemoteProtocolRendererChannel` to bridge the renderer JSON channel to a concrete renderer `IGuiRemoteProtocol` implementation and to serialize renderer events/responses back to the channel.
|
||||
2. `GuiRemoteProtocolRendererChannel` to bridge the renderer JSON channel to a concrete renderer `IGuiRemoteProtocol` implementation and to serialize renderer events/responses back to `GacUIRemoteProtocolCoreClientId`. Construct it with the renderer-side `IJsonChannel` and the `IGuiRemoteProtocol`.
|
||||
|
||||
## Image Service
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ The channel system converts typed protocol calls to Parser2 JSON node packages a
|
||||
Two channel adapters bridge typed protocol calls and JSON packages:
|
||||
|
||||
- `GuiRemoteProtocolCoreChannel`: Implements `IGuiRemoteProtocol` and reads from an `IJsonChannel`. `RequestNAME(...)` serializes arguments with `ConvertCustomTypeToJson()`, packs an envelope with `JsonChannelPack()`, and sends it to the current renderer client. Incoming packages are unpacked with `JsonChannelUnpack()`, dispatched by name, deserialized with `ConvertJsonToCustomType()`, and delivered as `events->OnNAME(...)` or `events->RespondNAME(...)`. It also queues outgoing packages before a renderer is known and exposes `DetachRenderer(clientId)` for renderer replacement.
|
||||
- `GuiRemoteProtocolRendererChannel`: Reads renderer-side JSON packages and calls the wrapped `IGuiRemoteProtocol`. It also implements `IGuiRemoteProtocolEvents` so renderer events and responses are serialized back to JSON packages and flushed through the renderer channel.
|
||||
- `GuiRemoteProtocolRendererChannel`: Reads renderer-side JSON packages and calls the wrapped `IGuiRemoteProtocol`. Its constructor takes the renderer-side `IJsonChannel` and the `IGuiRemoteProtocol`; the channel sends renderer events and responses back to `GacUIRemoteProtocolCoreClientId`.
|
||||
|
||||
### Transport Layer
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- Use `WString::IndexOf` with `wchar_t` (not `const wchar_t*`) [4]
|
||||
- Use `collections::BinarySearchLambda` on contiguous buffers (guard empty) [4]
|
||||
- Use `vl::Exception` for expected semantic failures and `CHECK_ERROR` for invariants [3]
|
||||
- Keep design documentation aligned with code after refactoring [3]
|
||||
- Capture dependent lambdas explicitly [2]
|
||||
- Don't assume observable changes are batched [2]
|
||||
- Do not assume async callback owners are heap allocated [2]
|
||||
@@ -19,8 +20,8 @@
|
||||
- Prefer simple calls before interface casts [2]
|
||||
- Validate expectations against implementation and existing tests [2]
|
||||
- Treat Debug memory leak dumps as required failures [2]
|
||||
- Keep design documentation aligned with code after refactoring [3]
|
||||
- Prefer well-defined tests over ambiguous edge cases [1]
|
||||
- Fix behavior at the owning state instead of patching symptoms [1]
|
||||
- Prefer `operator<=> = default` for lexicographic key structs [1]
|
||||
- Prefer two-pointer merge for sorted range maps [1]
|
||||
- Use named sentinel constants instead of raw values [1]
|
||||
@@ -253,3 +254,7 @@ For application refactors, remove helper wrappers that only duplicate an already
|
||||
## Keep design documentation aligned with code after refactoring
|
||||
|
||||
When a refactoring changes architecture or behavior, update the corresponding design documents in the same task rather than deferring it. After a structural change, re-read the related documents and reconcile anything that became misaligned (for example, descriptions of a transport path that no longer exists). Treat documentation drift left by a previous refactoring as part of the current cleanup.
|
||||
|
||||
## Fix behavior at the owning state instead of patching symptoms
|
||||
|
||||
When a bug is caused by state attached to a temporary or overly broad owner, move the state to the object or region that semantically owns it. Avoid compensating fixes such as forcing override values on every affected descendant, duplicating a template/resource just to mask inherited state, or adding side-channel code that only makes the symptom disappear. If a proposed fix looks like a patch, revisit the ownership boundary and preserve naturally correct inherited/default behavior for unaffected parts.
|
||||
|
||||
@@ -29,7 +29,7 @@ The window id is a path segment after `IO`, not a query parameter. All other met
|
||||
|
||||
## Starting The Service
|
||||
|
||||
Call `StartWindowsHttpAutomationService` from `GuiMain`, after the setup function has installed the current native controller and before entering the application event loop. Call `StopWindowsHttpAutomationService` during shutdown when the service lifetime is not already stopped through `INativeAutomationService::Stop`.
|
||||
Call `StartWindowsHttpAutomationService` from `GuiMain`, after the setup function has installed the current native controller and before entering the application event loop. Every code path that calls `StartWindowsHttpAutomationService` must later call `StopWindowsHttpAutomationService` before the native controller or substituted automation service is torn down. Skipping the stop leaks the process-wide HTTP service. Use a local guard or equivalent try/catch so the stop runs after the start on normal returns and exceptions.
|
||||
|
||||
A normal Windows application can start the service before `GetApplication()->Run`:
|
||||
```c++
|
||||
@@ -39,17 +39,30 @@ using namespace vl;
|
||||
using namespace vl::presentation;
|
||||
using namespace vl::presentation::controls;
|
||||
|
||||
class WindowsHttpAutomationServiceScope
|
||||
{
|
||||
public:
|
||||
WindowsHttpAutomationServiceScope(const WString& applicationName, vint port)
|
||||
{
|
||||
windows::StartWindowsHttpAutomationService(applicationName, port);
|
||||
}
|
||||
|
||||
~WindowsHttpAutomationServiceScope()
|
||||
{
|
||||
windows::StopWindowsHttpAutomationService();
|
||||
}
|
||||
};
|
||||
|
||||
void GuiMain()
|
||||
{
|
||||
demo::MainWindow window;
|
||||
window.ForceCalculateSizeImmediately();
|
||||
window.MoveToScreenCenter();
|
||||
|
||||
windows::StartWindowsHttpAutomationService(
|
||||
WindowsHttpAutomationServiceScope httpAutomationService(
|
||||
WString::Unmanaged(L"Automation/MyApp"),
|
||||
8888);
|
||||
GetApplication()->Run(&window);
|
||||
windows::StopWindowsHttpAutomationService();
|
||||
}
|
||||
|
||||
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
@@ -58,7 +71,7 @@ int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
}
|
||||
```
|
||||
|
||||
Repeated calls do not create multiple listeners. The Windows implementation keeps one process-wide HTTP service until `StopWindowsHttpAutomationService` or `INativeAutomationService::Stop` stops it.
|
||||
Repeated calls do not create multiple listeners. The Windows implementation keeps one process-wide HTTP service until `StopWindowsHttpAutomationService` stops it.
|
||||
|
||||
## Setup Function Cases
|
||||
|
||||
@@ -79,19 +92,20 @@ The setup function decides which controller and service are active while `GuiMai
|
||||
|
||||
Use `GetNativeServiceSubstitution()->Substitute(service, false)` before the automation service is first requested. The substitution layer rejects a late substitution after a service has already been used. Keep the substituted object alive until it is unsubstituted.
|
||||
|
||||
A remote protocol core can expose the core-side automation surface like this:
|
||||
A remote protocol core can expose the core-side automation surface like this. The sample uses the same `WindowsHttpAutomationServiceScope` guard from the normal Windows application example.
|
||||
```c++
|
||||
void GuiMain()
|
||||
{
|
||||
RemoteProtocolAutomationService automationService;
|
||||
GetNativeServiceSubstitution()->Substitute(&automationService, false);
|
||||
windows::StartWindowsHttpAutomationService(
|
||||
WString::Unmanaged(L"Automation/RemoteCore"),
|
||||
8888);
|
||||
|
||||
GetApplication()->Run(mainWindow);
|
||||
{
|
||||
WindowsHttpAutomationServiceScope httpAutomationService(
|
||||
WString::Unmanaged(L"Automation/RemoteCore"),
|
||||
8888);
|
||||
GetApplication()->Run(mainWindow);
|
||||
}
|
||||
|
||||
windows::StopWindowsHttpAutomationService();
|
||||
GetNativeServiceSubstitution()->Unsubstitute(&automationService);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,7 +48,6 @@ int StartNamedPipeRemoteRenderer()
|
||||
GuiRemoteProtocolAsyncJsonChannelRenderer asyncRendererChannel(channelClient.GetProtocolChannel());
|
||||
GuiRemoteRendererSingle renderer(true);
|
||||
GuiRemoteProtocolRendererChannel rendererChannel(
|
||||
&channelClient,
|
||||
&asyncRendererChannel,
|
||||
&renderer);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ A remote protocol core application is a normal GacUI application that calls Setu
|
||||
The standard C++ path is small:
|
||||
- Start a GuiRemoteProtocolNetworkChannelServer\<TServerBase\> over an INetworkProtocolServer implementation such as NamedPipeServer or HttpServer.
|
||||
- Connect the core to that server with GuiRemoteProtocolLocalChannelClient.
|
||||
- Wrap the core channel with GuiRemoteProtocolJsonChannelRenderer_Async and GuiRemoteProtocolCoreChannel.
|
||||
- Wrap the core channel with GuiRemoteProtocolAsyncJsonChannel and GuiRemoteProtocolCoreChannel.
|
||||
- Pass the protocol, usually after GuiRemoteProtocolFilter and GuiRemoteProtocolDomDiffConverter, to SetupRemoteNativeController.
|
||||
|
||||
The core client is expected to be registered as GacUIRemoteProtocolCoreClientId. A renderer created by GuiRemoteProtocolChannelClient advertises GacUIRemoteProtocolChannelName. GuiRemoteProtocolCoreChannel learns the renderer client id from the renderer's ControllerConnect event, so user code does not need to route individual remote protocol messages.
|
||||
@@ -69,7 +69,7 @@ void StartNamedPipeRemoteCore()
|
||||
|
||||
server.WaitForRenderer();
|
||||
|
||||
GuiRemoteProtocolJsonChannelRenderer_Async asyncChannel(coreClient->GetProtocolChannel());
|
||||
GuiRemoteProtocolAsyncJsonChannel asyncChannel(coreClient->GetProtocolChannel());
|
||||
GuiRemoteProtocolCoreChannel coreProtocol(
|
||||
coreClient.Obj(),
|
||||
&asyncChannel,
|
||||
|
||||
Reference in New Issue
Block a user