Socket
Socket
Sign inDemoInstall

mx-puppet-bridge

Package Overview
Dependencies
299
Maintainers
1
Versions
112
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.3 to 0.1.4

6

lib/src/config.d.ts

@@ -5,2 +5,3 @@ export declare class Config {

database: DatabaseConfig;
metrics: MetricsConfig;
provisioning: ProvisioningConfig;

@@ -55,2 +56,7 @@ presence: PresenceConfig;

}
export declare class MetricsConfig {
enabled: boolean;
port: number;
path: string;
}
export declare class DatabaseConfig {

@@ -57,0 +63,0 @@ connString: string;

@@ -22,2 +22,3 @@ "use strict";

this.database = new DatabaseConfig();
this.metrics = new MetricsConfig();
this.provisioning = new ProvisioningConfig();

@@ -83,2 +84,10 @@ this.presence = new PresenceConfig();

exports.LoggingFileConfig = LoggingFileConfig;
class MetricsConfig {
constructor() {
this.enabled = false;
this.port = 8000;
this.path = "/metrics";
}
}
exports.MetricsConfig = MetricsConfig;
class DatabaseConfig {

@@ -85,0 +94,0 @@ constructor() {

2

lib/src/db/connector.d.ts

@@ -0,1 +1,2 @@

import * as prometheus from "prom-client";
declare type SQLTYPES = number | boolean | string | null;

@@ -10,2 +11,3 @@ export interface ISqlCommandParameters {

type: string;
latency: prometheus.Histogram<string>;
Open(): void;

@@ -12,0 +14,0 @@ Get(sql: string, parameters?: ISqlCommandParameters): Promise<ISqlRow | null>;

4

lib/src/db/emotestore.d.ts

@@ -5,3 +5,4 @@ import { IDatabaseConnector } from "./connector";

private db;
constructor(db: IDatabaseConnector);
private protocol;
constructor(db: IDatabaseConnector, protocol?: string);
newData(puppetId: number, roomId: string | null, emoteId: string): IEmoteStoreEntry;

@@ -13,2 +14,3 @@ get(puppetId: number, roomId: string | null, emoteId: string): Promise<IEmoteStoreEntry | null>;

private getFromRow;
private labels;
}

@@ -27,4 +27,5 @@ "use strict";

class DbEmoteStore {
constructor(db) {
constructor(db, protocol = "unknown") {
this.db = db;
this.protocol = protocol;
}

@@ -45,2 +46,3 @@ newData(puppetId, roomId, emoteId) {

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
if (roomId) {

@@ -52,2 +54,3 @@ const row = yield this.db.Get("SELECT * FROM emote_store WHERE puppet_id = $pid AND room_id = $rid AND emote_id = $eid LIMIT 1", {

});
stopTimer();
return this.getFromRow(row);

@@ -60,2 +63,3 @@ }

});
stopTimer();
return this.getFromRow(row);

@@ -67,2 +71,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxc"));
if (roomId) {

@@ -74,2 +79,3 @@ const row = yield this.db.Get("SELECT * FROM emote_store WHERE puppet_id = $pid AND room_id = $rid AND avatar_mxc = $mxid LIMIT 1", {

});
stopTimer();
return this.getFromRow(row);

@@ -82,2 +88,3 @@ }

});
stopTimer();
return this.getFromRow(row);

@@ -89,2 +96,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_room"));
const rows = yield this.db.All("SELECT * FROM emote_store WHERE puppet_id = $pid AND room_id = $rid", {

@@ -101,2 +109,3 @@ pid: puppetId,

}
stopTimer();
return result;

@@ -107,2 +116,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
let exists = null;

@@ -165,2 +175,3 @@ if (data.roomId) {

});
stopTimer();
});

@@ -183,3 +194,11 @@ }

}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "emote_store",
type: queryName,
};
}
}
exports.DbEmoteStore = DbEmoteStore;
import { IDatabaseConnector } from "./connector";
export declare class DbEventStore {
private db;
constructor(db: IDatabaseConnector);
private protocol;
constructor(db: IDatabaseConnector, protocol?: string);
insert(puppetId: number, roomId: string, matrixId: string, remoteId: string): Promise<void>;

@@ -9,2 +10,3 @@ remove(puppetId: number, roomId: string, remoteId: string): Promise<void>;

getRemote(puppetId: number, roomId: string, matrixId: string): Promise<string[]>;
private labels;
}

@@ -27,7 +27,9 @@ "use strict";

class DbEventStore {
constructor(db) {
constructor(db, protocol = "unknown") {
this.db = db;
this.protocol = protocol;
}
insert(puppetId, roomId, matrixId, remoteId) {
return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
yield this.db.Run("INSERT INTO event_store (puppet_id, room_id, matrix_id, remote_id) VALUES ($p, $room, $m, $r)", {

@@ -39,2 +41,3 @@ p: puppetId,

});
stopTimer();
});

@@ -44,2 +47,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("remove"));
yield this.db.Run("DELETE FROM event_store WHERE puppet_id = $p AND room_id = $room AND remote_id = $r", {

@@ -50,2 +54,3 @@ p: puppetId,

});
stopTimer();
});

@@ -55,2 +60,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_matrix"));
const result = [];

@@ -65,2 +71,3 @@ const rows = yield this.db.All("SELECT * FROM event_store WHERE puppet_id=$p AND room_id = $room AND remote_id=$r", {

}
stopTimer();
return result;

@@ -71,2 +78,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_remote"));
const result = [];

@@ -81,6 +89,15 @@ const rows = yield this.db.All("SELECT * FROM event_store WHERE puppet_id = $p AND room_id = $room AND matrix_id = $m", {

}
stopTimer();
return result;
});
}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "event_store",
type: queryName,
};
}
}
exports.DbEventStore = DbEventStore;

@@ -6,3 +6,4 @@ import { IDatabaseConnector } from "./connector";

private groupsCache;
constructor(db: IDatabaseConnector, cache?: boolean);
private protocol;
constructor(db: IDatabaseConnector, cache?: boolean, protocolId?: string);
newData(mxid: string, groupId: string, puppetId: number): IGroupStoreEntry;

@@ -15,2 +16,3 @@ getByRemote(puppetId: number, groupId: string, ignoreCache?: boolean): Promise<IGroupStoreEntry | null>;

private getFromRow;
private labels;
}

@@ -30,5 +30,6 @@ "use strict";

class DbGroupStore {
constructor(db, cache = true) {
constructor(db, cache = true, protocolId = "unknown") {
this.db = db;
this.groupsCache = new timedcache_1.TimedCache(cache ? GROUP_CACHE_LIFETIME : 0);
this.protocol = protocolId;
}

@@ -45,2 +46,3 @@ newData(mxid, groupId, puppetId) {

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_remote"));
if (!ignoreCache) {

@@ -56,3 +58,5 @@ const cached = this.groupsCache.get(`${puppetId};${groupId}`);

});
return yield this.getFromRow(row);
const result = yield this.getFromRow(row);
stopTimer();
return result;
});

@@ -62,2 +66,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_puppet"));
const rows = yield this.db.All("SELECT * FROM group_store WHERE puppet_id = $puppetId", {

@@ -73,2 +78,3 @@ puppetId,

}
stopTimer();
return results;

@@ -79,4 +85,7 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxid"));
const row = yield this.db.Get("SELECT * FROM group_store WHERE mxid = $mxid", { mxid });
return yield this.getFromRow(row);
const result = yield this.getFromRow(row);
stopTimer();
return result;
});

@@ -86,2 +95,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
// first de-dupe the room IDs

@@ -200,2 +210,3 @@ const uniqueRoomIds = [];

this.groupsCache.set(`${data.puppetId};${data.groupId}`, data);
stopTimer();
});

@@ -205,2 +216,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
yield this.db.Run("DELETE FROM group_store WHERE mxid = $mxid", { mxid: data.mxid });

@@ -212,2 +224,3 @@ yield this.db.Run("DELETE FROM group_store_rooms WHERE puppet_id = $puppetId AND group_id = $groupId", {

this.groupsCache.delete(`${data.puppetId};${data.groupId}`);
stopTimer();
});

@@ -217,2 +230,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_from_row"));
if (!row) {

@@ -238,6 +252,15 @@ return null;

this.groupsCache.set(`${data.puppetId};${data.groupId}`, data);
stopTimer();
return data;
});
}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "group_store",
type: queryName,
};
}
}
exports.DbGroupStore = DbGroupStore;
import { IDatabaseConnector, ISqlCommandParameters, ISqlRow } from "./connector";
import * as prometheus from "prom-client";
export declare class Postgres implements IDatabaseConnector {

@@ -6,2 +7,3 @@ private connectionString;

type: string;
latency: prometheus.Histogram<string>;
private db;

@@ -8,0 +10,0 @@ constructor(connectionString: string);

@@ -29,2 +29,3 @@ "use strict";

const log_1 = require("../log");
const prometheus = require("prom-client");
const log = new log_1.Log("Postgres");

@@ -38,2 +39,9 @@ const pgp = pgPromise({

this.type = "postgres";
this.latency = new prometheus.Histogram({
name: "bridge_database_query_seconds",
help: "Time spent querying the database engine",
labelNames: ["protocol", "engine", "type", "table"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.0075, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5],
});
}

@@ -40,0 +48,0 @@ static ParameterizeSql(sql) {

@@ -29,3 +29,4 @@ import { IDatabaseConnector } from "./connector";

private allPuppetIds;
constructor(db: IDatabaseConnector, cache?: boolean);
private protocol;
constructor(db: IDatabaseConnector, cache?: boolean, protocol?: string);
deleteStatusRoom(mxid: string): Promise<void>;

@@ -54,2 +55,3 @@ getMxidInfo(puppetMxid: string): Promise<IMxidInfo | null>;

private getRow;
private labels;
}

@@ -33,3 +33,3 @@ "use strict";

class DbPuppetStore {
constructor(db, cache = true) {
constructor(db, cache = true, protocol = "unknown") {
this.db = db;

@@ -40,6 +40,9 @@ this.mxidCache = new timedcache_1.TimedCache(cache ? PUPPET_CACHE_LIFETIME : 0);

this.allPuppetIds = null;
this.protocol = protocol;
}
deleteStatusRoom(mxid) {
return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_status"));
yield this.db.Run("UPDATE puppet_mxid_store SET status_room = '' WHERE status_room = $mxid", { mxid });
stopTimer();
});

@@ -49,2 +52,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("get_mx_info"));
const row = yield this.db.Get("SELECT * FROM puppet_mxid_store WHERE puppet_mxid=$id", { id: puppetMxid });

@@ -54,2 +58,3 @@ if (!row) {

}
stopTimer();
return {

@@ -89,2 +94,3 @@ puppetMxid,

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("set_mxid_info"));
const exists = yield this.db.Get("SELECT * FROM puppet_mxid_store WHERE puppet_mxid=$id", { id: puppet.puppetMxid });

@@ -122,2 +128,3 @@ let query = "";

});
stopTimer();
});

