Skip to content

Commit

Permalink
fix: write to dedicated channel collection
Browse files Browse the repository at this point in the history
  • Loading branch information
kevmo314 committed Oct 1, 2022
1 parent 496a103 commit 4f7a63b
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 152 deletions.
19 changes: 13 additions & 6 deletions agent/src/adapters/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,27 @@ export class FirebaseAdapter {
private firestore: admin.firestore.Firestore,
private provider: "twitch",
public debugKeepConnected: Set<String>
) {
}
) {}

getMessage(key: string) {
return this.firestore.collection("messages").doc(key);
getMessage(channelId: string, key: string) {
return this.firestore
.collection("channels")
.doc(channelId)
.collection("messages")
.doc(key);
}

getMetadata(key: string) {
return this.firestore.collection("metadata").doc(key);
}

setIfNotExists(key: string, value: any) {
setIfNotExists(channelId: string, key: string, value: any) {
return this.firestore.runTransaction(async (transaction) => {
const ref = this.firestore.collection("messages").doc(key);
const ref = this.firestore
.collection("channels")
.doc(channelId)
.collection("messages")
.doc(key);
const doc = await transaction.get(ref);
if (doc.exists) {
return;
Expand Down
211 changes: 111 additions & 100 deletions agent/src/agents/twitch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,46 +221,49 @@ async function join(
const badges = tags["badges"]
.split(",")
.map((badge) => badge.split("/") as [string, string]);
await firebase.getMessage(`twitch:${msg.id}`).set({
channelId: `twitch:${msg.channelId}`,
channel,
type: "message",
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
reply: tags["reply-parent-msg-id"]
? {
messageId: `twitch:${tags["reply-parent-msg-id"]}`,
displayName: tags["reply-parent-display-name"],
userLogin: tags["reply-parent-user-login"],
userId: tags["reply-parent-user-id"],
message: tags["reply-parent-msg-body"],
}
: null,
author: {
userId: tags["user-id"],
displayName: tags["display-name"],
login: tags["username"],
},
// we have to shim some tags because the frontend still needs some of these.
tags: {
"user-id": tags["user-id"],
"display-name": tags["display-name"],
username: user,
"room-id": tags["room-id"],
color: tags["color"],
"message-type": isAction ? "action" : "chat",
"badges-raw": tags["badges"],
badges: {
vip: badges.find((badge) => badge[0] === "vip") !== null,
moderator: badges.find((badge) => badge[0] === "moderator") !== null,
await firebase
.getMessage(`twitch:${msg.channelId}`, `twitch:${msg.id}`)
.set({
channelId: `twitch:${msg.channelId}`,
channel,
type: "message",
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
reply: tags["reply-parent-msg-id"]
? {
messageId: `twitch:${tags["reply-parent-msg-id"]}`,
displayName: tags["reply-parent-display-name"],
userLogin: tags["reply-parent-user-login"],
userId: tags["reply-parent-user-id"],
message: tags["reply-parent-msg-body"],
}
: null,
author: {
userId: tags["user-id"],
displayName: tags["display-name"],
login: tags["username"],
},
"emotes-raw": tags["emotes"],
},
message,
annotations: {
isFirstTimeChatter: tags["first-msg"] === "1",
isAction,
},
});
// we have to shim some tags because the frontend still needs some of these.
tags: {
"user-id": tags["user-id"],
"display-name": tags["display-name"],
username: user,
"room-id": tags["room-id"],
color: tags["color"],
"message-type": isAction ? "action" : "chat",
"badges-raw": tags["badges"],
badges: {
vip: badges.find((badge) => badge[0] === "vip") !== null,
moderator:
badges.find((badge) => badge[0] === "moderator") !== null,
},
"emotes-raw": tags["emotes"],
},
message,
annotations: {
isFirstTimeChatter: tags["first-msg"] === "1",
isAction,
},
});
});

chat.onAnnouncement(async (channel, user, announcement, msg) => {
Expand All @@ -283,84 +286,91 @@ async function join(
const badges = tags["badges"]
.split(",")
.map((badge) => badge.split("/") as [string, string]);
await firebase.getMessage(`twitch:${msg.id}`).set({
channelId: `twitch:${msg.channelId}`,
channel,
type: "message",
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
reply: tags["reply-parent-msg-id"]
? {
messageId: `twitch:${tags["reply-parent-msg-id"]}`,
displayName: tags["reply-parent-display-name"],
userLogin: tags["reply-parent-user-login"],
userId: tags["reply-parent-user-id"],
message: tags["reply-parent-msg-body"],
}
: null,
author: {
userId: tags["user-id"],
displayName: tags["display-name"],
login: tags["username"],
},
// we have to shim some tags because the frontend still needs some of these.
tags: {
"user-id": tags["user-id"],
"display-name": tags["display-name"],
username: user,
"room-id": tags["room-id"],
color: tags["color"],
"message-type": "chat",
"badges-raw": tags["badges"],
badges: {
vip: badges.find((badge) => badge[0] === "vip") !== null,
moderator: badges.find((badge) => badge[0] === "moderator") !== null,
await firebase
.getMessage(`twitch:${msg.channelId}`, `twitch:${msg.id}`)
.set({
channelId: `twitch:${msg.channelId}`,
channel,
type: "message",
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
reply: tags["reply-parent-msg-id"]
? {
messageId: `twitch:${tags["reply-parent-msg-id"]}`,
displayName: tags["reply-parent-display-name"],
userLogin: tags["reply-parent-user-login"],
userId: tags["reply-parent-user-id"],
message: tags["reply-parent-msg-body"],
}
: null,
author: {
userId: tags["user-id"],
displayName: tags["display-name"],
login: tags["username"],
},
"emotes-raw": tags["emotes"],
},
message,
annotations: {
announcement: { color: announcement.color },
isFirstTimeChatter: tags["first-msg"] === "1",
},
});
// we have to shim some tags because the frontend still needs some of these.
tags: {
"user-id": tags["user-id"],
"display-name": tags["display-name"],
username: user,
"room-id": tags["room-id"],
color: tags["color"],
"message-type": "chat",
"badges-raw": tags["badges"],
badges: {
vip: badges.find((badge) => badge[0] === "vip") !== null,
moderator:
badges.find((badge) => badge[0] === "moderator") !== null,
},
"emotes-raw": tags["emotes"],
},
message,
annotations: {
announcement: { color: announcement.color },
isFirstTimeChatter: tags["first-msg"] === "1",
},
});
});

chat.onMessageRemove(async (channel, messageId, msg) => {
const original = await firebase.getMessage(`twitch:${messageId}`).get();
if (!original.exists) {
log.error({ messageId, timestamp: msg.date }, "no message to delete");
return;
}
await firebase.getMessage(`twitch:x-${messageId}`).set({
const channelId = `twitch:${await getTwitchUserId(channel)}`;
await firebase.getMessage(channelId, `twitch:x-${messageId}`).set({
channel,
channelId: original.get("channelId"),
channelId,
type: "messagedeleted",
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
messageId: `twitch:${messageId}`,
});
});

chat.onChatClear(async (channel, msg) => {
await firebase.getMessage(`twitch:clear-${msg.date.toISOString()}`).set({
channel,
channelId: `twitch:${msg.channelId}`,
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
type: "clear",
});
await firebase
.getMessage(
`twitch:${msg.channelId}`,
`twitch:clear-${msg.date.toISOString()}`
)
.set({
channel,
channelId: `twitch:${msg.channelId}`,
timestamp: admin.firestore.Timestamp.fromDate(msg.date),
type: "clear",
});
});

chat.onHosted(async (channel, hosterChannel, auto, viewers) => {
// host messages don't have an associated timestamp so the best we can do is use the current date stamp.
const timestamp = new Date();
await firebase.getMessage(`twitch:host-${timestamp.toISOString()}`).set({
channel: `#${channel}`,
channelId: `twitch:${await getTwitchUserId(channel)}`,
type: "host",
displayName: hosterChannel,
hosterChannelId: `twitch:${await getTwitchUserId(hosterChannel)}`,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
viewers: viewers || 0, // includes the original I guess.
});
const channelId = `twitch:${await getTwitchUserId(channel)}`;
await firebase
.getMessage(channelId, `twitch:host-${timestamp.toISOString()}`)
.set({
channel: `#${channel}`,
channelId,
type: "host",
displayName: hosterChannel,
hosterChannelId: `twitch:${await getTwitchUserId(hosterChannel)}`,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
viewers: viewers || 0, // includes the original I guess.
});
});

chat.onR9k(async (channel, enabled) => {
Expand Down Expand Up @@ -464,6 +474,7 @@ async function join(
raidListener = await pubsub.onCustomTopic("raid", async (message) => {
const data = message.data as any;
await firebase.setIfNotExists(
`twitch:${data["raid"]["source_id"]}`,
`twitch:${data["type"]}-${data["raid"]["id"]}`,
{
channel,
Expand Down
2 changes: 2 additions & 0 deletions auxiliary/src/streamlabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ function listenForSingleUserId(userId: string) {
mergeMap((donation) => {
return admin
.firestore()
.collection("channels")
.doc(donation.channelId)
.collection("messages")
.doc(`streamlabs-${donation.channelId}-${donation.id}`)
.set({
Expand Down
4 changes: 4 additions & 0 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ service cloud.firestore {
allow read: if true;
allow write: if false;
}
match /channels/{channelId}/messages/{document=**} {
allow read: if true;
allow write: if false;
}
match /chat-status/{document=**} {
allow list: if request.query.limit == 1;
allow get: if true;
Expand Down
29 changes: 17 additions & 12 deletions functions/src/alchemy_webhook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,23 @@ async function storeDonation(
functions.logger.info("ChannelId obtained", { channelId: channelId });

// storing donation respoonses in realtimecash collection
await admin.firestore().collection("messages").add({
channelId: channelId,
webhookId: notification.webhookId,
id: notification.id,
createdAt: notification.createdAt,
type: "realtimecash.donation",
notificationType: notification.type,
activity: activity,
donor: donor,
message: message,
timestamp: new Date(),
});
await admin
.firestore()
.collection("channels")
.doc(channelId)
.collection("messages")
.add({
channelId: channelId,
webhookId: notification.webhookId,
id: notification.id,
createdAt: notification.createdAt,
type: "realtimecash.donation",
notificationType: notification.type,
activity: activity,
donor: donor,
message: message,
timestamp: new Date(),
});
functions.logger.info("Payload is stored in messages collection");
}

Expand Down
12 changes: 7 additions & 5 deletions functions/src/eventsub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,18 @@ export const eventsub = functions.https.onRequest(async (req, res) => {
} else if (status === "enabled") {
const type = req.body?.subscription?.type as EventsubType;

const messageRef = admin
.firestore()
.collection("messages")
.doc(`twitch:${messageId}`);

const channelId = `twitch:${
req.body.event["broadcaster_user_id"] ??
req.body.event["to_broadcaster_user_id"]
}`;

const messageRef = admin
.firestore()
.collection("channels")
.doc(channelId)
.collection("messages")
.doc(`twitch:${messageId}`);

await messageRef.set({
channelId,
type,
Expand Down
4 changes: 2 additions & 2 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getUserEmotes, getEmotes } from "./emotes";
import { eventsub } from "./eventsub";
import { getAppAccessToken, TWITCH_CLIENT_ID } from "./oauth";
import { search } from "./search";
import { cleanup, subscribe, unsubscribe } from "./subscriptions";
import { migrate, subscribe, unsubscribe } from "./subscriptions";
import { synthesize, getVoices } from "./tts";
import { getTwitchLogin, getChannelId } from "./twitch";
import { updateChatStatus } from "./chat-status";
Expand Down Expand Up @@ -472,7 +472,7 @@ export {
search,
getUserEmotes,
getEmotes,
cleanup,
migrate,
synthesize,
getVoices,
updateChatStatus,
Expand Down
Loading

0 comments on commit 4f7a63b

Please sign in to comment.