Skip to content

feat(HikVision): hack JSVideoPlugin script prevent throw exception#795

Merged
ArgoZhang merged 4 commits intomasterfrom
fix-hik
Dec 6, 2025
Merged

feat(HikVision): hack JSVideoPlugin script prevent throw exception#795
ArgoZhang merged 4 commits intomasterfrom
fix-hik

Conversation

@ArgoZhang
Copy link
Copy Markdown
Member

@ArgoZhang ArgoZhang commented Dec 6, 2025

Link issues

fixes #794

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Improve HikVision video plugin lifecycle handling to avoid runtime exceptions during resize and destruction and ensure clean shutdown when disposing the control.

Bug Fixes:

  • Prevent JSVideoPlugin resize from throwing when the target DOM element has been removed.
  • Guard JSVideoPlugin destroy logic against sending requests over closed WebSocket connections.
  • Ensure HikVision video playback is stopped before destroying the plugin during disposal.

Enhancements:

  • Hook custom JSVideoPlugin lifecycle patches after the WebVideoCtrl window initialization completes.

Copilot AI review requested due to automatic review settings December 6, 2025 08:39
@bb-auto bb-auto Bot added the enhancement New feature or request label Dec 6, 2025
@bb-auto bb-auto Bot added this to the v9.2.0 milestone Dec 6, 2025
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Dec 6, 2025

Reviewer's Guide

Adds defensive hacks around the HikVision JSVideoPlugin to avoid runtime exceptions during resize and destroy operations, and ensures the plugin is cleanly stopped before destruction.

Sequence diagram for hacked JS_DestroyPlugin shutdown flow

sequenceDiagram
    participant Caller
    participant JSVideoPlugin
    participant oPlugin as Plugin
    participant oRequest as Request
    participant oWebSocket as WebSocket

    Caller->>JSVideoPlugin: JS_DestroyPlugin(n)
    activate JSVideoPlugin
    JSVideoPlugin->>oPlugin: access oRequest
    oPlugin->>oRequest: override sendRequest(r)
    activate oRequest
    Note over oRequest,oWebSocket: New sendRequest checks WebSocket.readyState
    oRequest->>oWebSocket: check readyState
    alt WebSocket is open
        oWebSocket-->>oRequest: OPEN
        oRequest->>oRequest: origianlSendRequestProxy(r)
    else WebSocket not open
        oWebSocket-->>oRequest: not OPEN
        oRequest-->>oRequest: do not send request
    end
    deactivate oRequest
    JSVideoPlugin->>oPlugin: JS_DestroyPlugin(true)
    deactivate JSVideoPlugin
Loading

Sequence diagram for initWindow initialization and plugin hacks

sequenceDiagram
    participant UI as CallerInit
    participant Module as hikvisionModule
    participant WebVideoCtrl

    UI->>Module: init(id)
    activate Module
    Module->>Module: initWindow(id)
    activate WebVideoCtrl
    WebVideoCtrl->>WebVideoCtrl: I_InitPlugin(options)
    WebVideoCtrl-->>Module: callback(result.inited, result.iWndIndex)
    deactivate WebVideoCtrl
    Module->>Module: poll with setInterval
    alt inited false or inited and iWndIndex != -1
        Module->>Module: clearInterval(handler)
        Module->>Module: hackJSResize()
        Module->>Module: hackJSDestroyPlugin()
        Module-->>UI: resolve(result)
    end
    deactivate Module
Loading

Sequence diagram for dispose with explicit stop before destroy

sequenceDiagram
    participant UI as CallerDispose
    participant Module as hikvisionModule
    participant WebVideoCtrl

    UI->>Module: dispose(id)
    activate Module
    alt logined is true
        Module->>Module: logout(id)
    end
    Module->>WebVideoCtrl: I_Stop()
    Module->>WebVideoCtrl: I_DestroyPlugin()
    deactivate Module
Loading

Class diagram for JSVideoPlugin hacks and related objects

classDiagram
    class JSVideoPlugin {
        oOptions
        oPlugin
        JS_Resize(e, t)
        JS_DestroyPlugin(n)
    }

    class Plugin {
        oRequest
        JS_DestroyPlugin(force)
    }

    class RequestRoot {
        oRequest
    }

    class RequestInner {
        oWebSocket
        sendRequest(r)
    }

    class WebSocket {
        readyState
    }

    JSVideoPlugin *-- Plugin : oPlugin
    Plugin *-- RequestRoot : oRequest
    RequestRoot *-- RequestInner : oRequest
    RequestInner *-- WebSocket : oWebSocket
Loading

File-Level Changes