@@ -127,2 +134,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
let result = [];

@@ -153,2 +161,3 @@ if (this.allPuppetIds) {

}
stopTimer();
return result;

@@ -159,2 +168,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_for_mx"));
const result = [];

@@ -168,2 +178,3 @@ const rows = yield this.db.All("SELECT * FROM puppet_store WHERE puppet_mxid=$mxid", { mxid: puppetMxid });

}
stopTimer();
return result;

@@ -174,2 +185,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
const cached = this.puppetCache.get(puppetId);

@@ -183,2 +195,3 @@ if (cached) {

}
stopTimer();
return this.getRow(row);

@@ -189,2 +202,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_mxid"));
const cached = this.mxidCache.get(puppetId);

@@ -200,2 +214,3 @@ if (cached) {

this.mxidCache.set(puppetId, mxid);
stopTimer();
return mxid;

@@ -206,2 +221,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_uid"));
yield this.db.Run("UPDATE puppet_store SET user_id=$uid WHERE puppet_id=$pid", {

@@ -212,2 +228,3 @@ uid: userId,

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -217,2 +234,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_data"));
let dataStr = "";

@@ -231,2 +249,3 @@ try {

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -236,2 +255,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_type"));
yield this.db.Run("UPDATE puppet_store SET type=$t WHERE puppet_id=$id", {

@@ -242,2 +262,3 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -247,2 +268,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_visibility"));
yield this.db.Run("UPDATE puppet_store SET is_public=$p WHERE puppet_id=$id", {

@@ -253,2 +275,3 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -258,2 +281,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_autoinvite"));
yield this.db.Run("UPDATE puppet_store SET autoinvite=$a WHERE puppet_id=$id", {

@@ -264,2 +288,3 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -269,2 +294,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_namespace"));
yield this.db.Run("UPDATE puppet_store SET is_global_namespace=$is WHERE puppet_id=$id", {

@@ -275,2 +301,3 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
});

@@ -280,2 +307,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
let dataStr = "";

@@ -300,2 +328,3 @@ try {

this.allPuppetIds = null;
stopTimer();
return puppetId;

@@ -306,2 +335,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
yield this.db.Run("DELETE FROM puppet_store WHERE puppet_id=$id", { id: puppetId });

@@ -311,2 +341,3 @@ this.mxidCache.delete(puppetId);

this.allPuppetIds = null;
stopTimer();
});

@@ -316,2 +347,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_ghost_in_room"));
const exists = yield this.db.Get("SELECT * FROM ghosts_joined_chans WHERE ghost_mxid = $ghostMxid AND chan_mxid = $roomMxid", {

@@ -321,2 +353,3 @@ ghostMxid,

});
stopTimer();
return exists ? true : false;

@@ -327,2 +360,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_ghost_in_room"));
if (yield this.isGhostInRoom(ghostMxid, roomMxid)) {

@@ -335,2 +369,3 @@ return;

});
stopTimer();
});

@@ -340,2 +375,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_ghost_in_room"));
const result = [];

@@ -346,2 +382,3 @@ const rows = yield this.db.All("SELECT * FROM ghosts_joined_chans WHERE chan_mxid = $room", { room });

}
stopTimer();
return result;

@@ -352,2 +389,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_rooms_of_ghost"));
const result = [];

@@ -358,2 +396,3 @@ const rows = yield this.db.All("SELECT * FROM ghosts_joined_chans WHERE ghost_mxid = $ghost", { ghost });

}
stopTimer();
return result;

@@ -364,3 +403,5 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete_ghosts_in_room"));
yield this.db.Run("DELETE FROM ghosts_joined_chans WHERE chan_mxid = $room", { room });
stopTimer();
});

@@ -370,2 +411,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete_ghost_in_room"));
yield this.db.Run("DELETE FROM ghosts_joined_chans " +

@@ -376,2 +418,3 @@ "WHERE ghost_mxid = $g AND chan_mxid = $c", {

});
stopTimer();
});

@@ -399,3 +442,11 @@ }

}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "puppet_store",
type: queryName,
};
}
}
exports.DbPuppetStore = DbPuppetStore;

@@ -12,3 +12,4 @@ import { IDatabaseConnector } from "./connector";

private db;
constructor(db: IDatabaseConnector);
private protocol;
constructor(db: IDatabaseConnector, protocol?: string);
exists(data: IReactionStoreEntry): Promise<boolean>;

@@ -22,2 +23,3 @@ insert(data: IReactionStoreEntry): Promise<boolean>;

private getFromRow;
private labels;
}

@@ -27,7 +27,9 @@ "use strict";

class DbReactionStore {
constructor(db) {
constructor(db, protocol = "unknown") {
this.db = db;
this.protocol = protocol;
}
exists(data) {
return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_exists"));
const exists = yield this.db.Get(`SELECT 1 FROM reaction_store WHERE puppet_id = $pid AND user_id = $uid

@@ -41,2 +43,3 @@ AND room_id = $rid AND user_id = $uid AND event_id = $eid AND key = $key`, {

});
stopTimer();
return exists ? true : false;

@@ -47,2 +50,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
if (yield this.exists(data)) {

@@ -61,2 +65,3 @@ return false;

});
stopTimer();
return true;

@@ -67,3 +72,5 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_reaction_mxid"));
const row = yield this.db.Get("SELECT * FROM reaction_store WHERE reaction_mxid = $reactionMxid", { reactionMxid });
stopTimer();
return this.getFromRow(row);

@@ -74,2 +81,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_key"));
const row = yield this.db.Get(`SELECT * FROM reaction_store WHERE puppet_id = $pid AND user_id = $uid AND room_id = $rid

@@ -83,2 +91,3 @@ AND event_id = $eid AND key = $key`, {

});
stopTimer();
return this.getFromRow(row);

@@ -89,2 +98,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_for_event"));
const rows = yield this.db.All("SELECT * FROM reaction_store WHERE puppet_id = $puppetId AND event_id = $eventId", { puppetId, eventId });

@@ -98,2 +108,3 @@ const result = [];

}
stopTimer();
return result;

@@ -104,3 +115,5 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
yield this.db.Run("DELETE FROM reaction_store WHERE reaction_mxid = $reactionMxid", { reactionMxid });
stopTimer();
});

@@ -110,3 +123,5 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete_for_event"));
yield this.db.Run("DELETE FROM reaction_store WHERE puppet_id = $puppetId AND event_id = $eventId", { puppetId, eventId });
stopTimer();
});

@@ -127,3 +142,11 @@ }

}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "reaction_store",
type: queryName,
};
}
}
exports.DbReactionStore = DbReactionStore;

@@ -8,3 +8,4 @@ import { IDatabaseConnector } from "./connector";

private opCache;
constructor(db: IDatabaseConnector, cache?: boolean);
private protocol;
constructor(db: IDatabaseConnector, cache?: boolean, protocol?: string);
newData(mxid: string, roomId: string, puppetId: number): IRoomStoreEntry;

@@ -21,2 +22,3 @@ getAll(): Promise<IRoomStoreEntry[]>;

private getFromRow;
private labels;
}

@@ -30,3 +30,3 @@ "use strict";

class DbRoomStore {
constructor(db, cache = true) {
constructor(db, cache = true, protocol = "unknown") {
this.db = db;

@@ -36,2 +36,3 @@ this.remoteCache = new timedcache_1.TimedCache(cache ? ROOM_CACHE_LIFETIME : 0);

this.opCache = new timedcache_1.TimedCache(cache ? ROOM_CACHE_LIFETIME : 0);
this.protocol = protocol;
}

@@ -50,2 +51,3 @@ newData(mxid, roomId, puppetId) {

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
const rows = yield this.db.All("SELECT * FROM room_store");

@@ -59,2 +61,3 @@ const results = [];

}
stopTimer();
return results;

@@ -65,2 +68,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_remote"));
const cached = this.remoteCache.get(`${puppetId};${roomId}`);

@@ -74,2 +78,3 @@ if (cached) {

});
stopTimer();
return this.getFromRow(row);

@@ -80,2 +85,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_puppet"));
const rows = yield this.db.All("SELECT * FROM room_store WHERE puppet_id = $puppet_id", {

@@ -91,2 +97,3 @@ puppet_id: puppetId,

}
stopTimer();
return results;

@@ -97,2 +104,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxid"));
const cached = this.mxidCache.get(mxid);

@@ -103,2 +111,3 @@ if (cached) {

const row = yield this.db.Get("SELECT * FROM room_store WHERE mxid = $mxid", { mxid });
stopTimer();
return this.getFromRow(row);

@@ -109,2 +118,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
const exists = yield this.db.Get("SELECT * FROM room_store WHERE mxid = $mxid", { mxid: data.mxid });

@@ -176,2 +186,3 @@ let query = "";

this.mxidCache.set(data.mxid, data);
stopTimer();
});

@@ -181,2 +192,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
yield this.db.Run("DELETE FROM room_store WHERE mxid = $mxid", { mxid: data.mxid });

@@ -187,2 +199,3 @@ yield this.db.Run("DELETE FROM chan_op WHERE chan_mxid=$mxid", { mxid: data.mxid });

this.opCache.delete(data.mxid);
stopTimer();
});

@@ -192,2 +205,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_namespace"));
const exists = yield this.getByRemote(-1, roomId);

@@ -208,2 +222,3 @@ if (exists) {

this.opCache.delete(room.mxid);
stopTimer();
});

@@ -213,2 +228,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("update_room_op"));
const row = yield this.db.Get("SELECT * FROM chan_op WHERE chan_mxid=$chan LIMIT 1", {

@@ -220,2 +236,3 @@ chan: roomMxid,

// nothing to do, we are already set
stopTimer();
return;

@@ -232,2 +249,3 @@ }

this.opCache.set(roomMxid, userMxid);
stopTimer();
});

@@ -237,2 +255,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_room_op"));
const cached = this.opCache.get(roomMxid);

