Skip to content

#1366 Buffer events from BoardListWatchResponse #1379

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arduino-ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"dateformat": "^3.0.3",
"deepmerge": "2.0.1",
"electron-updater": "^4.6.5",
"fast-json-stable-stringify": "^2.0.0",
"fast-safe-stringify": "^2.1.1",
"glob": "^7.1.6",
"google-protobuf": "^3.20.1",
Expand Down
11 changes: 10 additions & 1 deletion arduino-ide-extension/src/common/protocol/boards-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ import { Searchable } from './searchable';
import { Installable } from './installable';
import { ArduinoComponent } from './arduino-component';
import { nls } from '@theia/core/lib/common/nls';
import URI from '@theia/core/lib/common/uri';
import {
All,
Contributed,
Partner,
Type as TypeLabel,
Updatable,
} from '../nls';
import URI from '@theia/core/lib/common/uri';
import stableJsonStringify = require('fast-json-stable-stringify');

/**
* Keys come from `Port#keyOf`.
*/
export type AvailablePorts = Record<string, [Port, Array<Board>]>;
export namespace AvailablePorts {
export function groupByProtocol(
Expand Down Expand Up @@ -44,6 +48,11 @@ export namespace AvailablePorts {
ports: availablePorts,
};
}
export function sameAs(left: AvailablePorts, right: AvailablePorts): boolean {
return (
left === right || stableJsonStringify(left) === stableJsonStringify(right)
);
}
}

export interface AttachedBoardsChangeEvent {
Expand Down
141 changes: 88 additions & 53 deletions arduino-ide-extension/src/node/board-discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Disposable } from '@theia/core/lib/common/disposable';
import { v4 } from 'uuid';
import { Unknown } from '../common/nls';
import {
AttachedBoardsChangeEvent,
AvailablePorts,
Board,
NotificationServiceServer,
Expand Down Expand Up @@ -251,57 +250,14 @@ export class BoardDiscovery
return;
}

const detectedPort = resp.getPort();
if (detectedPort) {
const { port, boards } = this.fromRpc(detectedPort);
if (!port) {
if (!!boards.length) {
console.warn(
`Could not detect the port, but unexpectedly received discovered boards. This is most likely a bug! Response was: ${this.toJson(
resp
)}`
);
}
return;
}
const oldState = deepClone(this._availablePorts);
const newState = deepClone(this._availablePorts);
const key = Port.keyOf(port);

if (eventType === EventType.Add) {
if (newState[key]) {
const [, knownBoards] = newState[key];
this.logger.warn(
`Port '${Port.toString(
port
)}' was already available. Known boards before override: ${JSON.stringify(
knownBoards
)}`
);
}
newState[key] = [port, boards];
} else if (eventType === EventType.Remove) {
if (!newState[key]) {
this.logger.warn(
`Port '${Port.toString(port)}' was not available. Skipping`
);
return;
}
delete newState[key];
}

const event: AttachedBoardsChangeEvent = {
oldState: {
...AvailablePorts.split(oldState),
},
newState: {
...AvailablePorts.split(newState),
},
uploadInProgress: this.uploadInProgress,
};

this._availablePorts = newState;
this.notificationService.notifyAttachedBoardsDidChange(event);
const rpcDetectedPort = resp.getPort();
if (rpcDetectedPort) {
const detectedPort = this.fromRpc(rpcDetectedPort);
this.fireSoon({ detectedPort, eventType });
} else if (resp.getError()) {
this.logger.error(
`Could not extract any detected 'port' from the board list watch response. An 'error' has occurred: ${resp.getError()}`
);
}
}

Expand Down Expand Up @@ -332,6 +288,75 @@ export class BoardDiscovery
};
return port;
}

private fireSoonHandle?: NodeJS.Timeout;
private bufferedEvents: DetectedPortChangeEvent[] = [];
private fireSoon(event: DetectedPortChangeEvent): void {
this.bufferedEvents.push(event);
clearTimeout(this.fireSoonHandle);
this.fireSoonHandle = setTimeout(() => {
const prevState = deepClone(this.availablePorts);
const newState = this.calculateNewState(this.bufferedEvents, prevState);
if (!AvailablePorts.sameAs(prevState, newState)) {
this._availablePorts = newState;
this.notificationService.notifyAttachedBoardsDidChange({
newState: AvailablePorts.split(newState),
oldState: AvailablePorts.split(prevState),
uploadInProgress: this.uploadInProgress,
});
}
this.bufferedEvents.length = 0;
}, 100);
}

private calculateNewState(
events: DetectedPortChangeEvent[],
prevState: AvailablePorts
): AvailablePorts {
const newState = deepClone(prevState);
for (const { detectedPort, eventType } of events) {
if (!DetectedPort.hasPort(detectedPort)) {
if (!!detectedPort.boards.length) {
console.warn(
`Could not detect the port, but unexpectedly received discovered boards. This is most likely a bug! Detected port was: ${JSON.stringify(
detectedPort
)}`
);
} else {
console.warn(
`Could not detect the port. Skipping: ${JSON.stringify(
detectedPort
)}`
);
}
continue;
}
const { port, boards } = detectedPort;
const key = Port.keyOf(port);
if (eventType === EventType.Add) {
const alreadyDetectedPort = newState[key];
if (alreadyDetectedPort) {
console.warn(
`Detected a new port that has been already discovered. The old value will be overridden. Old value: ${JSON.stringify(
alreadyDetectedPort
)}, new value: ${JSON.stringify(detectedPort)}`
);
}
newState[key] = [port, boards];
} else if (eventType === EventType.Remove) {
const alreadyDetectedPort = newState[key];
if (!alreadyDetectedPort) {
console.warn(
`Detected a port removal but it has not been discovered. This is most likely a bug! Detected port was: ${JSON.stringify(
detectedPort
)}`
);
}
delete newState[key];
}
}
return newState;
}
}

enum EventType {
Expand All @@ -356,8 +381,18 @@ namespace EventType {
}
}
}

interface DetectedPort {
port: Port | undefined;
boards: Board[];
}
namespace DetectedPort {
export function hasPort(
detectedPort: DetectedPort
): detectedPort is DetectedPort & { port: Port } {
return !!detectedPort.port;
}
}
interface DetectedPortChangeEvent {
detectedPort: DetectedPort;
eventType: EventType.Add | EventType.Remove;
}