Merge branch 'driver_ui' into dev
Build and Push Docker Images / build-auth-api (push) Has been skipped
Build and Push Docker Images / build-employee-api (push) Has been skipped
Build and Push Docker Images / detect-changes (push) Successful in 10s
Build and Push Docker Images / build-transit-api (push) Has been skipped
Build and Push Docker Images / build-error-log-api (push) Has been skipped
Build and Push Docker Images / build-admin-ui (push) Has been skipped
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m30s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
Build and Push Docker Images / build-auth-api (push) Has been skipped
Build and Push Docker Images / build-employee-api (push) Has been skipped
Build and Push Docker Images / detect-changes (push) Successful in 10s
Build and Push Docker Images / build-transit-api (push) Has been skipped
Build and Push Docker Images / build-error-log-api (push) Has been skipped
Build and Push Docker Images / build-admin-ui (push) Has been skipped
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m30s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
# Windows XP Driver UI
|
||||||
|
|
||||||
|
This project is a native Win32 application built for Windows XP compatibility.
|
||||||
|
It avoids .NET and WinForms completely and targets a classic Windows API implementation instead.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Login form for driver authentication
|
||||||
|
- Calls the existing auth API on 192.168.68.66:5000
|
||||||
|
- Fetches the daily schedule from 192.168.68.66:5001
|
||||||
|
- Works with Windows XP and older native Windows systems
|
||||||
|
- Uses the WinHTTP API, which is available on XP
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
This uses the MinGW cross-compiler targeting 32-bit Windows.
|
||||||
|
|
||||||
|
## Runtime requirements
|
||||||
|
|
||||||
|
The app expects the following services to be available:
|
||||||
|
|
||||||
|
- auth_api on http://192.168.68.66:5000
|
||||||
|
- transit_api on http://192.168.68.66:5001
|
||||||
|
|
||||||
|
The app intentionally points at the live network host instead of localhost so it works on a Windows XP machine connected to the same LAN.
|
||||||
|
|
||||||
|
## Installer
|
||||||
|
|
||||||
|
A custom Windows installer is the distribution package for XP-era machines. The executable is bundled inside the installer; distribute `TransitDriverXPSetup.exe` rather than the internal `driver_xp.exe`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
makensis installer.nsi
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates `TransitDriverXPSetup.exe`, which installs:
|
||||||
|
|
||||||
|
- `driver_xp.exe`
|
||||||
|
- `README.md`
|
||||||
|
- Start menu shortcut
|
||||||
|
- Desktop shortcut
|
||||||
|
- Uninstaller entry
|
||||||
|
|
||||||
|
When run on a machine with an existing Transit Driver XP installation, the installer
|
||||||
|
reuses the saved installation directory, stops the previous app if it is running,
|
||||||
|
and replaces the installed files with the new version. Existing shortcuts remain in
|
||||||
|
place and point to the updated app.
|
||||||
|
|
||||||
|
The installer is designed for test deployment on a real Windows XP or older Windows machine compatible with native Win32 executables.
|
||||||
@@ -52,30 +52,6 @@ static void SetOutputText(HWND hwnd, const char *text)
|
|||||||
SetWindowTextA(GetDlgItem(hwnd, ID_OUTPUT), text);
|
SetWindowTextA(GetDlgItem(hwnd, ID_OUTPUT), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogDiagnostic(const char *stage, DWORD code)
|
|
||||||
{
|
|
||||||
char path[MAX_PATH];
|
|
||||||
char *separator;
|
|
||||||
FILE *file;
|
|
||||||
|
|
||||||
GetModuleFileNameA(NULL, path, sizeof(path));
|
|
||||||
separator = strrchr(path, '\\');
|
|
||||||
if (separator) {
|
|
||||||
*(separator + 1) = '\0';
|
|
||||||
} else {
|
|
||||||
snprintf(path, sizeof(path), ".\\");
|
|
||||||
}
|
|
||||||
strncat(path, "driver_xp.log", sizeof(path) - strlen(path) - 1);
|
|
||||||
|
|
||||||
file = fopen(path, "a");
|
|
||||||
if (!file) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(file, "%s: %lu\r\n", stage, (unsigned long)code);
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ShowControl(HWND hwnd, int id, int visible)
|
static void ShowControl(HWND hwnd, int id, int visible)
|
||||||
{
|
{
|
||||||
ShowWindow(GetDlgItem(hwnd, id), visible ? SW_SHOW : SW_HIDE);
|
ShowWindow(GetDlgItem(hwnd, id), visible ? SW_SHOW : SW_HIDE);
|
||||||
@@ -354,7 +330,7 @@ static void ExtractScheduleSummary(const char *json, APPSTATE *state, char *out,
|
|||||||
ExtractJsonFieldString(routeText, "lineNumber", routeLine, sizeof(routeLine));
|
ExtractJsonFieldString(routeText, "lineNumber", routeLine, sizeof(routeLine));
|
||||||
ExtractJsonFieldString(routeText, "startTime", routeStartTime, sizeof(routeStartTime));
|
ExtractJsonFieldString(routeText, "startTime", routeStartTime, sizeof(routeStartTime));
|
||||||
ExtractJsonFieldString(routeText, "id", routeLineId, sizeof(routeLineId));
|
ExtractJsonFieldString(routeText, "id", routeLineId, sizeof(routeLineId));
|
||||||
{
|
if (routeLine[0] == '\0' || routeLineId[0] == '\0') {
|
||||||
char busLine[1024];
|
char busLine[1024];
|
||||||
const char *busKey = strstr(routeText, "\"busLine\"");
|
const char *busKey = strstr(routeText, "\"busLine\"");
|
||||||
if (busKey) {
|
if (busKey) {
|
||||||
@@ -540,7 +516,8 @@ static void ExtractTokenFromJson(const char *json, char *outToken, size_t outSiz
|
|||||||
|
|
||||||
static void HttpErrorMessage(const char *context, DWORD error)
|
static void HttpErrorMessage(const char *context, DWORD error)
|
||||||
{
|
{
|
||||||
LogDiagnostic(context, error);
|
(void)context;
|
||||||
|
(void)error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int HttpRequestText(const char *method,
|
static int HttpRequestText(const char *method,
|
||||||
@@ -561,7 +538,6 @@ static int HttpRequestText(const char *method,
|
|||||||
const char *src;
|
const char *src;
|
||||||
const char *slash;
|
const char *slash;
|
||||||
const char *colon;
|
const char *colon;
|
||||||
int secure = 0;
|
|
||||||
int port = 80;
|
int port = 80;
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
DWORD status = 0;
|
DWORD status = 0;
|
||||||
@@ -578,7 +554,6 @@ static int HttpRequestText(const char *method,
|
|||||||
src += 7;
|
src += 7;
|
||||||
} else if (strncmp(src, "https://", 8) == 0) {
|
} else if (strncmp(src, "https://", 8) == 0) {
|
||||||
src += 8;
|
src += 8;
|
||||||
secure = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
host[0] = '\0';
|
host[0] = '\0';
|
||||||
@@ -621,7 +596,7 @@ static int HttpRequestText(const char *method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (host[0] == '\0') {
|
if (host[0] == '\0') {
|
||||||
snprintf(host, sizeof(host), "%s", API_HOST);
|
snprintf(host, sizeof(host), "192.168.68.66");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0) {
|
if (port == 0) {
|
||||||
@@ -658,7 +633,7 @@ static int HttpRequestText(const char *method,
|
|||||||
NULL,
|
NULL,
|
||||||
WINHTTP_NO_REFERER,
|
WINHTTP_NO_REFERER,
|
||||||
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
||||||
secure ? WINHTTP_FLAG_SECURE : 0);
|
0);
|
||||||
if (!hRequest) {
|
if (!hRequest) {
|
||||||
HttpErrorMessage("Unable to open request", GetLastError());
|
HttpErrorMessage("Unable to open request", GetLastError());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -713,7 +688,6 @@ static int HttpRequestText(const char *method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status >= 400) {
|
if (status >= 400) {
|
||||||
LogDiagnostic("HTTP response status", status);
|
|
||||||
snprintf(response, responseSize, "HTTP error %lu", status);
|
snprintf(response, responseSize, "HTTP error %lu", status);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -810,7 +784,7 @@ static void PerformRefresh(HWND hwnd, APPSTATE *state)
|
|||||||
if (date[0] == '\0') {
|
if (date[0] == '\0') {
|
||||||
snprintf(date, sizeof(date), "2026-09-17");
|
snprintf(date, sizeof(date), "2026-09-17");
|
||||||
}
|
}
|
||||||
snprintf(scheduleUrl, sizeof(scheduleUrl), "http://192.168.68.66:5001/driver/schedules/daily?date=%s", date);
|
snprintf(scheduleUrl, sizeof(scheduleUrl), "http://192.168.68.66:5001/schedule/daily?date=%s", date);
|
||||||
SetStatusText(hwnd, "Loading schedule...");
|
SetStatusText(hwnd, "Loading schedule...");
|
||||||
|
|
||||||
if (!HttpRequestText("GET", scheduleUrl, NULL, authHeader, response, sizeof(response))) {
|
if (!HttpRequestText("GET", scheduleUrl, NULL, authHeader, response, sizeof(response))) {
|
||||||
|
|||||||
@@ -1,29 +1,39 @@
|
|||||||
|
; Transit Driver XP custom installer
|
||||||
!include "MUI2.nsh"
|
!include "MUI2.nsh"
|
||||||
|
!include "WinVer.nsh"
|
||||||
|
|
||||||
!define APPNAME "Transit Driver XP"
|
!define APPNAME "Transit Driver XP"
|
||||||
!define COMPANYNAME "Transit Project"
|
!define COMPANYNAME "Transit Project"
|
||||||
!define VERSION "2.0.0"
|
!define DESCRIPTION "Native Windows XP-compatible driver app"
|
||||||
|
!define VERSIONMAJOR 1
|
||||||
|
!define VERSIONMINOR 1
|
||||||
|
!define VERSIONBUILD 0
|
||||||
|
|
||||||
Name "${APPNAME}"
|
Name "${APPNAME}"
|
||||||
OutFile "TransitDriverXPSetup.exe"
|
OutFile "TransitDriverXPSetup.exe"
|
||||||
InstallDir "$PROGRAMFILES\TransitDriverXP"
|
InstallDir "$PROGRAMFILES\TransitDriverXP"
|
||||||
InstallDirRegKey HKCU "Software\TransitDriverXP" "InstallDir"
|
InstallDirRegKey HKCU "Software\TransitDriverXP" "InstallDir"
|
||||||
RequestExecutionLevel admin
|
RequestExecutionLevel admin
|
||||||
VIProductVersion "2.0.0.0"
|
|
||||||
|
VIProductVersion "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0"
|
||||||
VIAddVersionKey "ProductName" "${APPNAME}"
|
VIAddVersionKey "ProductName" "${APPNAME}"
|
||||||
VIAddVersionKey "CompanyName" "${COMPANYNAME}"
|
VIAddVersionKey "CompanyName" "${COMPANYNAME}"
|
||||||
VIAddVersionKey "FileDescription" "Native Windows XP driver client"
|
|
||||||
VIAddVersionKey "FileVersion" "${VERSION}"
|
|
||||||
VIAddVersionKey "ProductVersion" "${VERSION}"
|
|
||||||
VIAddVersionKey "LegalCopyright" "Transit Project"
|
VIAddVersionKey "LegalCopyright" "Transit Project"
|
||||||
|
VIAddVersionKey "FileDescription" "${DESCRIPTION}"
|
||||||
|
VIAddVersionKey "FileVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}"
|
||||||
|
VIAddVersionKey "ProductVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}"
|
||||||
|
|
||||||
Function .onInit
|
Function .onInit
|
||||||
ReadRegStr $0 HKCU "Software\TransitDriverXP" "InstallDir"
|
ReadRegStr $0 HKCU "Software\TransitDriverXP" "InstallDir"
|
||||||
StrCmp $0 "" done
|
StrCmp $0 "" done
|
||||||
|
|
||||||
IfFileExists "$0\driver_xp.exe" 0 done
|
IfFileExists "$0\driver_xp.exe" 0 done
|
||||||
StrCpy $INSTDIR $0
|
StrCpy $INSTDIR $0
|
||||||
MessageBox MB_OK|MB_ICONINFORMATION "An existing Transit Driver XP installation was found. It will be updated."
|
MessageBox MB_OK|MB_ICONINFORMATION "An existing Transit Driver XP installation was found. It will be updated in $INSTDIR."
|
||||||
|
|
||||||
|
; Release the old executable before NSIS replaces it.
|
||||||
ExecWait '"$SYSDIR\taskkill.exe" /F /IM driver_xp.exe'
|
ExecWait '"$SYSDIR\taskkill.exe" /F /IM driver_xp.exe'
|
||||||
|
|
||||||
done:
|
done:
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
@@ -35,14 +45,20 @@ Section "Install"
|
|||||||
SetOutPath "$INSTDIR"
|
SetOutPath "$INSTDIR"
|
||||||
SetOverwrite on
|
SetOverwrite on
|
||||||
File "driver_xp.exe"
|
File "driver_xp.exe"
|
||||||
|
File "README.md"
|
||||||
|
|
||||||
WriteRegStr HKCU "Software\TransitDriverXP" "InstallDir" "$INSTDIR"
|
WriteRegStr HKCU "Software\TransitDriverXP" "InstallDir" "$INSTDIR"
|
||||||
WriteRegStr HKCU "Software\TransitDriverXP" "DisplayName" "${APPNAME}"
|
WriteRegStr HKCU "Software\TransitDriverXP" "DisplayName" "${APPNAME}"
|
||||||
WriteRegStr HKCU "Software\TransitDriverXP" "Version" "${VERSION}"
|
|
||||||
CreateDirectory "$SMPROGRAMS\TransitDriverXP"
|
CreateDirectory "$SMPROGRAMS\TransitDriverXP"
|
||||||
CreateShortCut "$SMPROGRAMS\TransitDriverXP\Transit Driver XP.lnk" "$INSTDIR\driver_xp.exe"
|
CreateShortCut "$SMPROGRAMS\TransitDriverXP\Transit Driver XP.lnk" "$INSTDIR\driver_xp.exe"
|
||||||
CreateShortCut "$DESKTOP\Transit Driver XP.lnk" "$INSTDIR\driver_xp.exe"
|
CreateShortCut "$DESKTOP\Transit Driver XP.lnk" "$INSTDIR\driver_xp.exe"
|
||||||
|
|
||||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
CreateShortCut "$SMPROGRAMS\TransitDriverXP\Uninstall Transit Driver XP.lnk" "$INSTDIR\Uninstall.exe"
|
CreateShortCut "$SMPROGRAMS\TransitDriverXP\Uninstall Transit Driver XP.lnk" "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
; launch after install
|
||||||
|
ExecShell "open" "$INSTDIR\driver_xp.exe"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
@@ -50,8 +66,11 @@ Section "Uninstall"
|
|||||||
Delete "$SMPROGRAMS\TransitDriverXP\Transit Driver XP.lnk"
|
Delete "$SMPROGRAMS\TransitDriverXP\Transit Driver XP.lnk"
|
||||||
Delete "$SMPROGRAMS\TransitDriverXP\Uninstall Transit Driver XP.lnk"
|
Delete "$SMPROGRAMS\TransitDriverXP\Uninstall Transit Driver XP.lnk"
|
||||||
RMDir "$SMPROGRAMS\TransitDriverXP"
|
RMDir "$SMPROGRAMS\TransitDriverXP"
|
||||||
|
|
||||||
Delete "$INSTDIR\driver_xp.exe"
|
Delete "$INSTDIR\driver_xp.exe"
|
||||||
|
Delete "$INSTDIR\README.md"
|
||||||
Delete "$INSTDIR\Uninstall.exe"
|
Delete "$INSTDIR\Uninstall.exe"
|
||||||
RMDir "$INSTDIR"
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
DeleteRegKey HKCU "Software\TransitDriverXP"
|
DeleteRegKey HKCU "Software\TransitDriverXP"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|||||||
Reference in New Issue
Block a user