@@ -250,2 +269,3 @@ if (cached) {

this.opCache.set(roomMxid, userMxid);
stopTimer();
return userMxid;

@@ -273,3 +293,11 @@ });

}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "room_store",
type: queryName,
};
}
}
exports.DbRoomStore = DbRoomStore;
import { IDatabaseConnector, ISqlCommandParameters, ISqlRow } from "./connector";
import * as prometheus from "prom-client";
export declare class SQLite3 implements IDatabaseConnector {
private filename;
type: string;
latency: prometheus.Histogram<string>;
private db;

@@ -6,0 +8,0 @@ private insertId;

@@ -29,2 +29,3 @@ "use strict";

const log_1 = require("../log");
const prometheus = require("prom-client");
const log = new log_1.Log("SQLite3");

@@ -36,2 +37,9 @@ class SQLite3 {

this.insertId = -1;
this.latency = new prometheus.Histogram({
name: "bridge_database_query_seconds",
help: "Time spent querying the database engine",
labelNames: ["protocol", "engine", "type", "table"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.0075, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5],
});
}

@@ -38,0 +46,0 @@ Open() {

@@ -6,4 +6,6 @@ import { IDatabaseConnector } from "./connector";

private usersCache;
constructor(db: IDatabaseConnector, cache?: boolean);
private protocol;
constructor(db: IDatabaseConnector, cache?: boolean, protocol?: string);
newData(puppetId: number, userId: string): IUserStoreEntry;
getAll(): Promise<IUserStoreEntry[]>;
get(puppetId: number, userId: string): Promise<IUserStoreEntry | null>;

@@ -17,2 +19,3 @@ set(data: IUserStoreEntry): Promise<void>;

private getRoomOverrideFromRow;
private labels;
}

@@ -30,5 +30,6 @@ "use strict";

class DbUserStore {
constructor(db, cache = true) {
constructor(db, cache = true, protocol = "unknown") {
this.db = db;
this.usersCache = new timedcache_1.TimedCache(cache ? USERS_CACHE_LIFETIME : 0);
this.protocol = protocol;
}

@@ -41,4 +42,28 @@ newData(puppetId, userId) {

}
getAll() {
return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
const results = [];
const rows = yield this.db.All("SELECT * FROM user_store;");
if (!rows) {
return [];
}
for (const r of rows) {
const data = {
name: r.name,
userId: r.user_id,
puppetId: r.puppet_id,
avatarUrl: r.avatar_url,
avatarMxc: r.avatar_mxc,
avatarHash: r.avatar_hash,
};
results.push(data);
}
stopTimer();
return results;
});
}
get(puppetId, userId) {
return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
const cacheKey = `${puppetId};${userId}`;

@@ -59,2 +84,3 @@ const cached = this.usersCache.get(cacheKey);

this.usersCache.set(cacheKey, data);
stopTimer();
return data;

@@ -65,2 +91,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
const exists = yield this.db.Get("SELECT 1 FROM user_store WHERE user_id = $id AND puppet_id = $pid", { id: data.userId, pid: data.puppetId });

@@ -103,2 +130,3 @@ let query = "";

this.usersCache.set(cacheKey, data);
stopTimer();
});

@@ -108,2 +136,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
yield this.db.Run("DELETE FROM user_store WHERE user_id = $user_id AND puppet_id = $puppet_id", {

@@ -120,2 +149,3 @@ user_id: data.userId,

this.usersCache.delete(cacheKey);
stopTimer();
});

@@ -132,2 +162,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("get_room_override"));
const row = yield this.db.Get("SELECT * FROM user_store_room_override WHERE user_id = $uid AND puppet_id = $pid AND room_id = $rid", {

@@ -141,2 +172,3 @@ uid: userId,

}
stopTimer();
return this.getRoomOverrideFromRow(row);

@@ -147,2 +179,3 @@ });

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update_room_override"));
const exists = yield this.db.Get("SELECT 1 FROM user_store_room_override WHERE user_id = $uid AND puppet_id = $pid AND room_id = $rid", {

@@ -190,2 +223,3 @@ uid: data.userId,

});
stopTimer();
});

@@ -195,2 +229,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_room_override"));
const result = [];

@@ -207,2 +242,3 @@ const rows = yield this.db.All("SELECT * FROM user_store_room_override WHERE user_id = $uid AND puppet_id = $pid", {

}
stopTimer();
return result;

@@ -222,3 +258,11 @@ });

}
labels(queryName) {
return {
protocol: this.protocol,
engine: this.db.type,
table: "user_store",
type: queryName,
};
}
}
exports.DbUserStore = DbUserStore;

@@ -27,2 +27,3 @@ "use strict";

const escapeHtml = require("escape-html");
const prometheus = require("prom-client");
const log = new log_1.Log("MatrixEventHandler");

@@ -38,2 +39,19 @@ // tslint:disable no-magic-numbers

this.memberInfoCache = {};
this.bridge.metrics.matrixEvent = new prometheus.Counter({
name: "bridge_matrix_events_total",
help: "Total matrix events bridged to the remote network, by protocol and type",
labelNames: ["protocol", "type"],
});
this.bridge.metrics.matrixEventBucket = new prometheus.Histogram({
name: "bridge_matrix_event_seconds",
help: "Time spent processing matrix events in seconds, by protocol",
labelNames: ["protocol", "type"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.01, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 5, 7, 10],
});
this.bridge.metrics.matrixEventError = new prometheus.Counter({
name: "bridge_matrix_event_errors_total",
help: "Errors encountered during matrix event processing",
labelNames: ["protocol"],
});
}

@@ -43,2 +61,6 @@ registerAppserviceEvents() {

this.bridge.AS.on("room.event", (roomId, rawEvent) => __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "room.event",
});
try {

@@ -49,6 +71,14 @@ yield this.handleRoomEvent(roomId, new matrix_bot_sdk_1.RoomEvent(rawEvent));

log.error("Error handling appservice room.event", err.error || err.body || err);
this.bridge.metrics.matrixEventError.inc({ protocol: this.bridge.protocol.id });
}
finally {
stopTimer();
}
}));
// tslint:disable-next-line no-any
this.bridge.AS.on("room.invite", (roomId, rawEvent) => __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "room.invite",
});
try {

@@ -59,6 +89,14 @@ yield this.handleInviteEvent(roomId, new matrix_bot_sdk_1.MembershipEvent(rawEvent));

log.error("Error handling appservice room.invite", err.error || err.body || err);
this.bridge.metrics.matrixEventError.inc({ protocol: this.bridge.protocol.id });
}
finally {
stopTimer();
}
}));
// tslint:disable-next-line no-any
this.bridge.AS.on("query.room", (alias, createRoom) => __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "query.room",
});
try {

@@ -68,7 +106,15 @@ yield this.handleRoomQuery(alias, createRoom);

catch (err) {
this.bridge.metrics.matrixEventError.inc({ protocol: this.bridge.protocol.id });
log.error("Error handling appservice query.room", err.error || err.body || err);
}
finally {
stopTimer();
}
}));
// tslint:disable-next-line no-any
this.bridge.AS.on("ephemeral.event", (rawEvent) => __awaiter(this, void 0, void 0, function* () {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "ephemeral.event",
});
try {

@@ -90,2 +136,3 @@ switch (rawEvent.type) {

}
stopTimer();
}));

@@ -136,2 +183,6 @@ }

const membershipEvent = new matrix_bot_sdk_1.MembershipEvent(event.raw);
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: `${event.type}.${membershipEvent.membership}`,
});
switch (membershipEvent.membership) {

@@ -151,2 +202,6 @@ case "join":

yield this.handleRedactEvent(roomId, evt);
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: event.type,
});
return;

@@ -379,2 +434,6 @@ }

}
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: msgtype,
});
});

@@ -514,2 +573,3 @@ }

handleInviteEvent(roomId, invite) {
var _a;
return __awaiter(this, void 0, void 0, function* () {

@@ -593,2 +653,3 @@ const userId = invite.membershipFor;

yield this.bridge.userSync.getClient(parts); // create user, if it doesn't exist
(_a = this.bridge.metrics.room) === null || _a === void 0 ? void 0 : _a.inc({ type: roomData.isDirect ? "dm" : "group", protocol: this.bridge.protocol.id });
});

@@ -595,0 +656,0 @@ }

@@ -330,2 +330,3 @@ "use strict";

yield this.bridge.roomSync.rebridge(mxid, newRoomParts);
this.bridge.metrics.room.inc({ type: "group", protocol: this.bridge.protocol.id });
});

@@ -348,2 +349,3 @@ }

yield this.bridge.roomSync.delete(roomParts, true);
this.bridge.metrics.room.dec({ type: "group", protocol: this.bridge.protocol.id });
return true;