Change Details Files
Wrap JSVideoPlugin resize and destroy behaviors with safety checks to prevent errors when DOM elements or WebSocket connections are unavailable.
  • Stop loading the legacy jsVideoPlugin script directly and rely on webVideoCtrl.js (which loads/uses JSVideoPlugin) instead.
  • Introduce hackJSResize to override JSVideoPlugin.prototype.JS_Resize so it only calls the original method when the target DOM element still exists.
  • Introduce hackJSDestroyPlugin to override JSVideoPlugin.prototype.JS_DestroyPlugin, guarding internal WebSocket request sending and forcing a safe destroy call.
src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js
Adjust plugin initialization and teardown to apply the hacks at the right time and ensure the plugin stops before destruction.
  • After WebVideoCtrl initialization polling completes, invoke hackJSResize and hackJSDestroyPlugin once the window is ready.
  • In dispose(id), explicitly call WebVideoCtrl.I_Stop() before WebVideoCtrl.I_DestroyPlugin() to ensure playback is stopped before plugin destruction.
src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js

Assessment against linked issues

Issue Objective Addressed Explanation
#794 Modify the HikVision integration to hack/wrap JSVideoPlugin behavior so that it no longer throws exceptions during plugin lifecycle operations (e.g., resize, destroy) while keeping existing functionality.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • The monkey-patch helpers hackJSResize and hackJSDestroyPlugin assume JSVideoPlugin is defined; consider guarding them (e.g., if (!window.JSVideoPlugin) return;) to avoid new runtime errors when the plugin script fails to load or changes its global name.
  • In hackJSDestroyPlugin, the override ignores the original n argument and calls this.oPlugin.JS_DestroyPlugin(true) directly; if the original method relied on the argument, this may change behavior—consider delegating to originalDestroy.call(this, n) after wrapping sendRequest instead of hard-coding true.
  • The new override of sendRequest inside hackJSDestroyPlugin is never restored and also contains a typo in origianlSendRequestProxy; it would be safer to cache and restore the original function (and fix the spelling) to avoid permanently altering the request behavior beyond the destroy lifecycle.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The monkey-patch helpers `hackJSResize` and `hackJSDestroyPlugin` assume `JSVideoPlugin` is defined; consider guarding them (e.g., `if (!window.JSVideoPlugin) return;`) to avoid new runtime errors when the plugin script fails to load or changes its global name.
- In `hackJSDestroyPlugin`, the override ignores the original `n` argument and calls `this.oPlugin.JS_DestroyPlugin(true)` directly; if the original method relied on the argument, this may change behavior—consider delegating to `originalDestroy.call(this, n)` after wrapping `sendRequest` instead of hard-coding `true`.
- The new override of `sendRequest` inside `hackJSDestroyPlugin` is never restored and also contains a typo in `origianlSendRequestProxy`; it would be safer to cache and restore the original function (and fix the spelling) to avoid permanently altering the request behavior beyond the destroy lifecycle.

## Individual Comments

### Comment 1
<location> `src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js:38-47` </location>
<code_context>
+    }
+}
+
+const hackJSDestroyPlugin = function () {
+    const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;
+    JSVideoPlugin.prototype.JS_DestroyPlugin = function (n) {
+        const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
+        this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
+            if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
+                return origianlSendRequestProxy.call(this, r);
+            }
+        }
+        return this.oPlugin.JS_DestroyPlugin(true);
+    }
+}
</code_context>

<issue_to_address>
**issue (bug_risk):** Overriding `JS_DestroyPlugin` bypasses the original implementation and ignores its arguments.

This override replaces `JSVideoPlugin.prototype.JS_DestroyPlugin` without ever calling `originalDestroy`, and it always invokes `this.oPlugin.JS_DestroyPlugin(true)` regardless of `n`. This changes the method’s contract and may break callers or future upstream changes that depend on the argument. Please preserve the original behavior by delegating to `originalDestroy` with the original arguments (potentially after wrapping `sendRequest`).
</issue_to_address>

### Comment 2
<location> `src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js:79-80` </location>
<code_context>
             if (result.inited === false || (result.inited && result.iWndIndex !== -1)) {
-                clearInterval(handler)
+                clearInterval(handler);
+                hackJSResize();
+                hackJSDestroyPlugin();
                 resolve(result);
             }
</code_context>

<issue_to_address>
**suggestion:** Prototype hacks are applied every time `initWindow` resolves, which can repeatedly reassign the same methods.

`hackJSResize` and `hackJSDestroyPlugin` patch `JSVideoPlugin.prototype`, and `initWindow` can run multiple times, causing the same prototype methods to be reassigned on each successful init. This adds unnecessary repetition and makes it harder to see when the patch is applied. Consider a module-level guard (e.g. `let jsPluginPatched = false`) so the prototype is patched only once.

Suggested implementation:

```javascript
}

let jsPluginPatched = false;

const initWindow = id => {

```

