-
-
Notifications
You must be signed in to change notification settings - Fork 7
feat(HikVisionWebPlugin): add OnInitedAsync parameter #785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| @namespace BootstrapBlazor.Components | ||
| @inherits BootstrapModuleComponentBase | ||
|
|
||
| <div @attributes="AdditionalAttributes" class="@ClassString" id="@Id" style="@StyleString"> | ||
| </div> | ||
| <div @attributes="AdditionalAttributes" class="@ClassString" id="@Id" style="@StyleString"></div> |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,17 +11,20 @@ export async function init(id) { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const el = document.getElementById(id); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (el === null) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const result = await initWindow(id); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (result.inited === false) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| Data.set(id, { | ||||||||||||||||||||||||||||||||||||||||||||||
| iWndIndex: result.iWndIndex | ||||||||||||||||||||||||||||||||||||||||||||||
| iWndIndex: result.iWndIndex, | ||||||||||||||||||||||||||||||||||||||||||||||
| inited: true | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const initWindow = id => { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -30,7 +33,7 @@ const initWindow = id => { | |||||||||||||||||||||||||||||||||||||||||||||
| bWndFull: true, | ||||||||||||||||||||||||||||||||||||||||||||||
| iWndowType: 1, | ||||||||||||||||||||||||||||||||||||||||||||||
| cbSelWnd: function (xmlDoc) { | ||||||||||||||||||||||||||||||||||||||||||||||
| result.iWndIndex = getTagNameFirstValue(xmlDoc, "SelectWnd") | ||||||||||||||||||||||||||||||||||||||||||||||
| result.iWndIndex = parseInt(getTagNameFirstValue(xmlDoc, "SelectWnd")); | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| cbDoubleClickWnd: function (iWndIndex, bFullScreen) { | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -59,6 +62,14 @@ const initWindow = id => { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export async function login(id, ip, port, userName, password, loginType) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const vision = Data.get(id); | ||||||||||||||||||||||||||||||||||||||||||||||
| const { inited, logined } = vision; | ||||||||||||||||||||||||||||||||||||||||||||||
| if (inited !== true || ip.length === 0 || port <= 0 || userName.length === 0 || password.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| if (logined === true) { | ||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| vision.szDeviceIdentify = `${ip}_${port}`; | ||||||||||||||||||||||||||||||||||||||||||||||
| vision.logined = null; | ||||||||||||||||||||||||||||||||||||||||||||||
| vision.loginErrorCode = null; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -84,9 +95,9 @@ export async function login(id, ip, port, userName, password, loginType) { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return new Promise((resolve, reject) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const handler = setInterval(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (vision.logined !== void 0) { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (vision.logined !== null) { | ||||||||||||||||||||||||||||||||||||||||||||||
| clearInterval(handler) | ||||||||||||||||||||||||||||||||||||||||||||||
| resolve(vision); | ||||||||||||||||||||||||||||||||||||||||||||||
| resolve(vision.logined); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }, 16); | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -152,34 +163,27 @@ const getChannelInfo = vision => { | |||||||||||||||||||||||||||||||||||||||||||||
| const handler = setInterval(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (analog_completed && digital_completed && zero_completed) { | ||||||||||||||||||||||||||||||||||||||||||||||
| clearInterval(handler) | ||||||||||||||||||||||||||||||||||||||||||||||
| resolve(vision); | ||||||||||||||||||||||||||||||||||||||||||||||
| resolve(); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }, 16); | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export function logout(id) { | ||||||||||||||||||||||||||||||||||||||||||||||
| export async function logout(id) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const vision = Data.get(id); | ||||||||||||||||||||||||||||||||||||||||||||||
| const { szDeviceIdentify } = vision; | ||||||||||||||||||||||||||||||||||||||||||||||
| const { szDeviceIdentify, logined } = vision; | ||||||||||||||||||||||||||||||||||||||||||||||
| if (logined !== true) { | ||||||||||||||||||||||||||||||||||||||||||||||
| vision.logined = false; | ||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| let completed = null; | ||||||||||||||||||||||||||||||||||||||||||||||
| WebVideoCtrl.I_Logout(szDeviceIdentify).then(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| completed = true; | ||||||||||||||||||||||||||||||||||||||||||||||
| }, () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| completed = false; | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
| stopRealPlay(id); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
| stopRealPlay(id); | |
| await stopRealPlay(id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider replacing the polling-based async handling in startRealPlay/stopRealPlay with direct Promise wrappers around the existing callbacks and returning a consistent Promise API.
The new async handling in startRealPlay / stopRealPlay adds avoidable complexity via polling + shared flags and inconsistent return types. You can keep all current behavior while simplifying by directly wrapping the callback API in Promises and making the API consistently async.
1. Simplify startRealPlay async handling
You don’t need completed + setInterval because I_StartRealPlay already exposes success/error callbacks:
export async function startRealPlay(id, iStreamType, iChannelID) {
const vision = Data.get(id);
const { iWndIndex, szDeviceIdentify } = vision;
vision.devicePort = await WebVideoCtrl.I_GetDevicePort(vision.szDeviceIdentify);
await getChannelInfo(vision);
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
const iRtspPort = vision.devicePort.iRtspPort;
const bZeroChannel = false;
const startRealPlay = () => new Promise(resolve => {
WebVideoCtrl.I_StartRealPlay(szDeviceIdentify, {
iWndIndex,
iStreamType,
iChannelID,
bZeroChannel,
iPort: iRtspPort,
success: () => {
vision.realPlaying = true;
resolve(true);
},
error: () => {
vision.realPlaying = false;
resolve(false);
}
});
});
if (oWndInfo !== null) {
await new Promise(resolve => {
WebVideoCtrl.I_Stop({ success: resolve, error: resolve });
});
}
// preserve boolean success/failure result
return startRealPlay();
}This keeps:
vision.realPlayingupdates- boolean result indicating success/failure
I_Stopbefore restart
but removes the polling loop and shared completed flag.
2. Make stopRealPlay consistently async and remove polling
Currently it sometimes returns true synchronously and sometimes a Promise, and it polls completed. You can keep behavior while returning a Promise<boolean> in all cases:
export function stopRealPlay(id) {
const vision = Data.get(id);
const { iWndIndex, realPlaying } = vision;
if (realPlaying !== true) {
// already stopped
return Promise.resolve(true);
}
const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex);
if (oWndInfo === null) {
vision.realPlaying = false;
return Promise.resolve(true);
}
return new Promise(resolve => {
WebVideoCtrl.I_Stop({
success: () => {
vision.realPlaying = false;
resolve(true);
},
error: () => {
resolve(false);
}
});
});
}This preserves:
vision.realPlayingset tofalseon success- boolean success/failure result
- “already stopped” fast-path
but removes the interval polling and type ambiguity (boolean vs Promise<boolean>).
If you want to keep dispose synchronous, you can still call stopRealPlay(id) without await; the above returns a Promise but callers that don’t care about completion can ignore it.
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This console.log statement should be removed before merging to production. Debug logging statements should not be left in production code.
| console.log(oWndInfo); |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stopRealPlay function is not declared as async but returns a Promise. When the condition realPlaying !== true is met on line 241-243, it returns a boolean true directly instead of a Promise. This creates an inconsistent return type. Either make the function async and use return Promise.resolve(true) for the early return, or wrap the synchronous return in Promise.resolve(true).
| return true; | |
| return Promise.resolve(true); |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If oWndInfo === null on line 247, the completed variable remains null and this Promise will never resolve, causing an infinite polling loop. Consider setting completed = true when oWndInfo === null to handle this case, or return early with a resolved value.
| } | |
| return new Promise((resolve, reject) => { | |
| const handler = setInterval(() => { | |
| if (completed !== null) { | |
| clearInterval(handler) | |
| resolve(completed); | |
| } | |
| }, 16); | |
| }); | |
| return new Promise((resolve, reject) => { | |
| const handler = setInterval(() => { | |
| if (completed !== null) { | |
| clearInterval(handler) | |
| resolve(completed); | |
| } | |
| }, 16); | |
| }); | |
| } else { | |
| // If oWndInfo is null, resolve immediately (not playing) | |
| return Promise.resolve(true); | |
| } |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dispose function calls Data.remove(id) on line 271 before using vision properties on lines 273-279. This could cause issues if other operations need the data. Additionally, stopRealPlay(id) and logout(id) are called after the data is removed, which may cause errors since they both call Data.get(id). Move Data.remove(id) to the end of the function, after all cleanup operations are complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk):
logoutignores the asynchronous result ofstopRealPlay, which may cause races.stopRealPlay(id)now returns aPromise, butlogoutdoes notawaitit. This allowslogoutto continue (including clearinglogined) before playback has actually stopped, and any rejection fromstopRealPlaywill be lost. If the goal is to stop playback before logout completes,await stopRealPlay(id);here and consider handling its boolean result.