@@ -409,3 +411,6 @@ });

}
else if (!(yield this.bridge.namespaceHandler.canSeeRoom(roomParts, userId))) {
else if (!(yield this.bridge.namespaceHandler.canSeeRoom({
puppetId: yield this.bridge.namespaceHandler.getDbPuppetId(roomParts.puppetId),
roomId: roomParts.roomId,
}, userId))) {
targetLevel = MUTED_POWER_LEVEL;

@@ -481,3 +486,6 @@ }

}
if (yield this.bridge.namespaceHandler.canSeeRoom(room, userId)) {
if (yield this.bridge.namespaceHandler.canSeeRoom({
roomId: room.roomId,
puppetId: yield this.bridge.namespaceHandler.getDbPuppetId(room.puppetId),
}, userId)) {
const client = (yield this.bridge.roomSync.getRoomOp(room.mxid)) || this.bridge.botIntent.underlyingClient;

@@ -484,0 +492,0 @@ try {

/// <reference types="node" />
import { Appservice, Intent, MatrixClient } from "@sorunome/matrix-bot-sdk";
import * as prometheus from "prom-client";
import { EventEmitter } from "events";

@@ -55,2 +56,13 @@ import { EmoteSyncroniser } from "./emotesyncroniser";

}
export declare class BridgeMetrics {
room: prometheus.Gauge<string>;
puppet: prometheus.Gauge<string>;
message: prometheus.Counter<string>;
remoteUser: prometheus.Gauge<string>;
matrixEvent: prometheus.Counter<string>;
matrixEventBucket: prometheus.Histogram<string>;
matrixEventError: prometheus.Counter<string>;
remoteUpdateBucket: prometheus.Histogram<string>;
connected: prometheus.Gauge<string>;
}
export declare class PuppetBridge extends EventEmitter {

@@ -76,2 +88,3 @@ private registrationPath;

namespaceHandler: NamespaceHandler;
metrics: BridgeMetrics;
private appservice;

@@ -81,2 +94,3 @@ private mxcLookupLock;

private remoteEventHandler;
private connectionMetricStatus;
constructor(registrationPath: string, configPath: string, prot?: IProtocolInformation);

@@ -194,6 +208,7 @@ /** @internal */

getPuppetMxidInfo(puppetId: number): Promise<IMxidInfo | null>;
trackConnectionStatus(puppetId: number, isConnected: boolean): void;
/**
* Send a status message either to the status message room or to a specified room
*/
sendStatusMessage(puppetId: number | IRemoteRoom, msg: string): Promise<void>;
sendStatusMessage(puppetId: number | IRemoteRoom, msg: string, isConnected?: boolean | null): Promise<void>;
/**

@@ -200,0 +215,0 @@ * Registers a custom command with the bot provisioner

@@ -28,2 +28,4 @@ "use strict";

const yaml = require("js-yaml");
const prometheus = require("prom-client");
const express = require("express");
const events_1 = require("events");

@@ -56,2 +58,5 @@ const emotesyncroniser_1 = require("./emotesyncroniser");

const AVATAR_SIZE = 800;
class BridgeMetrics {
}
exports.BridgeMetrics = BridgeMetrics;
class PuppetBridge extends events_1.EventEmitter {

@@ -80,4 +85,26 @@ constructor(registrationPath, configPath, prot) {

this.hooks = {};
this.connectionMetricStatus = {};
this.delayedFunction = new delayedfunction_1.DelayedFunction();
this.mxcLookupLock = new lock_1.Lock(MXC_LOOKUP_LOCK_TIMEOUT);
this.metrics = new BridgeMetrics();
this.metrics.room = new prometheus.Gauge({
name: "bridge_rooms_total",
help: "Total rooms bridged to the remote network, by type and protocol",
labelNames: ["type", "protocol"],
});
this.metrics.puppet = new prometheus.Gauge({
name: "bridge_puppets_total",
help: "Puppets linked to remote network, puppeted by matrix users",
labelNames: ["protocol"],
});
this.metrics.connected = new prometheus.Gauge({
name: "bridge_connected",
help: "Users connected to the remote network",
labelNames: ["protocol"],
});
this.metrics.message = new prometheus.Counter({
name: "bridge_messages_total",
help: "Total messages bridged into matrix, by type and protocol",
labelNames: ["type", "protocol"],
});
}

@@ -147,2 +174,12 @@ /** @internal */

this.provisioningAPI = new provisioningapi_1.ProvisioningAPI(this);
if (this.config.metrics.enabled) {
prometheus.collectDefaultMetrics();
const metricsServer = express();
metricsServer.get(this.config.metrics.path, (req, res) => __awaiter(this, void 0, void 0, function* () {
res.set("Content-Type", prometheus.register.contentType);
const metrics = yield prometheus.register.metrics();
res.send(metrics);
}));
metricsServer.listen(this.config.metrics.port);
}
// pipe matrix-bot-sdk logging int ours

@@ -310,2 +347,3 @@ const logMap = new Map();

const puppets = yield this.provisioner.getAll();
this.metrics.puppet.set({ protocol: this.protocol.id }, puppets.length);
for (const p of puppets) {

@@ -422,2 +460,3 @@ this.emit("puppetNew", p.puppetId, p.data);

bridgeRoom(roomData) {
var _a;
return __awaiter(this, void 0, void 0, function* () {

@@ -429,5 +468,9 @@ if (!this.hooks.createRoom) {

const room = yield this.namespaceHandler.createRoom(roomData);
if (!room || room.isDirect) {
if (!room) {
return;
}
this.metrics.room.inc({ type: room.isDirect ? "dm" : "group", protocol: (_a = this.protocol) === null || _a === void 0 ? void 0 : _a.id });
if (room.isDirect) {
return;
}
log.info(`Got request to bridge room puppetId=${room.puppetId} roomId=${room.roomId}`);

@@ -450,2 +493,3 @@ yield this.roomSync.getMxid(room);

unbridgeRoom(room) {
var _a;
return __awaiter(this, void 0, void 0, function* () {

@@ -457,2 +501,3 @@ if (!room) {

yield this.roomSync.delete(room, true);
this.metrics.room.dec({ type: room.isDirect ? "dm" : "group", protocol: (_a = this.protocol) === null || _a === void 0 ? void 0 : _a.id });
});

@@ -602,7 +647,22 @@ }

}
trackConnectionStatus(puppetId, isConnected) {
if (Boolean(this.connectionMetricStatus[puppetId]) === isConnected) {
return;
}
this.connectionMetricStatus[puppetId] = isConnected;
if (isConnected) {
this.metrics.connected.inc({ protocol: this.protocol.id });
}
else {
this.metrics.connected.dec({ protocol: this.protocol.id });
}
}
/**
* Send a status message either to the status message room or to a specified room
*/
sendStatusMessage(puppetId, msg) {
sendStatusMessage(puppetId, msg, isConnected = null) {
return __awaiter(this, void 0, void 0, function* () {
if (isConnected !== null) {
this.trackConnectionStatus(typeof puppetId === "number" ? puppetId : puppetId.puppetId, isConnected);
}
yield this.botProvisioner.sendStatusMessage(puppetId, msg);

@@ -631,2 +691,3 @@ });

yield this.remoteEventHandler.sendFileByType("m.file", params, thing, name);
this.metrics.message.inc({ type: "file", protocol: this.protocol.id });
});

@@ -640,2 +701,3 @@ }

yield this.remoteEventHandler.sendFileByType("m.video", params, thing, name);
this.metrics.message.inc({ type: "video", protocol: this.protocol.id });
});

@@ -649,2 +711,3 @@ }

yield this.remoteEventHandler.sendFileByType("m.audio", params, thing, name);
this.metrics.message.inc({ type: "audio", protocol: this.protocol.id });
});

@@ -658,2 +721,3 @@ }

yield this.remoteEventHandler.sendFileByType("m.image", params, thing, name);
this.metrics.message.inc({ type: "image", protocol: this.protocol.id });
});

@@ -667,2 +731,3 @@ }

yield this.remoteEventHandler.sendMessage(params, opts);
this.metrics.message.inc({ type: "text", protocol: this.protocol.id });
});

@@ -676,2 +741,3 @@ }

yield this.remoteEventHandler.sendEdit(params, eventId, opts, ix);
this.metrics.message.inc({ type: "edit", protocol: this.protocol.id });
});

@@ -685,2 +751,3 @@ }

yield this.remoteEventHandler.sendRedact(params, eventId);
this.metrics.message.inc({ type: "redact", protocol: this.protocol.id });
});

@@ -702,2 +769,3 @@ }

yield this.remoteEventHandler.sendReaction(params, eventId, reaction);
this.metrics.message.inc({ type: "reaction", protocol: this.protocol.id });
});

@@ -704,0 +772,0 @@ }

@@ -24,3 +24,4 @@ /// <reference types="node" />

private prepareSend;
private preprocessBody;
private preprocessMessageEvent;
}

@@ -29,2 +29,3 @@ "use strict";

const unescapeHtml = require("unescape");
const prometheus = require("prom-client");
const blurhash_1 = require("blurhash");

@@ -40,2 +41,9 @@ const Canvas = require("canvas");

this.ghostInviteCache = new timedcache_1.TimedCache(PUPPET_INVITE_CACHE_LIFETIME);
this.bridge.metrics.remoteUpdateBucket = new prometheus.Histogram({
name: "bridge_remote_update_seconds",
help: "Time spent processing updates from the remote network, by protocol and type",
labelNames: ["protocol", "type"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.01, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 5, 7, 10],
});
}

@@ -146,2 +154,5 @@ setUserPresence(user, presence) {

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received message from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -175,2 +186,3 @@ this.preprocessMessageEvent(opts);

yield this.bridge.typingHandler.set(yield client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
});

@@ -183,2 +195,5 @@ }

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received edit from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -239,2 +254,3 @@ this.preprocessMessageEvent(opts);

yield this.bridge.typingHandler.set(yield client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
});

@@ -261,2 +277,5 @@ }

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received reply from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -299,4 +318,4 @@ this.preprocessMessageEvent(opts);

}
const bodyParts = info.message.body.split("\n");
bodyParts[0] = `${info.message.emote ? "* " : ""}<${info.user.mxid}> ${bodyParts[0]}`;
const bodyParts = this.preprocessBody(info.message.body).split("\n");
bodyParts[0] = `${info.message.emote ? "* " : ""}<${this.preprocessBody(info.user.mxid)}> ${bodyParts[0]}`;
send.body = `${bodyParts.map((l) => `> ${l}`).join("\n")}\n\n${send.body}`;

@@ -322,3 +341,3 @@ const matrixReplyRegex = /^<mx-reply>.*<\/mx-reply>/gs;

}
const plainHeader = `> <${info.user.mxid}> sent ${msg}.\n\n`;
const plainHeader = `> <${this.preprocessBody(info.user.mxid)}> sent ${msg}.\n\n`;
send.body = plainHeader + send.body;

@@ -350,2 +369,3 @@ const richHeader = `<mx-reply><blockquote>

yield this.bridge.typingHandler.set(yield client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
});

@@ -391,2 +411,5 @@ }

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received file to send from ${params.user.userId} in ${params.room.roomId}.`);

@@ -543,2 +566,3 @@ log.verbose(`thing=${typeof thing === "string" ? thing : "<Buffer>"} name=${name}`);

yield this.bridge.typingHandler.set(yield client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
});