```javascript
            if (result.inited === false || (result.inited && result.iWndIndex !== -1)) {
                clearInterval(handler);
                if (!jsPluginPatched) {
                    hackJSResize();
                    hackJSDestroyPlugin();
                    jsPluginPatched = true;
                }
                resolve(result);
            }

```
</issue_to_address>

### Comment 3
<location> `src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js:28` </location>
<code_context>
     return true;
 }

+const hackJSResize = function () {
+    const originalResize = JSVideoPlugin.prototype.JS_Resize;
+    JSVideoPlugin.prototype.JS_Resize = function (e, t) {
</code_context>

<issue_to_address>
**issue (complexity):** Consider consolidating the plugin monkey-patching into a single idempotent function, while cleaning up naming and unused imports to keep the code simpler and clearer.

You can reduce the added complexity by centralizing and making the plugin patching idempotent, and by simplifying the destroy override.

### 1. Consolidate monkey‑patching into a single, idempotent function

Instead of `hackJSResize` and `hackJSDestroyPlugin` being called on every init loop resolution, create a single `patchJSVideoPluginOnce` that:

- Patches both `JS_Resize` and `JS_DestroyPlugin`.
- Guards against multiple executions.
- Does the `sendRequest` guarding at patch time instead of per‑destroy call.

```js
let jsVideoPluginPatched = false;

function patchJSVideoPluginOnce() {
    if (jsVideoPluginPatched || typeof JSVideoPlugin === 'undefined') return;
    jsVideoPluginPatched = true;

    const originalResize = JSVideoPlugin.prototype.JS_Resize;
    JSVideoPlugin.prototype.JS_Resize = function (e, t) {
        const { szId } = this.oOptions;
        if (document.getElementById(szId)) {
            return originalResize.call(this, e, t);
        }
        // silently ignore if element no longer exists (current behavior)
    };

    const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;
    JSVideoPlugin.prototype.JS_DestroyPlugin = function (n) {
        const request = this.oPlugin?.oRequest?.oRequest;
        if (request && !request._sendRequestPatched) {
            const originalSendRequest = request.sendRequest;
            request._sendRequestPatched = true;

            request.sendRequest = function (r) {
                if (this.oWebSocket && this.oWebSocket.readyState === WebSocket.OPEN) {
                    return originalSendRequest.call(this, r);
                }
                // ignore when WebSocket is not open (current behavior)
            };
        }

        // preserve the new behavior of forcing `true`
        return originalDestroy.call(this, true);
    };
}
```

Then call it once when the plugin is ready (keeping the same lifecycle point), but without re‑patching on every init:

```js
return new Promise((resolve, reject) => {
    const handler = setInterval(() => {
        if (result.inited === false || (result.inited && result.iWndIndex !== -1)) {
            clearInterval(handler);
            patchJSVideoPluginOnce();
            resolve(result);
        }
    }, 16);
});
```

This keeps all current behavior (resize guarded by DOM presence, destroy guarded by WebSocket state, `true` passed to destroy) but:

- Removes multiple patch functions and call sites.
- Ensures prototype mutations only happen once.
- Avoids reassigning `sendRequest` on every destroy.

### 2. Fix naming/typo to reduce cognitive load

While you’re touching this code, correct the variable typo when you move it:

```js
const originalSendRequest = request.sendRequest;
```

### 3. Remove unused import

If `registerBootstrapBlazorModule` is not used, drop it to avoid unnecessary noise:

```js
- import { addScript, registerBootstrapBlazorModule } from '../BootstrapBlazor/modules/utility.js';
+ import { addScript } from '../BootstrapBlazor/modules/utility.js';
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +38 to +47
const hackJSDestroyPlugin = function () {
const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;
JSVideoPlugin.prototype.JS_DestroyPlugin = function (n) {
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
}
}
return this.oPlugin.JS_DestroyPlugin(true);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Overriding JS_DestroyPlugin bypasses the original implementation and ignores its arguments.

This override replaces JSVideoPlugin.prototype.JS_DestroyPlugin without ever calling originalDestroy, and it always invokes this.oPlugin.JS_DestroyPlugin(true) regardless of n. This changes the method’s contract and may break callers or future upstream changes that depend on the argument. Please preserve the original behavior by delegating to originalDestroy with the original arguments (potentially after wrapping sendRequest).

Comment on lines +79 to +80
hackJSResize();
hackJSDestroyPlugin();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Prototype hacks are applied every time initWindow resolves, which can repeatedly reassign the same methods.

hackJSResize and hackJSDestroyPlugin patch JSVideoPlugin.prototype, and initWindow can run multiple times, causing the same prototype methods to be reassigned on each successful init. This adds unnecessary repetition and makes it harder to see when the patch is applied. Consider a module-level guard (e.g. let jsPluginPatched = false) so the prototype is patched only once.

Suggested implementation:

}

let jsPluginPatched = false;

const initWindow = id => {
            if (result.inited === false || (result.inited && result.iWndIndex !== -1)) {
                clearInterval(handler);
                if (!jsPluginPatched) {
                    hackJSResize();
                    hackJSDestroyPlugin();
                    jsPluginPatched = true;
                }
                resolve(result);
            }

@ArgoZhang ArgoZhang merged commit bdbd944 into master Dec 6, 2025
2 checks passed
@ArgoZhang ArgoZhang deleted the fix-hik branch December 6, 2025 08:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes exception handling issues in the HikVision video plugin integration by adding protective wrapper functions ("hacks") around the JSVideoPlugin methods. The changes prevent errors when the plugin attempts to resize or destroy elements that no longer exist in the DOM.

  • Removes redundant manual loading of jsVideoPlugin-1.0.0.min.js (already loaded by webVideoCtrl.js)
  • Adds defensive wrappers for JS_Resize and JS_DestroyPlugin methods to prevent exceptions
  • Adds WebVideoCtrl.I_Stop() call in dispose function to ensure proper cleanup
  • Bumps version from 10.0.0-beta05 to 10.0.0

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js Adds protective wrapper functions to prevent exceptions during resize and destroy operations, removes redundant script loading, and adds explicit stop call in dispose
src/components/BootstrapBlazor.HikVision/BootstrapBlazor.HikVision.csproj Updates version from beta05 to stable 10.0.0 release

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +79 to +80
hackJSResize();
hackJSDestroyPlugin();
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hack functions are called unconditionally, even when result.inited === false. Consider only applying these hacks when initialization succeeds to avoid potential errors when the plugin is not properly initialized.

Suggested change
hackJSResize();
hackJSDestroyPlugin();
if (result.inited === true) {
hackJSResize();
hackJSDestroyPlugin();
}

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +36
const hackJSResize = function () {
const originalResize = JSVideoPlugin.prototype.JS_Resize;
JSVideoPlugin.prototype.JS_Resize = function (e, t) {
const { szId } = this.oOptions;
if (document.getElementById(szId)) {
return originalResize.call(this, e, t);
}
}
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider checking if JSVideoPlugin exists before attempting to hack its prototype. If the script is not loaded, this could throw a ReferenceError.

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +49
const hackJSDestroyPlugin = function () {
const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;
JSVideoPlugin.prototype.JS_DestroyPlugin = function (n) {
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
}
}
return this.oPlugin.JS_DestroyPlugin(true);
}
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider checking if JSVideoPlugin exists before attempting to hack its prototype. If the script is not loaded, this could throw a ReferenceError.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +44
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in variable name: origianlSendRequestProxy should be originalSendRequestProxy. The letter 'a' and 'l' are swapped.

Suggested change
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
const originalSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return originalSendRequestProxy.call(this, r);

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +44
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in variable name: origianlSendRequestProxy should be originalSendRequestProxy. The letter 'a' and 'l' are swapped (same typo as line 41).

Suggested change
const origianlSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
const originalSendRequestProxy = this.oPlugin.oRequest.oRequest.sendRequest;
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return originalSendRequestProxy.call(this, r);

Copilot uses AI. Check for mistakes.
const { szId } = this.oOptions;
if (document.getElementById(szId)) {
return originalResize.call(this, e, t);
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hacked JS_Resize function doesn't return anything when the element is not found. This could lead to unexpected behavior for callers expecting a return value. Consider returning a default value or explicitly returning undefined.

Suggested change
}
}
return undefined;

Copilot uses AI. Check for mistakes.
this.oPlugin.oRequest.oRequest.sendRequest = function (r) {
if (this.oWebSocket && WebSocket.OPEN === this.oWebSocket.readyState) {
return origianlSendRequestProxy.call(this, r);
}
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hacked sendRequest function doesn't return anything when the WebSocket is not open. This could lead to unexpected behavior for callers expecting a return value. Consider returning a default value or explicitly handling this case.

Suggested change
}
}
// Explicitly return a default value when WebSocket is not open
return null;

Copilot uses AI. Check for mistakes.
@@ -1,8 +1,7 @@
import { addScript } from '../BootstrapBlazor/modules/utility.js';
import { addScript, registerBootstrapBlazorModule } from '../BootstrapBlazor/modules/utility.js';
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import registerBootstrapBlazorModule.

Suggested change
import { addScript, registerBootstrapBlazorModule } from '../BootstrapBlazor/modules/utility.js';
import { addScript } from '../BootstrapBlazor/modules/utility.js';

Copilot uses AI. Check for mistakes.
}

const hackJSDestroyPlugin = function () {
const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable originalDestroy.

Suggested change
const originalDestroy = JSVideoPlugin.prototype.JS_DestroyPlugin;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(HikVision): hack JSVideoPlugin script prevent throw exception

2 participants