Skip to content

Commit

Permalink
Merge pull request #1098 from matrix-org/tilosp-fix-944-2
Browse files Browse the repository at this point in the history
Make sure a killed BridgedClient is dead, even if connect was never called (continuation)
  • Loading branch information
Half-Shot authored Aug 7, 2020
2 parents 2e8e61e + f59a5c0 commit 6c99cef
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 112 deletions.
1 change: 1 addition & 0 deletions changelog.d/1098.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make sure a killed BridgedClient is dead, even if connect was never called
4 changes: 4 additions & 0 deletions spec/util/irc-client-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ function Client(addr, nick, opts) {
return channel.toLowerCase();
}

this.getSplitMessages = function(target, text) {
return [];
}

this.modeForPrefix = {
"@" : "o",
"+" : "v",
Expand Down
15 changes: 6 additions & 9 deletions src/DebugApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { inspect } from "util";
import { DataStore } from "./datastore/DataStore";
import { ClientPool } from "./irc/ClientPool";
import { getLogger } from "./logging";
import { BridgedClient } from "./irc/BridgedClient";
import { BridgedClient, BridgedClientStatus } from "./irc/BridgedClient";
import { IrcBridge } from "./bridge/IrcBridge";
import { ProvisionRequest } from "./provisioning/ProvisionRequest";
import { getBridgeVersion } from "./util/PackageInfo";
Expand Down Expand Up @@ -251,8 +251,7 @@ export class DebugApi {
"User " + user + " does not have a client on " + server.domain + "\n"
);
}
const connection = client.unsafeClient && client.unsafeClient.conn;
if (!client.unsafeClient || !connection) {
if (client.status !== BridgedClientStatus.CONNECTED) {
return Bluebird.resolve(
"There is no underlying client instance.\n"
);
Expand All @@ -261,25 +260,23 @@ export class DebugApi {
// store all received response strings
const buffer: string[] = [];
// "raw" can take many forms
const listener = (msg: object) => {
const listener = (msg: unknown) => {
buffer.push(JSON.stringify(msg));
}

client.unsafeClient.on("raw", listener);
client.addClientListener("raw", listener);
// turn rn to n so if there are any new lines they are all n.
body = body.replace("\r\n", "\n");
body.split("\n").forEach((c: string) => {
// IRC protocol require rn
connection.write(c + "\r\n");
client.writeToConnection(c + "\r\n");
buffer.push(c);
});

// wait 3s to pool responses
return Bluebird.delay(3000).then(function() {
// unhook listener to avoid leaking
if (client.unsafeClient) {
client.unsafeClient.removeListener("raw", listener);
}
client.removeClientListener("raw", listener);
return buffer.join("\n") + "\n";
});
}
Expand Down
6 changes: 1 addition & 5 deletions src/bridge/AdminRoomHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,7 @@ export class AdminRoomHandler {
server, sender
);

if (!bridgedClient.unsafeClient) {
throw new Error('Possibly disconnected');
}

bridgedClient.unsafeClient.send(...sendArgs);
bridgedClient.sendCommands(...sendArgs);
}
catch (err) {
const notice = new MatrixAction("notice", `${err}\n` );
Expand Down
4 changes: 2 additions & 2 deletions src/bridge/IrcBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MatrixHandler } from "./MatrixHandler";
import { MemberListSyncer } from "./MemberListSyncer";
import { IrcServer } from "../irc/IrcServer";
import { ClientPool } from "../irc/ClientPool";
import { BridgedClient } from "../irc/BridgedClient";
import { BridgedClient, BridgedClientStatus } from "../irc/BridgedClient";
import { IrcUser } from "../models/IrcUser";
import { IrcRoom } from "../models/IrcRoom";
import { BridgeRequest, BridgeRequestErr } from "../models/BridgeRequest";
Expand Down Expand Up @@ -984,7 +984,7 @@ export class IrcBridge {
public sendIrcAction(ircRoom: IrcRoom, bridgedClient: BridgedClient, action: IrcAction) {
log.info(
"Sending IRC message in %s as %s (connected=%s)",
ircRoom.channel, bridgedClient.nick, Boolean(bridgedClient.unsafeClient)
ircRoom.channel, bridgedClient.nick, Boolean(bridgedClient.status === BridgedClientStatus.CONNECTED)
);
return bridgedClient.sendAction(ircRoom, action);
}
Expand Down
9 changes: 3 additions & 6 deletions src/bridge/MatrixHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -905,14 +905,11 @@ export class MatrixHandler {
this.eventCache.delete(delKey);
}

// Check for the existance of the getSplitMessages method.
if (!(ircClient.unsafeClient && ircClient.unsafeClient.getSplitMessages)) {
await this.ircBridge.sendIrcAction(ircRoom, ircClient, ircAction);
return;
}
// The client might still be connected, for abundance of safety let's wait.
await ircClient.waitForConnected();

// Generate an array of individual messages that would be sent
const potentialMessages = ircClient.unsafeClient.getSplitMessages(ircRoom.channel, text);
const potentialMessages = ircClient.getSplitMessages(ircRoom.channel, text);
const lineLimit = ircRoom.server.getLineLimit();

if (potentialMessages.length <= lineLimit) {
Expand Down
22 changes: 9 additions & 13 deletions src/bridge/PublicitySyncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,15 @@ export class PublicitySyncer {
};
constructor (private ircBridge: IrcBridge) { }

public initModeForChannel(server: IrcServer, chan: string) {
return this.ircBridge.getBotClient(server).then(
(client) => {
if (!client.unsafeClient) {
throw Error("Can't request modes, bot client not connected")
}
log.info(`Bot requesting mode for ${chan} on ${server.domain}`);
client.unsafeClient.mode(chan);
},
(err) => {
log.error(`Could not request mode of ${chan} (${err.message})`);
}
);
public async initModeForChannel(server: IrcServer, chan: string) {
try {
const botClient = await this.ircBridge.getBotClient(server);
log.info(`Bot requesting mode for ${chan} on ${server.domain}`);
await botClient.mode(chan);
}
catch (err) {
log.error(`Could not request mode of ${chan} (${err.message})`);
}
}

public async initModes (server: IrcServer) {
Expand Down
10 changes: 5 additions & 5 deletions src/bridge/RoomAccessSyncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IrcBridge } from "./IrcBridge";
import { BridgeRequest } from "../models/BridgeRequest";
import { IrcServer } from "../irc/IrcServer";
import { MatrixRoom } from "matrix-appservice-bridge";
import { BridgedClientStatus } from "../irc/BridgedClient";
const log = getLogger("RoomAccessSyncer");

const MODES_TO_WATCH = [
Expand Down Expand Up @@ -114,21 +115,20 @@ export class RoomAccessSyncer {
let userId = null;
if (nick !== null && bridgedClient) {
userId = bridgedClient.userId;
if (!bridgedClient.unsafeClient) {
if (bridgedClient.status !== BridgedClientStatus.CONNECTED) {
req.log.info(`Bridged client for ${nick} has no IRC client.`);
return;
}
const client = bridgedClient.unsafeClient;
const chanData = client.chanData(channel);
const chanData = bridgedClient.chanData(channel);
if (!(chanData && chanData.users)) {
req.log.error(`No channel data for ${channel}`);
return;
}
const userPrefixes = chanData.users[nick] as string;
userPrefixes.split('').forEach(
prefix => {
const m = client.modeForPrefix[prefix];
if (modeToPower[m] !== undefined) {
const m = bridgedClient.modeForPrefix(prefix);
if (m && modeToPower[m] !== undefined) {
userPowers.push(modeToPower[m]);
}
}
Expand Down
Loading

0 comments on commit 6c99cef

Please sign in to comment.