docs(delmia-notifier): README + publish/AOT instructions
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"planPath": "docs/plans/2026-06-26-delmia-recipe-notifier.md",
|
"planPath": "docs/plans/2026-06-26-delmia-recipe-notifier.md",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{"id": 11, "subject": "Task 1: Scaffold src + test projects", "status": "pending"},
|
{"id": 11, "subject": "Task 1: Scaffold src + test projects", "status": "completed"},
|
||||||
{"id": 12, "subject": "Task 2: DTOs + JSON source-gen context", "status": "pending", "blockedBy": [11]},
|
{"id": 12, "subject": "Task 2: DTOs + JSON source-gen context", "status": "completed", "blockedBy": [11]},
|
||||||
{"id": 13, "subject": "Task 3: CLI arg parser", "status": "pending", "blockedBy": [11]},
|
{"id": 13, "subject": "Task 3: CLI arg parser", "status": "completed", "blockedBy": [11]},
|
||||||
{"id": 14, "subject": "Task 4: Config loader + API key", "status": "pending", "blockedBy": [11]},
|
{"id": 14, "subject": "Task 4: Config loader + API key", "status": "completed", "blockedBy": [11]},
|
||||||
{"id": 15, "subject": "Task 5: Failover loop (IRecipeSender seam)", "status": "pending", "blockedBy": [12]},
|
{"id": 15, "subject": "Task 5: Failover loop (IRecipeSender seam)", "status": "completed", "blockedBy": [12]},
|
||||||
{"id": 16, "subject": "Task 6: HttpClient recipe sender", "status": "pending", "blockedBy": [12, 15]},
|
{"id": 16, "subject": "Task 6: HttpClient recipe sender", "status": "completed", "blockedBy": [12, 15]},
|
||||||
{"id": 17, "subject": "Task 7: Program wiring + reporter + logger", "status": "pending", "blockedBy": [13, 14, 15, 16]},
|
{"id": 17, "subject": "Task 7: Program wiring + reporter + logger", "status": "completed", "blockedBy": [13, 14, 15, 16]},
|
||||||
{"id": 18, "subject": "Task 8: README + publish/AOT + final verify", "status": "pending", "blockedBy": [17]}
|
{"id": 18, "subject": "Task 8: README + publish/AOT + final verify", "status": "completed", "blockedBy": [17]}
|
||||||
],
|
],
|
||||||
"lastUpdated": "2026-06-26"
|
"lastUpdated": "2026-06-26"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# DelmiaNotifier (`WWNotifier.exe`)
|
||||||
|
|
||||||
|
A compact, self-contained Windows console app that **DELMIA Apriso shells out to** on each
|
||||||
|
recipe / NC-program download to notify the plant that a recipe was placed at a path for a machine.
|
||||||
|
|
||||||
|
It is the modern, drop-in replacement for the legacy `WWNotifier` (see
|
||||||
|
[`../../docs/former-api-specs/dnc/Delmia-Integration-API.md`](../../docs/former-api-specs/dnc/Delmia-Integration-API.md),
|
||||||
|
*Surface B*), repointed from the old Wonderware `/notify` receiver to the **ScadaBridge Inbound API**
|
||||||
|
method `DelmiaRecipeDownload`. The command-line flags, the `YES`/`NO` stdout contract, and the
|
||||||
|
exit-code semantics are **unchanged**, so Delmia's call site and output parsing need no changes — only
|
||||||
|
the executable on disk and its `appsettings.json` are swapped.
|
||||||
|
|
||||||
|
> The published assembly name is **`WWNotifier`** precisely so it is a literal file-for-file drop-in
|
||||||
|
> for Delmia's existing call path.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
Per invocation it POSTs the recipe-download notification to the configured ScadaBridge node(s) and
|
||||||
|
maps the result back to the legacy contract:
|
||||||
|
|
||||||
|
```
|
||||||
|
DELMIA → WWNotifier.exe → POST {baseUrl}/api/DelmiaRecipeDownload (X-API-Key: <key>)
|
||||||
|
← { "Result": true/false, "ResultText": "..." }
|
||||||
|
← stdout: YES | NO\n<reason> · exit: 0 | -1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command-line flags
|
||||||
|
|
||||||
|
| Short | Long | Required | → payload field |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `-d` | `--downloadpath` | yes | `DownloadPath` |
|
||||||
|
| `-m` | `--machine` | yes | `MachineCode` |
|
||||||
|
| `-w` | `--workorder` | yes | `WorkOrderNumber` |
|
||||||
|
| `-p` | `--partnumber` | yes | `PartNumber` |
|
||||||
|
| `-s` | `--seqop` | no | `JobStepNumber` |
|
||||||
|
| `-u` | `--username` | no | `Username` |
|
||||||
|
|
||||||
|
Each flag takes one value (`-m Z28061`). A missing required flag → `NO` + reason, exit `-1`, **no**
|
||||||
|
HTTP attempt.
|
||||||
|
|
||||||
|
```
|
||||||
|
WWNotifier.exe -m Z28061 -d "C:\recipes\job.nc" -w WO12345 -p PN-7788 -s 0100 -u operator1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output contract (drop-in parity)
|
||||||
|
|
||||||
|
- **stdout** is reserved for the contract Delmia parses:
|
||||||
|
- success → `YES` (exit `0`)
|
||||||
|
- failure → `NO` on the first line, then a human-readable reason on the next line (exit `-1`)
|
||||||
|
- **exit code**: `0` on success, `-1` on failure. (On POSIX shells `-1` surfaces as `255`; on Windows
|
||||||
|
`%ERRORLEVEL%` is `-1`.)
|
||||||
|
- All diagnostics (per-URL attempt, status code, which URL answered, exceptions) go to **stderr** and,
|
||||||
|
if `LogPath` is set, an appended log file — never to stdout.
|
||||||
|
|
||||||
|
## Configuration — `appsettings.json`
|
||||||
|
|
||||||
|
Placed next to the exe (copied to the output on build/publish):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ScadaBridge": {
|
||||||
|
"BaseUrls": "http://host-a:8085,http://host-b:8085",
|
||||||
|
"TimeoutSeconds": 30,
|
||||||
|
"LogPath": "logs/delmia-notifier.log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`BaseUrls`** — comma-separated failover list of **base URLs only**; the app appends
|
||||||
|
`/api/DelmiaRecipeDownload`. URLs are tried in order with **connect-failure-only failover**: a node
|
||||||
|
that responds at all (even `4xx`/`5xx`) is authoritative and its answer is final; only a node that
|
||||||
|
fails to connect (refused/reset, DNS, TLS, timeout) rolls over to the next. If every URL fails to
|
||||||
|
connect → `NO` + last connection error.
|
||||||
|
- **`TimeoutSeconds`** — per-attempt HTTP timeout (default `30`).
|
||||||
|
- **`LogPath`** — optional diagnostic log file, relative to the exe. Omit to log to stderr only.
|
||||||
|
|
||||||
|
## Secret — `SCADABRIDGE_API_KEY`
|
||||||
|
|
||||||
|
The inbound API key is read **only** from the environment variable `SCADABRIDGE_API_KEY` and is sent
|
||||||
|
as the `X-API-Key` header. It is never read from or written to a file. If unset/empty → `NO` +
|
||||||
|
`API key not configured (SCADABRIDGE_API_KEY)`, exit `-1`, no HTTP attempt.
|
||||||
|
|
||||||
|
Set it on the machine/account that DELMIA runs under (e.g. a system/user environment variable, or the
|
||||||
|
service account's environment).
|
||||||
|
|
||||||
|
## Building & publishing (Native AOT, `win-x64`)
|
||||||
|
|
||||||
|
The runtime artifact is a self-contained, single-file native exe. **Native AOT does not cross-compile
|
||||||
|
from macOS/Linux** — publish on Windows with the MSVC build tools (Desktop C++ workload) installed:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On Windows:
|
||||||
|
dotnet publish src/ZB.MOM.WW.ScadaBridge.DelmiaNotifier -c Release -r win-x64
|
||||||
|
# → bin/Release/net10.0/win-x64/publish/WWNotifier.exe (+ appsettings.json)
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `WWNotifier.exe` **and** `appsettings.json` to the Delmia host, set `SCADABRIDGE_API_KEY`, and
|
||||||
|
point `BaseUrls` at the central node(s).
|
||||||
|
|
||||||
|
> Managed `dotnet build` / `dotnet test` run cross-platform and are the development/CI gate; only the
|
||||||
|
> final native publish requires Windows.
|
||||||
|
|
||||||
|
## Manual smoke test
|
||||||
|
|
||||||
|
After deploying (or against a reachable test cluster such as `wonder-app-vd03`):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:SCADABRIDGE_API_KEY = "sbk_..."
|
||||||
|
.\WWNotifier.exe -m Z28061Sim -d "C:\recipes\test.nc" -w WO-TEST -p PN-TEST -s 0100 -u smoketest
|
||||||
|
# expect: YES (exit 0) — or NO + reason (exit -1) with details on stderr / in the log file
|
||||||
|
```
|
||||||
|
|
||||||
|
This mirrors the earlier `curl` verification of `POST /api/DelmiaRecipeDownload` with the
|
||||||
|
`X-API-Key` header.
|
||||||
Reference in New Issue
Block a user