@@ -635,7 +659,11 @@ }

}
preprocessMessageEvent(opts) {
preprocessBody(body) {
for (const homeserver of this.bridge.config.bridge.stripHomeservers) {
const urlRegex = homeserver.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
opts.body = opts.body.replace(new RegExp(`@([\x21-\x39\x3b-\x7e]+):${urlRegex}`, "g"), "@$1");
body = body.replace(new RegExp(`@([\x21-\x39\x3b-\x7e]+):${urlRegex}`, "g"), "@$1");
}
return body;
}
preprocessMessageEvent(opts) {
opts.body = this.preprocessBody(opts.body);
if (!opts.formattedBody) {

@@ -642,0 +670,0 @@ return;

@@ -36,2 +36,18 @@ "use strict";

this.mxidLock = new lock_1.Lock(MXID_LOOKUP_LOCK_TIMEOUT);
if (this.bridge.config.metrics.enabled) {
const roomMetricsInit = (rooms) => {
this.bridge.metrics.room.set({
type: "dm",
protocol: this.bridge.protocol.id,
}, rooms.filter((room) => room.isDirect).length);
this.bridge.metrics.room.set({
type: "group",
protocol: this.bridge.protocol.id,
}, rooms.filter((room) => !room.isDirect).length);
};
this.roomStore.getAll()
.catch((err) => log.error("could not get room store"))
.then(roomMetricsInit)
.catch((err) => log.warn("could not init room metrics"));
}
}

@@ -38,0 +54,0 @@ getRoomOp(room) {

@@ -188,2 +188,3 @@ "use strict";

openDatabase() {
var _a, _b, _c, _d, _e, _f, _g;
return __awaiter(this, void 0, void 0, function* () {

@@ -200,9 +201,9 @@ if (this.config.connString) {

this.db.Open();
this.pRoomStore = new roomstore_1.DbRoomStore(this.db);
this.pUserStore = new userstore_1.DbUserStore(this.db);
this.pGroupStore = new groupstore_1.DbGroupStore(this.db);
this.pPuppetStore = new puppetstore_1.DbPuppetStore(this.db);
this.pEventStore = new eventstore_1.DbEventStore(this.db);
this.pReactionStore = new reactionstore_1.DbReactionStore(this.db);
this.pEmoteStore = new emotestore_1.DbEmoteStore(this.db);
this.pRoomStore = new roomstore_1.DbRoomStore(this.db, undefined, (_a = this.bridge.protocol) === null || _a === void 0 ? void 0 : _a.id);
this.pUserStore = new userstore_1.DbUserStore(this.db, undefined, (_b = this.bridge.protocol) === null || _b === void 0 ? void 0 : _b.id);
this.pGroupStore = new groupstore_1.DbGroupStore(this.db, undefined, (_c = this.bridge.protocol) === null || _c === void 0 ? void 0 : _c.id);
this.pPuppetStore = new puppetstore_1.DbPuppetStore(this.db, undefined, (_d = this.bridge.protocol) === null || _d === void 0 ? void 0 : _d.id);
this.pEventStore = new eventstore_1.DbEventStore(this.db, (_e = this.bridge.protocol) === null || _e === void 0 ? void 0 : _e.id);
this.pReactionStore = new reactionstore_1.DbReactionStore(this.db, (_f = this.bridge.protocol) === null || _f === void 0 ? void 0 : _f.id);
this.pEmoteStore = new emotestore_1.DbEmoteStore(this.db, (_g = this.bridge.protocol) === null || _g === void 0 ? void 0 : _g.id);
}

@@ -209,0 +210,0 @@ catch (ex) {

@@ -28,2 +28,3 @@ "use strict";

const lock_1 = require("./structures/lock");
const prometheus = require("prom-client");
const log = new log_1.Log("UserSync");

@@ -41,2 +42,14 @@ // tslint:disable no-magic-numbers

this.roomOverrideLock = new lock_1.Lock(ROOM_OVERRIDE_LOCK_TIMEOUT);
const that = this;
this.bridge.metrics.remoteUser = new prometheus.Gauge({
name: "bridge_remote_users_total",
help: "Total number of users on the remote network",
labelNames: ["protocol"],
collect() {
return __awaiter(this, void 0, void 0, function* () {
const remoteUsers = yield that.userStore.getAll();
this.set({ protocol: that.bridge.protocol.id }, remoteUsers.length);
});
},
});
}

@@ -43,0 +56,0 @@ getClientFromTokenCallback(token) {

{
"name": "mx-puppet-bridge",
"version": "0.1.3",
"version": "0.1.4",
"description": "Matrix Puppeting Bridge library",

@@ -36,2 +36,3 @@ "repository": {

"pg-promise": "^10.5.0",
"prom-client": "^13.0.0",
"unescape": "^1.0.1",

@@ -38,0 +39,0 @@ "uuid": "^3.4.0",

@@ -21,2 +21,3 @@ /*

public database: DatabaseConfig = new DatabaseConfig();
public metrics: MetricsConfig = new MetricsConfig();
public provisioning: ProvisioningConfig = new ProvisioningConfig();

@@ -82,2 +83,8 @@ public presence: PresenceConfig = new PresenceConfig();

export class MetricsConfig {
public enabled: boolean = false;
public port: number = 8000;
public path: string = "/metrics";
}
export class DatabaseConfig {

@@ -84,0 +91,0 @@ public connString: string;

@@ -17,2 +17,4 @@ /*

import * as prometheus from "prom-client";
type SQLTYPES = number | boolean | string | null;

@@ -30,2 +32,3 @@

type: string;
latency: prometheus.Histogram<string>;
Open(): void;

@@ -32,0 +35,0 @@ Get(sql: string, parameters?: ISqlCommandParameters): Promise<ISqlRow|null>;

@@ -23,3 +23,4 @@ /*

private db: IDatabaseConnector,
) { }
private protocol: string = "unknown",
) {}

@@ -40,2 +41,3 @@ public newData(puppetId: number, roomId: string | null, emoteId: string): IEmoteStoreEntry {

public async get(puppetId: number, roomId: string | null, emoteId: string): Promise<IEmoteStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
if (roomId) {

@@ -48,2 +50,3 @@ const row = await this.db.Get(

});
stopTimer();
return this.getFromRow(row);

@@ -56,2 +59,3 @@ } else {

});
stopTimer();
return this.getFromRow(row);

@@ -62,2 +66,3 @@ }

public async getByMxc(puppetId: number, roomId: string | null, mxid: string): Promise<IEmoteStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxc"));
if (roomId) {

@@ -70,2 +75,3 @@ const row = await this.db.Get(

});
stopTimer();
return this.getFromRow(row);

@@ -78,2 +84,3 @@ } else {

});
stopTimer();
return this.getFromRow(row);

@@ -84,2 +91,3 @@ }

public async getForRoom(puppetId: number, roomId: string): Promise<IEmoteStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_room"));
const rows = await this.db.All("SELECT * FROM emote_store WHERE puppet_id = $pid AND room_id = $rid", {

@@ -96,2 +104,3 @@ pid: puppetId,

}
stopTimer();
return result;

@@ -101,2 +110,3 @@ }

public async set(data: IEmoteStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
let exists: ISqlRow | null = null;

@@ -159,2 +169,3 @@ if (data.roomId) {

});
stopTimer();
}

@@ -177,2 +188,11 @@

}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "emote_store",
type: queryName,
};
}
}

@@ -22,5 +22,7 @@ /*

private db: IDatabaseConnector,
private protocol: string = "unknown",
) { }
public async insert(puppetId: number, roomId: string, matrixId: string, remoteId: string) {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
await this.db.Run("INSERT INTO event_store (puppet_id, room_id, matrix_id, remote_id) VALUES ($p, $room, $m, $r)", {

@@ -32,5 +34,7 @@ p: puppetId,

});
stopTimer();
}
public async remove(puppetId: number, roomId: string, remoteId: string) {
const stopTimer = this.db.latency.startTimer(this.labels("remove"));
await this.db.Run("DELETE FROM event_store WHERE puppet_id = $p AND room_id = $room AND remote_id = $r", {

@@ -41,5 +45,7 @@ p: puppetId,

});
stopTimer();
}
public async getMatrix(puppetId: number, roomId: string, remoteId: string): Promise<string[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_matrix"));
const result: string[] = [];

@@ -54,2 +60,3 @@ const rows = await this.db.All("SELECT * FROM event_store WHERE puppet_id=$p AND room_id = $room AND remote_id=$r", {

}
stopTimer();
return result;

@@ -59,2 +66,3 @@ }

public async getRemote(puppetId: number, roomId: string, matrixId: string): Promise<string[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_remote"));
const result: string[] = [];

@@ -70,4 +78,14 @@ const rows = await this.db.All(

}
stopTimer();
return result;
}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "event_store",
type: queryName,
};
}
}

@@ -26,7 +26,10 @@ /*

private groupsCache: TimedCache<string, IGroupStoreEntry>;
private protocol: string;
constructor(
private db: IDatabaseConnector,
cache: boolean = true,
protocolId: string = "unknown",
) {
this.groupsCache = new TimedCache(cache ? GROUP_CACHE_LIFETIME : 0);
this.protocol = protocolId;
}

@@ -48,2 +51,3 @@

): Promise<IGroupStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_remote"));
if (!ignoreCache) {

@@ -60,6 +64,9 @@ const cached = this.groupsCache.get(`${puppetId};${groupId}`);

});
return await this.getFromRow(row);
const result = await this.getFromRow(row);
stopTimer();
return result;
}
public async getByPuppetId(puppetId: number): Promise<IGroupStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_puppet"));
const rows = await this.db.All(

@@ -76,2 +83,3 @@ "SELECT * FROM group_store WHERE puppet_id = $puppetId", {

}
stopTimer();
return results;

@@ -81,9 +89,13 @@ }

public async getByMxid(mxid: string): Promise<IGroupStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxid"));
const row = await this.db.Get(
"SELECT * FROM group_store WHERE mxid = $mxid", { mxid },
);
return await this.getFromRow(row);
const result = await this.getFromRow(row);
stopTimer();
return result;
}
public async set(data: IGroupStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
// first de-dupe the room IDs

@@ -202,5 +214,7 @@ const uniqueRoomIds: string[] = [];

this.groupsCache.set(`${data.puppetId};${data.groupId}`, data);
stopTimer();
}
public async delete(data: IGroupStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
await this.db.Run(

@@ -215,5 +229,7 @@ "DELETE FROM group_store WHERE mxid = $mxid", { mxid: data.mxid },

this.groupsCache.delete(`${data.puppetId};${data.groupId}`);
stopTimer();
}
private async getFromRow(row: ISqlRow | null): Promise<IGroupStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_from_row"));
if (!row) {

@@ -246,4 +262,14 @@ return null;

this.groupsCache.set(`${data.puppetId};${data.groupId}`, data);
stopTimer();
return data;
}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "group_store",
type: queryName,
};
}
}

@@ -20,2 +20,3 @@ /*

import { IDatabaseConnector, ISqlCommandParameters, ISqlRow } from "./connector";
import * as prometheus from "prom-client";
const log = new Log("Postgres");

@@ -35,2 +36,3 @@

public type = "postgres";
public latency: prometheus.Histogram<string>;

@@ -40,3 +42,9 @@ // tslint:disable-next-line no-any

constructor(private connectionString: string) {
this.latency = new prometheus.Histogram({
name: "bridge_database_query_seconds",
help: "Time spent querying the database engine",
labelNames: ["protocol", "engine", "type", "table"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.0075, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5],
});
}

@@ -43,0 +51,0 @@ public Open() {

@@ -55,5 +55,7 @@ /*

private allPuppetIds: Set<number> | null;
private protocol: string;
constructor(
private db: IDatabaseConnector,
cache: boolean = true,
protocol: string = "unknown",
) {

@@ -64,9 +66,13 @@ this.mxidCache = new TimedCache(cache ? PUPPET_CACHE_LIFETIME : 0);

this.allPuppetIds = null;
this.protocol = protocol;
}
public async deleteStatusRoom(mxid: string) {
const stopTimer = this.db.latency.startTimer(this.labels("update_status"));
await this.db.Run("UPDATE puppet_mxid_store SET status_room = '' WHERE status_room = $mxid", { mxid });
stopTimer();
}
public async getMxidInfo(puppetMxid: string): Promise<IMxidInfo | null> {
const stopTimer = this.db.latency.startTimer(this.labels("get_mx_info"));
const row = await this.db.Get("SELECT * FROM puppet_mxid_store WHERE puppet_mxid=$id", { id: puppetMxid });

@@ -76,2 +82,3 @@ if (!row) {

}
stopTimer();
return {

@@ -109,2 +116,3 @@ puppetMxid,

public async setMxidInfo(puppet: IMxidInfo) {
const stopTimer = this.db.latency.startTimer(this.labels("set_mxid_info"));
const exists = await this.db.Get("SELECT * FROM puppet_mxid_store WHERE puppet_mxid=$id", { id: puppet.puppetMxid });

@@ -141,5 +149,7 @@ let query = "";

});
stopTimer();
}
public async getAll(): Promise<IPuppet[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
let result: IPuppet[] = [];

@@ -170,2 +180,3 @@ if (this.allPuppetIds) {

}
stopTimer();
return result;

@@ -175,2 +186,3 @@ }

public async getForMxid(puppetMxid: string): Promise<IPuppet[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_for_mx"));
const result: IPuppet[] = [];

@@ -184,2 +196,3 @@ const rows = await this.db.All("SELECT * FROM puppet_store WHERE puppet_mxid=$mxid", { mxid: puppetMxid });

}
stopTimer();
return result;

@@ -189,2 +202,3 @@ }

public async get(puppetId: number): Promise<IPuppet | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
const cached = this.puppetCache.get(puppetId);

@@ -198,2 +212,3 @@ if (cached) {

}
stopTimer();
return this.getRow(row);

@@ -203,2 +218,3 @@ }

public async getMxid(puppetId: number): Promise<string> {
const stopTimer = this.db.latency.startTimer(this.labels("select_mxid"));
const cached = this.mxidCache.get(puppetId);

@@ -214,2 +230,3 @@ if (cached) {

this.mxidCache.set(puppetId, mxid);
stopTimer();
return mxid;

@@ -219,2 +236,3 @@ }

public async setUserId(puppetId: number, userId: string) {
const stopTimer = this.db.latency.startTimer(this.labels("update_uid"));
await this.db.Run("UPDATE puppet_store SET user_id=$uid WHERE puppet_id=$pid", {

@@ -225,5 +243,7 @@ uid: userId,

this.puppetCache.delete(puppetId);
stopTimer();
}
public async setData(puppetId: number, data: IPuppetData) {
const stopTimer = this.db.latency.startTimer(this.labels("update_data"));
let dataStr = "";

@@ -241,5 +261,7 @@ try {

this.puppetCache.delete(puppetId);
stopTimer();
}
public async setType(puppetId: number, type: PuppetType) {
const stopTimer = this.db.latency.startTimer(this.labels("update_type"));
await this.db.Run("UPDATE puppet_store SET type=$t WHERE puppet_id=$id", {

@@ -250,5 +272,7 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
}
public async setIsPublic(puppetId: number, isPublic: boolean) {
const stopTimer = this.db.latency.startTimer(this.labels("update_visibility"));
await this.db.Run("UPDATE puppet_store SET is_public=$p WHERE puppet_id=$id", {

@@ -259,5 +283,7 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
}
public async setAutoinvite(puppetId: number, autoinvite: boolean) {
const stopTimer = this.db.latency.startTimer(this.labels("update_autoinvite"));
await this.db.Run("UPDATE puppet_store SET autoinvite=$a WHERE puppet_id=$id", {

@@ -268,5 +294,7 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
}
public async setIsGlobalNamespace(puppetId: number, isGlobalNamespace: boolean) {
const stopTimer = this.db.latency.startTimer(this.labels("update_namespace"));
await this.db.Run("UPDATE puppet_store SET is_global_namespace=$is WHERE puppet_id=$id", {

@@ -277,2 +305,3 @@ id: puppetId,

this.puppetCache.delete(puppetId);
stopTimer();
}

@@ -286,2 +315,3 @@

): Promise<number> {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
let dataStr = "";

@@ -307,2 +337,3 @@ try {

this.allPuppetIds = null;
stopTimer();
return puppetId;

@@ -312,2 +343,3 @@ }

public async delete(puppetId: number) {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
await this.db.Run("DELETE FROM puppet_store WHERE puppet_id=$id", { id: puppetId });

@@ -317,5 +349,7 @@ this.mxidCache.delete(puppetId);

this.allPuppetIds = null;
stopTimer();
}
public async isGhostInRoom(ghostMxid: string, roomMxid: string): Promise<boolean> {
const stopTimer = this.db.latency.startTimer(this.labels("select_ghost_in_room"));
const exists = await this.db.Get(

@@ -327,2 +361,3 @@ "SELECT * FROM ghosts_joined_chans WHERE ghost_mxid = $ghostMxid AND chan_mxid = $roomMxid"

});
stopTimer();
return exists ? true : false;

@@ -332,2 +367,3 @@ }

public async joinGhostToRoom(ghostMxid: string, roomMxid: string) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_ghost_in_room"));
if (await this.isGhostInRoom(ghostMxid, roomMxid)) {

@@ -340,5 +376,7 @@ return;

});
stopTimer();
}
public async getGhostsInRoom(room: string): Promise<string[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_ghost_in_room"));
const result: string[] = [];

@@ -349,2 +387,3 @@ const rows = await this.db.All("SELECT * FROM ghosts_joined_chans WHERE chan_mxid = $room", { room });

}
stopTimer();
return result;

@@ -354,2 +393,3 @@ }

public async getRoomsOfGhost(ghost: string): Promise<string[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_rooms_of_ghost"));
const result: string[] = [];

@@ -360,2 +400,3 @@ const rows = await this.db.All("SELECT * FROM ghosts_joined_chans WHERE ghost_mxid = $ghost", { ghost });

}
stopTimer();
return result;

@@ -365,6 +406,9 @@ }

public async emptyGhostsInRoom(room: string) {
const stopTimer = this.db.latency.startTimer(this.labels("delete_ghosts_in_room"));
await this.db.Run("DELETE FROM ghosts_joined_chans WHERE chan_mxid = $room", { room });
stopTimer();
}
public async leaveGhostFromRoom(ghostMxid: string, roomMxid: string) {
const stopTimer = this.db.latency.startTimer(this.labels("delete_ghost_in_room"));
await this.db.Run("DELETE FROM ghosts_joined_chans " +

@@ -375,2 +419,3 @@ "WHERE ghost_mxid = $g AND chan_mxid = $c", {

});
stopTimer();
}

@@ -397,2 +442,11 @@

}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "puppet_store",
type: queryName,
};
}
}

@@ -31,5 +31,7 @@ /*

private db: IDatabaseConnector,
private protocol: string = "unknown",
) { }
public async exists(data: IReactionStoreEntry): Promise<boolean> {
const stopTimer = this.db.latency.startTimer(this.labels("select_exists"));
const exists = await this.db.Get(

@@ -44,2 +46,3 @@ `SELECT 1 FROM reaction_store WHERE puppet_id = $pid AND user_id = $uid

});
stopTimer();
return exists ? true : false;

@@ -49,2 +52,3 @@ }

public async insert(data: IReactionStoreEntry): Promise<boolean> {
const stopTimer = this.db.latency.startTimer(this.labels("insert"));
if (await this.exists(data)) {

@@ -63,2 +67,3 @@ return false;

});
stopTimer();
return true;

@@ -68,5 +73,7 @@ }

public async getFromReactionMxid(reactionMxid: string): Promise<IReactionStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_reaction_mxid"));
const row = await this.db.Get(
"SELECT * FROM reaction_store WHERE reaction_mxid = $reactionMxid", { reactionMxid },
);
stopTimer();
return this.getFromRow(row);

@@ -76,2 +83,3 @@ }

public async getFromKey(data: IReactionStoreEntry): Promise<IReactionStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_key"));
const row = await this.db.Get(

@@ -86,2 +94,3 @@ `SELECT * FROM reaction_store WHERE puppet_id = $pid AND user_id = $uid AND room_id = $rid

});
stopTimer();
return this.getFromRow(row);

@@ -91,2 +100,3 @@ }

public async getForEvent(puppetId: number, eventId: string): Promise<IReactionStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_for_event"));
const rows = await this.db.All(

@@ -103,2 +113,3 @@ "SELECT * FROM reaction_store WHERE puppet_id = $puppetId AND event_id = $eventId",

}
stopTimer();
return result;

@@ -108,9 +119,13 @@ }

public async delete(reactionMxid: string) {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
await this.db.Run("DELETE FROM reaction_store WHERE reaction_mxid = $reactionMxid", { reactionMxid });
stopTimer();
}
public async deleteForEvent(puppetId: number, eventId: string) {
const stopTimer = this.db.latency.startTimer(this.labels("delete_for_event"));
await this.db.Run("DELETE FROM reaction_store WHERE puppet_id = $puppetId AND event_id = $eventId",
{ puppetId, eventId },
);
stopTimer();
}

@@ -131,2 +146,11 @@

}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "reaction_store",
type: queryName,
};
}
}

@@ -28,5 +28,7 @@ /*

private opCache: TimedCache<string, string>;
private protocol: string;
constructor(
private db: IDatabaseConnector,
cache: boolean = true,
protocol: string = "unknown",
) {

@@ -36,2 +38,3 @@ this.remoteCache = new TimedCache(cache ? ROOM_CACHE_LIFETIME : 0);

this.opCache = new TimedCache(cache ? ROOM_CACHE_LIFETIME : 0);
this.protocol = protocol;
}

@@ -51,2 +54,3 @@

public async getAll(): Promise<IRoomStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
const rows = await this.db.All("SELECT * FROM room_store");

@@ -60,2 +64,3 @@ const results: IRoomStoreEntry[] = [];

}
stopTimer();
return results;

@@ -65,2 +70,3 @@ }

public async getByRemote(puppetId: number, roomId: string): Promise<IRoomStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_remote"));
const cached = this.remoteCache.get(`${puppetId};${roomId}`);

@@ -75,2 +81,3 @@ if (cached) {

});
stopTimer();
return this.getFromRow(row);

@@ -80,2 +87,3 @@ }

public async getByPuppetId(puppetId: number): Promise<IRoomStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_puppet"));
const rows = await this.db.All(

@@ -92,2 +100,3 @@ "SELECT * FROM room_store WHERE puppet_id = $puppet_id", {

}
stopTimer();
return results;

@@ -97,2 +106,3 @@ }

public async getByMxid(mxid: string): Promise<IRoomStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_by_mxid"));
const cached = this.mxidCache.get(mxid);

@@ -105,2 +115,3 @@ if (cached) {

);
stopTimer();
return this.getFromRow(row);

@@ -110,2 +121,3 @@ }

public async set(data: IRoomStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
const exists = await this.db.Get(

@@ -178,5 +190,7 @@ "SELECT * FROM room_store WHERE mxid = $mxid", {mxid: data.mxid},

this.mxidCache.set(data.mxid, data);
stopTimer();
}
public async delete(data: IRoomStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
await this.db.Run(

@@ -191,5 +205,7 @@ "DELETE FROM room_store WHERE mxid = $mxid", { mxid: data.mxid },

this.opCache.delete(data.mxid);
stopTimer();
}
public async toGlobalNamespace(puppetId: number, roomId: string) {
const stopTimer = this.db.latency.startTimer(this.labels("update_namespace"));
const exists = await this.getByRemote(-1, roomId);

@@ -210,5 +226,7 @@ if (exists) {

this.opCache.delete(room.mxid);
stopTimer();
}
public async setRoomOp(roomMxid: string, userMxid: string) {
const stopTimer = this.db.latency.startTimer(this.labels("update_room_op"));
const row = await this.db.Get("SELECT * FROM chan_op WHERE chan_mxid=$chan LIMIT 1", {

@@ -220,2 +238,3 @@ chan: roomMxid,

// nothing to do, we are already set
stopTimer();
return;

@@ -232,5 +251,7 @@ }

this.opCache.set(roomMxid, userMxid);
stopTimer();
}
public async getRoomOp(roomMxid: string): Promise<string|null> {
const stopTimer = this.db.latency.startTimer(this.labels("select_room_op"));
const cached = this.opCache.get(roomMxid);

@@ -248,2 +269,3 @@ if (cached) {

this.opCache.set(roomMxid, userMxid);
stopTimer();
return userMxid;

@@ -276,2 +298,11 @@ }

}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "room_store",
type: queryName,
};
}
}

@@ -20,2 +20,3 @@ /*

import { IDatabaseConnector, ISqlCommandParameters, ISqlRow } from "./connector";
import * as prometheus from "prom-client";
const log = new Log("SQLite3");

@@ -25,2 +26,3 @@

public type = "sqlite";
public latency: prometheus.Histogram<string>;
private db: Database;

@@ -30,2 +32,9 @@ private insertId: number;

this.insertId = -1;
this.latency = new prometheus.Histogram({
name: "bridge_database_query_seconds",
help: "Time spent querying the database engine",
labelNames: ["protocol", "engine", "type", "table"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.0075, 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5],
});
}

@@ -32,0 +41,0 @@

@@ -26,7 +26,10 @@ /*

private usersCache: TimedCache<string, IUserStoreEntry>;
private protocol: string;
constructor(
private db: IDatabaseConnector,
cache: boolean = true,
protocol: string = "unknown",
) {
this.usersCache = new TimedCache(cache ? USERS_CACHE_LIFETIME : 0);
this.protocol = protocol;
}

@@ -41,3 +44,28 @@

public async getAll(): Promise<IUserStoreEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all"));
const results: IUserStoreEntry[] = [];
const rows = await this.db.All(
"SELECT * FROM user_store;",
);
if (!rows) {
return [];
}
for (const r of rows) {
const data = {
name: r.name as string | null,
userId: r.user_id as string,
puppetId: r.puppet_id as number,
avatarUrl: r.avatar_url as string | null,
avatarMxc: r.avatar_mxc as string | null,
avatarHash: r.avatar_hash as string | null,
};
results.push(data);
}
stopTimer();
return results;
}
public async get(puppetId: number, userId: string): Promise<IUserStoreEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("select"));
const cacheKey = `${puppetId};${userId}`;

@@ -60,2 +88,3 @@ const cached = this.usersCache.get(cacheKey);

this.usersCache.set(cacheKey, data);
stopTimer();
return data;

@@ -65,2 +94,3 @@ }

public async set(data: IUserStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update"));
const exists = await this.db.Get(

@@ -104,5 +134,7 @@ "SELECT 1 FROM user_store WHERE user_id = $id AND puppet_id = $pid", {id: data.userId, pid: data.puppetId},

this.usersCache.set(cacheKey, data);
stopTimer();
}
public async delete(data: IUserStoreEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("delete"));
await this.db.Run("DELETE FROM user_store WHERE user_id = $user_id AND puppet_id = $puppet_id", {

@@ -119,2 +151,3 @@ user_id: data.userId,

this.usersCache.delete(cacheKey);
stopTimer();
}

@@ -135,2 +168,3 @@

): Promise<IUserStoreRoomOverrideEntry | null> {
const stopTimer = this.db.latency.startTimer(this.labels("get_room_override"));
const row = await this.db.Get(

@@ -145,2 +179,3 @@ "SELECT * FROM user_store_room_override WHERE user_id = $uid AND puppet_id = $pid AND room_id = $rid", {

}
stopTimer();
return this.getRoomOverrideFromRow(row);

@@ -150,2 +185,3 @@ }

public async setRoomOverride(data: IUserStoreRoomOverrideEntry) {
const stopTimer = this.db.latency.startTimer(this.labels("insert_update_room_override"));
const exists = await this.db.Get(

@@ -193,5 +229,7 @@ "SELECT 1 FROM user_store_room_override WHERE user_id = $uid AND puppet_id = $pid AND room_id = $rid", {

});
stopTimer();
}
public async getAllRoomOverrides(puppetId: number, userId: string): Promise<IUserStoreRoomOverrideEntry[]> {
const stopTimer = this.db.latency.startTimer(this.labels("select_all_room_override"));
const result: IUserStoreRoomOverrideEntry[] = [];

@@ -209,2 +247,3 @@ const rows = await this.db.All(

}
stopTimer();
return result;

@@ -228,2 +267,11 @@ }

}
private labels(queryName: string): object {
return {
protocol: this.protocol,
engine: this.db.type,
table: "user_store",
type: queryName,
};
}
}

@@ -24,2 +24,3 @@ /*

import * as escapeHtml from "escape-html";
import * as prometheus from "prom-client";
import { IPuppet } from "./db/puppetstore";

@@ -42,2 +43,19 @@

this.memberInfoCache = {};
this.bridge.metrics.matrixEvent = new prometheus.Counter({
name: "bridge_matrix_events_total",
help: "Total matrix events bridged to the remote network, by protocol and type",
labelNames: ["protocol", "type"],
});
this.bridge.metrics.matrixEventBucket = new prometheus.Histogram({
name: "bridge_matrix_event_seconds",
help: "Time spent processing matrix events in seconds, by protocol",
labelNames: ["protocol", "type"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.01, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 5, 7, 10],
});
this.bridge.metrics.matrixEventError = new prometheus.Counter({
name: "bridge_matrix_event_errors_total",
help: "Errors encountered during matrix event processing",
labelNames: ["protocol"],
});
}

@@ -48,2 +66,6 @@

this.bridge.AS.on("room.event", async (roomId: string, rawEvent: any) => {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "room.event",
});
try {

@@ -53,2 +75,5 @@ await this.handleRoomEvent(roomId, new RoomEvent<RoomEventContent>(rawEvent));

log.error("Error handling appservice room.event", err.error || err.body || err);
this.bridge.metrics.matrixEventError.inc({protocol: this.bridge.protocol.id});
} finally {
stopTimer();
}

@@ -58,2 +83,6 @@ });

this.bridge.AS.on("room.invite", async (roomId: string, rawEvent: any) => {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "room.invite",
});
try {

@@ -63,2 +92,5 @@ await this.handleInviteEvent(roomId, new MembershipEvent(rawEvent));

log.error("Error handling appservice room.invite", err.error || err.body || err);
this.bridge.metrics.matrixEventError.inc({protocol: this.bridge.protocol.id});
} finally {
stopTimer();
}

@@ -68,6 +100,13 @@ });

this.bridge.AS.on("query.room", async (alias: string, createRoom: any) => {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "query.room",
});
try {
await this.handleRoomQuery(alias, createRoom);
} catch (err) {
this.bridge.metrics.matrixEventError.inc({protocol: this.bridge.protocol.id});
log.error("Error handling appservice query.room", err.error || err.body || err);
} finally {
stopTimer();
}

@@ -77,2 +116,6 @@ });

this.bridge.AS.on("ephemeral.event", async (rawEvent: any) => {
const stopTimer = this.bridge.metrics.matrixEventBucket.startTimer({
protocol: this.bridge.protocol.id,
type: "ephemeral.event",
});
try {

@@ -93,2 +136,3 @@ switch (rawEvent.type) {

}
stopTimer();
});

@@ -142,2 +186,6 @@ }

const membershipEvent = new MembershipEvent(event.raw);
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: `${event.type}.${membershipEvent.membership}`,
});
switch (membershipEvent.membership) {

@@ -157,2 +205,6 @@ case "join":

await this.handleRedactEvent(roomId, evt);
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: event.type,
});
return;

@@ -383,2 +435,6 @@ }

}
this.bridge.metrics.matrixEvent.inc({
protocol: this.bridge.protocol.id,
type: msgtype,
});
}

@@ -606,2 +662,3 @@

await this.bridge.userSync.getClient(parts); // create user, if it doesn't exist
this.bridge.metrics.room?.inc({ type: roomData.isDirect ? "dm" : "group", protocol: this.bridge.protocol.id });
}

@@ -608,0 +665,0 @@

@@ -324,2 +324,3 @@ /*

await this.bridge.roomSync.rebridge(mxid, newRoomParts);
this.bridge.metrics.room.inc({ type: "group", protocol: this.bridge.protocol.id });
}

@@ -341,2 +342,3 @@

await this.bridge.roomSync.delete(roomParts, true);
this.bridge.metrics.room.dec({ type: "group", protocol: this.bridge.protocol.id });
return true;

@@ -401,3 +403,6 @@ }

log.verbose(`No muting in direct rooms`);
} else if (!await this.bridge.namespaceHandler.canSeeRoom(roomParts, userId)) {
} else if (!await this.bridge.namespaceHandler.canSeeRoom({
puppetId: await this.bridge.namespaceHandler.getDbPuppetId(roomParts.puppetId),
roomId: roomParts.roomId,
}, userId)) {
targetLevel = MUTED_POWER_LEVEL;

@@ -469,3 +474,6 @@ }

}
if (await this.bridge.namespaceHandler.canSeeRoom(room, userId)) {
if (await this.bridge.namespaceHandler.canSeeRoom({
roomId: room.roomId,
puppetId: await this.bridge.namespaceHandler.getDbPuppetId(room.puppetId),
}, userId)) {
const client = (await this.bridge.roomSync.getRoomOp(room.mxid)) || this.bridge.botIntent.underlyingClient;

@@ -472,0 +480,0 @@ try {

@@ -25,2 +25,4 @@ /*

import * as yaml from "js-yaml";
import * as prometheus from "prom-client";
import * as express from "express";
import { EventEmitter } from "events";

@@ -100,2 +102,14 @@ import { EmoteSyncroniser } from "./emotesyncroniser";

export class BridgeMetrics {
public room: prometheus.Gauge<string>;
public puppet: prometheus.Gauge<string>;
public message: prometheus.Counter<string>;
public remoteUser: prometheus.Gauge<string>;
public matrixEvent: prometheus.Counter<string>;
public matrixEventBucket: prometheus.Histogram<string>;
public matrixEventError: prometheus.Counter<string>;
public remoteUpdateBucket: prometheus.Histogram<string>;
public connected: prometheus.Gauge<string>;
}
export class PuppetBridge extends EventEmitter {

@@ -119,2 +133,3 @@ public emoteSync: EmoteSyncroniser;

public namespaceHandler: NamespaceHandler;
public metrics: BridgeMetrics;
private appservice: Appservice;

@@ -124,2 +139,3 @@ private mxcLookupLock: Lock<string>;

private remoteEventHandler: RemoteEventHandler;
private connectionMetricStatus: { [puppetId: number]: boolean };

@@ -149,4 +165,26 @@ constructor(

this.hooks = {};
this.connectionMetricStatus = {};
this.delayedFunction = new DelayedFunction();
this.mxcLookupLock = new Lock(MXC_LOOKUP_LOCK_TIMEOUT);
this.metrics = new BridgeMetrics();
this.metrics.room = new prometheus.Gauge({
name: "bridge_rooms_total",
help: "Total rooms bridged to the remote network, by type and protocol",
labelNames: ["type", "protocol"],
});
this.metrics.puppet = new prometheus.Gauge({
name: "bridge_puppets_total",
help: "Puppets linked to remote network, puppeted by matrix users",
labelNames: ["protocol"],
});
this.metrics.connected = new prometheus.Gauge({
name: "bridge_connected",
help: "Users connected to the remote network",
labelNames: ["protocol"],
});
this.metrics.message = new prometheus.Counter({
name: "bridge_messages_total",
help: "Total messages bridged into matrix, by type and protocol",
labelNames: ["type", "protocol"],
});
}

@@ -219,2 +257,13 @@

if (this.config.metrics.enabled) {
prometheus.collectDefaultMetrics();
const metricsServer = express();
metricsServer.get(this.config.metrics.path, async (req, res) => {
res.set("Content-Type", prometheus.register.contentType);
const metrics = await prometheus.register.metrics();
res.send(metrics);
});
metricsServer.listen(this.config.metrics.port);
}
// pipe matrix-bot-sdk logging int ours

@@ -395,2 +444,3 @@ const logMap = new Map<string, Log>();

const puppets = await this.provisioner.getAll();
this.metrics.puppet.set({protocol: this.protocol.id}, puppets.length);
for (const p of puppets) {

@@ -523,5 +573,9 @@ this.emit("puppetNew", p.puppetId, p.data);

const room = await this.namespaceHandler.createRoom(roomData);
if (!room || room.isDirect) {
if (!room) {
return;
}
this.metrics.room.inc({type: room.isDirect ? "dm" : "group", protocol: this.protocol?.id});
if (room.isDirect) {
return;
}
log.info(`Got request to bridge room puppetId=${room.puppetId} roomId=${room.roomId}`);

@@ -548,2 +602,3 @@ await this.roomSync.getMxid(room);

await this.roomSync.delete(room, true);
this.metrics.room.dec({type: room.isDirect ? "dm" : "group", protocol: this.protocol?.id});
}

@@ -683,6 +738,24 @@

public trackConnectionStatus(puppetId: number, isConnected: boolean) {
if (Boolean(this.connectionMetricStatus[puppetId]) === isConnected) {
return;
}
this.connectionMetricStatus[puppetId] = isConnected;
if (isConnected) {
this.metrics.connected.inc({protocol: this.protocol.id});
} else {
this.metrics.connected.dec({protocol: this.protocol.id});
}
}
/**
* Send a status message either to the status message room or to a specified room
*/
public async sendStatusMessage(puppetId: number | IRemoteRoom, msg: string) {
public async sendStatusMessage(puppetId: number | IRemoteRoom, msg: string, isConnected: boolean | null = null) {
if (isConnected !== null) {
this.trackConnectionStatus(
typeof puppetId === "number" ? puppetId : puppetId.puppetId,
isConnected,
);
}
await this.botProvisioner.sendStatusMessage(puppetId, msg);

@@ -710,2 +783,3 @@ }

await this.remoteEventHandler.sendFileByType("m.file", params, thing, name);
this.metrics.message.inc({type: "file", protocol: this.protocol.id});
}

@@ -718,2 +792,3 @@

await this.remoteEventHandler.sendFileByType("m.video", params, thing, name);
this.metrics.message.inc({type: "video", protocol: this.protocol.id});
}

@@ -726,2 +801,3 @@

await this.remoteEventHandler.sendFileByType("m.audio", params, thing, name);
this.metrics.message.inc({type: "audio", protocol: this.protocol.id});
}

@@ -734,2 +810,3 @@

await this.remoteEventHandler.sendFileByType("m.image", params, thing, name);
this.metrics.message.inc({type: "image", protocol: this.protocol.id});
}

@@ -742,2 +819,3 @@

await this.remoteEventHandler.sendMessage(params, opts);
this.metrics.message.inc({type: "text", protocol: this.protocol.id});
}

@@ -750,2 +828,3 @@

await this.remoteEventHandler.sendEdit(params, eventId, opts, ix);
this.metrics.message.inc({type: "edit", protocol: this.protocol.id});
}

@@ -758,2 +837,3 @@

await this.remoteEventHandler.sendRedact(params, eventId);
this.metrics.message.inc({type: "redact", protocol: this.protocol.id});
}

@@ -773,2 +853,3 @@

await this.remoteEventHandler.sendReaction(params, eventId, reaction);
this.metrics.message.inc({type: "reaction", protocol: this.protocol.id});
}

@@ -775,0 +856,0 @@

@@ -25,2 +25,3 @@ /*

import * as unescapeHtml from "unescape";
import * as prometheus from "prom-client";
import { encode as blurhashEncode } from "blurhash";

@@ -48,2 +49,10 @@ import * as Canvas from "canvas";

this.ghostInviteCache = new TimedCache(PUPPET_INVITE_CACHE_LIFETIME);
this.bridge.metrics.remoteUpdateBucket = new prometheus.Histogram({
name: "bridge_remote_update_seconds",
help: "Time spent processing updates from the remote network, by protocol and type",
labelNames: ["protocol", "type"],
// tslint:disable-next-line no-magic-numbers
buckets: [0.002, 0.005, 0.01, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 5, 7, 10],
});
}

@@ -150,2 +159,5 @@

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received message from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -178,2 +190,3 @@ this.preprocessMessageEvent(opts);

await this.bridge.typingHandler.set(await client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
}

@@ -185,2 +198,5 @@

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received edit from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -239,2 +255,3 @@ this.preprocessMessageEvent(opts);

await this.bridge.typingHandler.set(await client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
}

@@ -258,2 +275,5 @@

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received reply from ${params.user.userId} to send to ${params.room.roomId}`);

@@ -295,4 +315,4 @@ this.preprocessMessageEvent(opts);

}
const bodyParts = info.message.body.split("\n");
bodyParts[0] = `${info.message.emote ? "* " : ""}<${info.user.mxid}> ${bodyParts[0]}`;
const bodyParts = this.preprocessBody(info.message.body).split("\n");
bodyParts[0] = `${info.message.emote ? "* " : ""}<${this.preprocessBody(info.user.mxid)}> ${bodyParts[0]}`;
send.body = `${bodyParts.map((l) => `> ${l}`).join("\n")}\n\n${send.body}`;

@@ -318,3 +338,3 @@ const matrixReplyRegex = /^<mx-reply>.*<\/mx-reply>/gs;

}
const plainHeader = `> <${info.user.mxid}> sent ${msg}.\n\n`;
const plainHeader = `> <${this.preprocessBody(info.user.mxid)}> sent ${msg}.\n\n`;
send.body = plainHeader + send.body;

@@ -344,2 +364,3 @@ const richHeader = `<mx-reply><blockquote>

await this.bridge.typingHandler.set(await client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
}

@@ -381,2 +402,5 @@

}
const stopTimer = this.bridge.metrics.remoteUpdateBucket.startTimer({
protocol: this.bridge.protocol.id,
});
log.info(`Received file to send from ${params.user.userId} in ${params.room.roomId}.`);

@@ -533,2 +557,3 @@ log.verbose(`thing=${typeof thing === "string" ? thing : "<Buffer>"} name=${name}`);

await this.bridge.typingHandler.set(await client.getUserId(), mxid, false);
stopTimer({ type: msgtype });
}

@@ -625,7 +650,12 @@

private preprocessMessageEvent(opts: IMessageEvent) {
private preprocessBody(body: string): string {
for (const homeserver of this.bridge.config.bridge.stripHomeservers) {
const urlRegex = homeserver.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
opts.body = opts.body.replace(new RegExp(`@([\x21-\x39\x3b-\x7e]+):${urlRegex}`, "g"), "@$1");
body = body.replace(new RegExp(`@([\x21-\x39\x3b-\x7e]+):${urlRegex}`, "g"), "@$1");
}
return body;
}
private preprocessMessageEvent(opts: IMessageEvent) {
opts.body = this.preprocessBody(opts.body);
if (!opts.formattedBody) {

@@ -632,0 +662,0 @@ return;

@@ -54,2 +54,24 @@ /*

this.mxidLock = new Lock(MXID_LOOKUP_LOCK_TIMEOUT);
if (this.bridge.config.metrics.enabled) {
const roomMetricsInit = (rooms) => {
this.bridge.metrics.room.set(
{
type: "dm",
protocol: this.bridge.protocol.id,
},
rooms.filter((room) => room.isDirect).length,
);
this.bridge.metrics.room.set(
{
type: "group",
protocol: this.bridge.protocol.id,
},
rooms.filter((room) => !room.isDirect).length,
);
};
this.roomStore.getAll()
.catch((err) => log.error("could not get room store"))
.then(roomMetricsInit)
.catch((err) => log.warn("could not init room metrics"));
}
}

@@ -56,0 +78,0 @@

@@ -206,9 +206,9 @@ /*

this.db.Open();
this.pRoomStore = new DbRoomStore(this.db);
this.pUserStore = new DbUserStore(this.db);
this.pGroupStore = new DbGroupStore(this.db);
this.pPuppetStore = new DbPuppetStore(this.db);
this.pEventStore = new DbEventStore(this.db);
this.pReactionStore = new DbReactionStore(this.db);
this.pEmoteStore = new DbEmoteStore(this.db);
this.pRoomStore = new DbRoomStore(this.db, undefined, this.bridge.protocol?.id);
this.pUserStore = new DbUserStore(this.db, undefined, this.bridge.protocol?.id);
this.pGroupStore = new DbGroupStore(this.db, undefined, this.bridge.protocol?.id);
this.pPuppetStore = new DbPuppetStore(this.db, undefined, this.bridge.protocol?.id);
this.pEventStore = new DbEventStore(this.db, this.bridge.protocol?.id);
this.pReactionStore = new DbReactionStore(this.db, this.bridge.protocol?.id);
this.pEmoteStore = new DbEmoteStore(this.db, this.bridge.protocol?.id);
} catch (ex) {

@@ -215,0 +215,0 @@ log.error("Error opening database:", ex);

@@ -24,2 +24,3 @@ /*

import { StringFormatter } from "./structures/stringformatter";
import * as prometheus from "prom-client";

@@ -44,2 +45,12 @@ const log = new Log("UserSync");

this.roomOverrideLock = new Lock(ROOM_OVERRIDE_LOCK_TIMEOUT);
const that = this;
this.bridge.metrics.remoteUser = new prometheus.Gauge({
name: "bridge_remote_users_total",
help: "Total number of users on the remote network",
labelNames: ["protocol"],
async collect() {
const remoteUsers = await that.userStore.getAll();
this.set({protocol: that.bridge.protocol.id}, remoteUsers.length);
},
});
}

@@ -46,0 +57,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc