qemu: fix qmp disconnection semi properly
this is actually something i need to push to crusttest as well, because this will affect it as well, though not as badly because it will only break certain buttons
This commit is contained in:
@@ -207,21 +207,26 @@ export class QemuVM extends EventEmitter {
|
|||||||
if (!this.qmpConnected) {
|
if (!this.qmpConnected) {
|
||||||
self.qmpInstance = new QmpClient();
|
self.qmpInstance = new QmpClient();
|
||||||
|
|
||||||
self.qmpInstance.on('close', async () => {
|
let onQmpError = async (err: Error|undefined) => {
|
||||||
self.qmpConnected = false;
|
self.qmpConnected = false;
|
||||||
|
|
||||||
// If we aren't stopping, then we do actually need to care QMP disconnected
|
// If we aren't stopping, then we do actually need to care QMP disconnected
|
||||||
if (self.state != VMState.Stopping) {
|
if (self.state != VMState.Stopping) {
|
||||||
|
//if(err !== undefined) // This doesn't show anything useful or maybe I'm just stupid idk
|
||||||
|
// self.VMLog().Error(`Error: ${err!}`)
|
||||||
if (self.qmpFailCount++ < kMaxFailCount) {
|
if (self.qmpFailCount++ < kMaxFailCount) {
|
||||||
this.VMLog().Error(`Failed to connect to QMP ${self.qmpFailCount} times`);
|
self.VMLog().Error(`Failed to connect to QMP ${self.qmpFailCount} times.`);
|
||||||
await Shared.Sleep(500);
|
await Shared.Sleep(500);
|
||||||
await self.ConnectQmp();
|
await self.ConnectQmp();
|
||||||
} else {
|
} else {
|
||||||
this.VMLog().Error(`Failed to connect to QMP ${self.qmpFailCount} times, giving up`);
|
self.VMLog().Error(`Reached max retries, giving up.`);
|
||||||
await self.Stop();
|
await self.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
self.qmpInstance.on('close', onQmpError);
|
||||||
|
self.qmpInstance.on('error', onQmpError);
|
||||||
|
|
||||||
self.qmpInstance.on('event', async (ev) => {
|
self.qmpInstance.on('event', async (ev) => {
|
||||||
switch (ev.event) {
|
switch (ev.event) {
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ export default class QmpClient extends Socket {
|
|||||||
private commandEntries: QmpCommandEntry[] = [];
|
private commandEntries: QmpCommandEntry[] = [];
|
||||||
private lastID = 0;
|
private lastID = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.assignHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
private ExecuteSync(command: string, args: any | null, callback: QmpCallback | null) {
|
private ExecuteSync(command: string, args: any | null, callback: QmpCallback | null) {
|
||||||
let cmd: QmpCommandEntry = {
|
let cmd: QmpCommandEntry = {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
@@ -65,71 +71,60 @@ export default class QmpClient extends Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this can probably be made async
|
// this can probably be made async
|
||||||
private ConnectImpl() {
|
private assignHandlers() {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
this.once('connect', () => {
|
this.on('connect', () => {
|
||||||
this.removeAllListeners('error');
|
// this should be more correct?
|
||||||
});
|
this.once('data', (data) => {
|
||||||
|
// Handshake QMP with the server.
|
||||||
|
self.qmpHandshakeData = JSON.parse(data.toString('utf8')).QMP;
|
||||||
|
self.Handshake(() => {
|
||||||
|
// Now ready to parse QMP responses/events.
|
||||||
|
self.pipe(split(JSON.parse))
|
||||||
|
.on('data', (json: any) => {
|
||||||
|
if (json == null) return self.end();
|
||||||
|
|
||||||
this.once('error', (err) => {
|
if (json.return || json.error) {
|
||||||
// just rethrow lol
|
// Our handshake has a spurious return because we never assign it an ID,
|
||||||
//throw err;
|
// and it is gathered by this pipe for some reason I'm not quite sure about.
|
||||||
|
// So, just for safety's sake, don't process any return objects which don't have an ID attached to them.
|
||||||
|
if (json.id == null) return;
|
||||||
|
|
||||||
console.log('you have pants: rules,', err);
|
let callbackEntry = this.commandEntries.find((entry) => entry.id === json.id);
|
||||||
});
|
let error: Error | null = json.error ? new Error(json.error.desc) : null;
|
||||||
|
|
||||||
this.once('data', (data) => {
|
// we somehow didn't find a callback entry for this response.
|
||||||
// Handshake QMP with the server.
|
// I don't know how. Techinically not an error..., but I guess you're not getting a reponse to whatever causes this to happen
|
||||||
self.qmpHandshakeData = JSON.parse(data.toString('utf8')).QMP;
|
if (callbackEntry == null) return;
|
||||||
self.Handshake(() => {
|
|
||||||
// Now ready to parse QMP responses/events.
|
|
||||||
self.pipe(split(JSON.parse))
|
|
||||||
.on('data', (json: any) => {
|
|
||||||
if (json == null) return self.end();
|
|
||||||
|
|
||||||
if (json.return || json.error) {
|
if (callbackEntry?.callback) callbackEntry.callback(error, json.return);
|
||||||
// Our handshake has a spurious return because we never assign it an ID,
|
|
||||||
// and it is gathered by this pipe for some reason I'm not quite sure about.
|
|
||||||
// So, just for safety's sake, don't process any return objects which don't have an ID attached to them.
|
|
||||||
if (json.id == null) return;
|
|
||||||
|
|
||||||
let callbackEntry = this.commandEntries.find((entry) => entry.id === json.id);
|
// Remove the completed callback entry.
|
||||||
let error: Error | null = json.error ? new Error(json.error.desc) : null;
|
this.commandEntries.slice(this.commandEntries.indexOf(callbackEntry));
|
||||||
|
} else if (json.event) {
|
||||||
// we somehow didn't find a callback entry for this response.
|
this.emit('event', json);
|
||||||
// I don't know how. Techinically not an error..., but I guess you're not getting a reponse to whatever causes this to happen
|
}
|
||||||
if (callbackEntry == null) return;
|
})
|
||||||
|
.on('error', () => {
|
||||||
if (callbackEntry?.callback) callbackEntry.callback(error, json.return);
|
// Give up.
|
||||||
|
return self.end();
|
||||||
// Remove the completed callback entry.
|
});
|
||||||
this.commandEntries.slice(this.commandEntries.indexOf(callbackEntry));
|
this.emit('qmp-ready');
|
||||||
} else if (json.event) {
|
});
|
||||||
this.emit('event', json);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('error', () => {
|
|
||||||
// Give up.
|
|
||||||
return self.end();
|
|
||||||
});
|
|
||||||
this.emit('qmp-ready');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.once('close', () => {
|
this.on('close', () => {
|
||||||
this.end();
|
this.end();
|
||||||
this.removeAllListeners('data'); // wow. good job bud. cool memory leak
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Connect(host: string, port: number) {
|
Connect(host: string, port: number) {
|
||||||
super.connect(port, host);
|
super.connect(port, host);
|
||||||
this.ConnectImpl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectUNIX(path: string) {
|
ConnectUNIX(path: string) {
|
||||||
super.connect(path);
|
super.connect(path);
|
||||||
this.ConnectImpl();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user