|
|
|
const mx = require('matrix-appservice-bridge');
|
|
|
|
const tmi = require('tmi.js');
|
|
|
|
|
|
|
|
// has to be defined here because of scope
|
|
|
|
let bridge;
|
|
|
|
let tmiListener;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Matrix part
|
|
|
|
async function matrixEventHandler(request, context) {
|
|
|
|
const event = request.getData();
|
|
|
|
|
|
|
|
if(event.type === 'm.room.message') {
|
|
|
|
const message = event.content.body;
|
|
|
|
const remoteUsers = await bridge.getUserStore().getRemoteUsersFromMatrixId(event.sender);
|
|
|
|
// use the first user, multipe user mappings are unsupported
|
|
|
|
const remoteUser = remoteUsers[0];
|
|
|
|
const tmiUsername = remoteUser.id;
|
|
|
|
const tmiPassword = remoteUser.data.password;
|
|
|
|
|
|
|
|
const remoteRooms = await bridge.getRoomStore().getLinkedRemoteRooms(event.room_id);
|
|
|
|
remoteRooms.forEach(remoteRoom => {
|
|
|
|
const tmiClient = new tmi.Client({
|
|
|
|
connection: {
|
|
|
|
secure: true,
|
|
|
|
},
|
|
|
|
identity: {
|
|
|
|
username: tmiUsername,
|
|
|
|
password: tmiPassword
|
|
|
|
},
|
|
|
|
channels: [
|
|
|
|
remoteRoom.roomId
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
// connect to tmi, send message and disconnect
|
|
|
|
tmiClient.connect();
|
|
|
|
tmiClient.on('connected', () => {
|
|
|
|
tmiClient.say(remoteRoom.roomId, message);
|
|
|
|
tmiClient.disconnect();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else if(event.content.membership === 'invite' && event.state_key === '@'+bridge.opts.registration.sender_localpart+':'+bridge.opts.domain) {
|
|
|
|
// auto-join on invite
|
|
|
|
bridge.getIntent().join(event.room_id);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
new mx.Cli({
|
|
|
|
registrationPath: 'matritch-registration.yaml',
|
|
|
|
generateRegistration: (reg, callback) => {
|
|
|
|
reg.setId(mx.AppServiceRegistration.generateToken());
|
|
|
|
reg.setHomeserverToken(mx.AppServiceRegistration.generateToken());
|
|
|
|
reg.setAppServiceToken(mx.AppServiceRegistration.generateToken());
|
|
|
|
reg.setSenderLocalpart('_matritch');
|
|
|
|
reg.addRegexPattern('users', '@_matritch_.*', true);
|
|
|
|
callback(reg);
|
|
|
|
},
|
|
|
|
run: async (port, config) => {
|
|
|
|
bridge = new mx.Bridge({
|
|
|
|
homeserverUrl: process.env.HOMESEVER || 'http://localhost:8008',
|
|
|
|
domain: process.env.DOMAIN || 'localhost',
|
|
|
|
registration: 'matritch-registration.yaml',
|
|
|
|
controller: {
|
|
|
|
onUserQuery: queriedUser => {
|
|
|
|
// auto-provision users with no additonal data
|
|
|
|
console.log(JSON.stringify(queriedUser))
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
onEvent: matrixEventHandler
|
|
|
|
}
|
|
|
|
});
|
|
|
|
console.log('Matrix-side listening on port %s', port);
|
|
|
|
|
|
|
|
await bridge.run(port, config);
|
|
|
|
connectTmiListener();
|
|
|
|
}
|
|
|
|
}).run();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Twitch part
|
|
|
|
const localpartPrefix = bridge.opts.registration.namespaces.users[0].regex.slice(0, -2);
|
|
|
|
const domain = bridge.opts.domain;
|
|
|
|
|
|
|
|
|
|
|
|
async function tmiEventHandler(target, context, message, self) {
|
|
|
|
const remoteUsers = await bridge.getUserStore().getRemoteUser(context.username)
|
|
|
|
if(remoteUsers) {
|
|
|
|
// ignore messages from briged users
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const matrixRooms = await bridge.getRoomStore().getLinkedMatrixRooms(target);
|
|
|
|
matrixRooms.forEach(matrixRoom => {
|
|
|
|
const intent = bridge.getIntent(localpartPrefix+context.username+':'+domain);
|
|
|
|
intent.sendText(matrixRoom.roomId, message);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
async function connectTmiListener() {
|
|
|
|
const remoteRooms = await bridge.getRoomStore().select({
|
|
|
|
matrix_id: {$exists: true},
|
|
|
|
remote_id: {$exists: true}
|
|
|
|
});
|
|
|
|
const channels = remoteRooms.map(remoteRoom => {
|
|
|
|
return remoteRoom.remote_id;
|
|
|
|
});
|
|
|
|
|
|
|
|
const tmiAnonymousOptions = {
|
|
|
|
connection: {
|
|
|
|
secure: true,
|
|
|
|
reconnect: true
|
|
|
|
},
|
|
|
|
channels: channels
|
|
|
|
};
|
|
|
|
tmiListener = new tmi.Client(tmiAnonymousOptions);
|
|
|
|
tmiListener.on('message', tmiEventHandler);
|
|
|
|
tmiListener.connect();
|
|
|
|
}
|