-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
159 lines (149 loc) · 6.31 KB
/
server.js
File metadata and controls
159 lines (149 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import express from 'express';
import cors from 'cors';
import redis from 'redis';
// import { db } from './firebase.js';
const app = express();
const port = process.env.PORT || 3000; // Ensure using PORT from environment in production
console.log(`client redis url: ${process.env.REDIS_URL}`)
const client = redis.createClient({
url: process.env.REDIS_URL,
socket: {
connectTimeout: 10000
}
});
await client.connect();
await client.flushDb();
console.log(` / client open: ${client.isOpen}`);
import axios from 'axios';
import { init, fetchQuery } from "@airstack/node";
init(process.env.AIRSTACK_API_KEY)
app.use(express.json()); // For parsing application/json
app.use(cors());
// GraphQL query as a string
const graphqlQuery = `
query MyQuery($fids: [Identity!], $startTime: Time) {
FarcasterCasts(
input: {filter: {castedBy: {_in: $fids}, castedAtTimestamp: {_gte: $startTime}}, blockchain: ALL}
) {
Cast {
embeds
text
channel {
name
}
fid
}
}
}
`;
const processFid = async (fid) => {
const pbURL = 'https://api.warpcast.com/v2/power-badge-users';
let powerBadgeUsers;
console.log(`STARTING PROCESSING FID: ${fid}`);
try {
const response = await axios.get(pbURL);
powerBadgeUsers = response.data.result.fids; // Adjusting path to match actual response structure
} catch (error) {
console.error('Error fetching power badge users:', error);
await client.set(`status:${fid}`, 'error')
}
let isPowerUser = powerBadgeUsers.includes(fid);
let openrankURL = 'https://graph.cast.k3l.io/scores/personalized/engagement/fids?k=3&limit=4999';
let globalRankUrl = `https://graph.cast.k3l.io/scores/global/engagement/fids`;
// If power badge user, fetch engagement scores
// isPowerUser = true
try {
const openRankResponse = await axios.post(globalRankUrl, [fid], {
headers: {
'Content-Type': 'application/json'
}
});
console.log(`openRankResult: ${JSON.stringify(openRankResponse?.data?.result)}`);
const openRank = openRankResponse?.data?.result?.[0];
const engagementScores = await axios.post(openrankURL, [fid], {
headers: {
'Content-Type': 'application/json'
}
});
// Filter out power badge users from the engagement scores
let filteredScores
if (isPowerUser){
console.log("Fid", fid, "is a poweruser");
filteredScores = engagementScores.data.result.filter(score =>
!powerBadgeUsers.includes(score.fid) // Assuming each score object has an 'fid' property
);
} else {
console.log("Fid", fid, "is not a poweruser... fetching power users that are highly engaging");
filteredScores = engagementScores.data.result.filter(score =>
powerBadgeUsers.includes(score.fid) // Assuming each score object has an 'fid' property
);
}
let randomNumber = Math.floor(Math.random() * filteredScores.length) + 2;
const fids = filteredScores.map(item => `fc_fid:${item.fid}`);
const now = new Date(); // Current date and time
const fortyEightHoursAgo = new Date(now.getTime() - (48 * 60 * 60 * 1000)); // Subtract 48 hours in milliseconds
// Convert to ISO string for use in APIs
const startTime = fortyEightHoursAgo.toISOString();
const variables = {
fids: fids,
startTime: startTime
};
const data = await fetchQuery(graphqlQuery, variables);
const casts = data.data.FarcasterCasts.Cast;
const fidsFromCasts = casts.map(cast => cast.fid);
randomNumber = Math.floor(Math.random() * fidsFromCasts.length/2) + 2;
let finalFid= fidsFromCasts[randomNumber]
const matchingObject = filteredScores.find(score => score.fid == finalFid);
console.log({...matchingObject, openRank: openRank, powerBadge: isPowerUser})
await client.set(`data:${fid}`, JSON.stringify({...matchingObject, user: { openRank: openRank, powerBadge: isPowerUser}}));
await client.set(`status:${fid}`, 'complete');
//res.json({...matchingObject, user: { openRank: openRank, powerBadge: true}})
} catch (error) {
console.error('Error fetching power badge users:', error);
await client.set(`status:${fid}`, 'error')
//res.status(500).send('Failed to fetch power badge users');
}
}
// Endpoint to start
app.get('/start/:fid', async (req, res) => {
console.log("### Starting server....")
console.log(`client open? ${client.isOpen}`);
const userFid = parseInt(req.params.fid); // Accessing the fid parameter from the URL
const action = req.query.action;
// if action is "start", start a fresh pull for user, reset the status and data for fid
console.log(`ACTION: ${action}`)
if(action === 'start') {
await client.del(`status:${userFid}`);
await client.del(`data:${userFid}`);
}
const status = await client.get(`status:${userFid}`);
console.log(`STATUS RETURNED: ${status}`);
if(status === 'processing') {
res.json({status: status});
} else if(status === 'complete') {
// get data for user and convert back to json
const data = await client.get(`data:${userFid}`);
try {
const jsonData = JSON.parse(data);
res.json({...jsonData, status: status});
} catch (e) {
res.json({ status: 'error' });
}
} else {
await client.set(`status:${userFid}`, 'processing');
processFid(userFid);
res.json({ status: 'processing'});
}
});
app.get('/user-relevant-cast/:fid/:targetFid', async (req, res) => {
const userDoc = db.collection('openrank-farhack').doc(req.params.fid);
const userDocData = (await userDoc.get())?.data();
if (userDocData && userDocData.cast) {
return res.json(userDocData);
} else {
return res.json({loading: true});
}
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});