Skip to content

Commit b2a0fc1

Browse files
committed
feat: hourly pipeline
1 parent 7752b87 commit b2a0fc1

File tree

7 files changed

+742
-0
lines changed

7 files changed

+742
-0
lines changed

gcp-graphql-pipeline/.gcloudignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This file specifies files that are *not* uploaded to Google Cloud
2+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
3+
# "#!include" directives (which insert the entries of the given .gitignore-style
4+
# file at that point).
5+
#
6+
# For more information, run:
7+
# $ gcloud topic gcloudignore
8+
#
9+
.gcloudignore
10+
# If you would like to upload your .git directory, .gitignore file or files
11+
# from your .gitignore file, remove the corresponding line
12+
# below:
13+
.git
14+
.gitignore
15+
16+
node_modules

gcp-graphql-pipeline/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
service-account.json
2+

gcp-graphql-pipeline/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# GCP GraphQL Pipeline
2+
3+
## Prerequisites
4+
5+
Get a `service-account.json` from https://console.cloud.google.com/iam-admin/serviceaccounts/details/111331970552820213056/keys?project=simulationlab
6+
7+
## Development
8+
9+
```sh
10+
export GOOGLE_APPLICATION_CREDENTIALS=service-account.json
11+
./test.js
12+
```
13+
14+
## Deployment
15+
16+
```sh
17+
gcloud functions deploy fetchAndStoreTransactions \
18+
--runtime nodejs22 \
19+
--trigger-http \
20+
--allow-unauthenticated \
21+
--set-env-vars GOOGLE_APPLICATION_CREDENTIALS=service-account.json
22+
```
23+
24+
That will output a URL you can invoke like this,
25+
26+
```
27+
curl -X POST https://us-central1-simulationlab.cloudfunctions.net/fetchAndStoreTransactions
28+
```
29+
30+
That runs every hour right now because of:
31+
32+
```sh
33+
gcloud scheduler jobs create http graphql-job \
34+
--schedule "every 1 hours" \
35+
--uri https://us-central1-simulationlab.cloudfunctions.net/fetchAndStoreTransactions \
36+
--http-method POST
37+
```

gcp-graphql-pipeline/index.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const { google } = require('googleapis');
2+
3+
const SPREADSHEET_ID = '15CZGF-GyqfimwZgrkFTIAkp8xEfHlLQhkp83flXqI84';
4+
const SHEET_NAME = 'live!A2'; // First row is for the existing header
5+
const GRAPHQL_ENDPOINT = 'https://api.subquery.network/sq/agoric-labs/internal';
6+
7+
async function appendToGoogleSheet(data) {
8+
const auth = new google.auth.GoogleAuth({
9+
keyFile: 'service-account.json', // Update with your service account key file
10+
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
11+
});
12+
13+
const sheets = google.sheets({ version: 'v4', auth });
14+
15+
console.log(`Appending ${data.length} rows to Google Sheets...`);
16+
17+
try {
18+
await sheets.spreadsheets.values.update({
19+
spreadsheetId: SPREADSHEET_ID,
20+
range: SHEET_NAME,
21+
valueInputOption: 'USER_ENTERED', // https://developers.google.com/sheets/api/reference/rest/v4/ValueInputOption
22+
requestBody: { values: data },
23+
});
24+
25+
console.log('Data successfully pushed to Google Sheets');
26+
} catch (error) {
27+
console.error('Error appending data to Google Sheets:', error.response?.data || error.message);
28+
throw error;
29+
}
30+
}
31+
32+
exports.fetchAndStoreTransactions = async (req, res) => {
33+
try {
34+
console.log('Fetching transactions from GraphQL API...');
35+
36+
const query = `
37+
query TransactionsQuery {
38+
fastUsdcTransactions(orderBy: SOURCE_BLOCK_TIMESTAMP_DESC) {
39+
edges {
40+
node {
41+
id
42+
sourceAddress
43+
sourceChainId
44+
sourceBlockTimestamp
45+
eud
46+
usdcAmount
47+
status
48+
statusHeight
49+
contractFee
50+
poolFee
51+
risksIdentified
52+
heightObserved
53+
heightAdvanced
54+
heightDisbursed
55+
timeObserved
56+
timeAdvanced
57+
timeDisbursed
58+
}
59+
}
60+
}
61+
}`;
62+
63+
const response = await fetch(GRAPHQL_ENDPOINT, {
64+
method: 'POST',
65+
headers: { 'Content-Type': 'application/json' },
66+
body: JSON.stringify({ query }),
67+
});
68+
69+
if (!response.ok) {
70+
throw new Error(`GraphQL request failed: ${response.statusText}`);
71+
}
72+
73+
const { data } = await response.json();
74+
if (!data) throw new Error('No data received from GraphQL API');
75+
76+
console.log('Raw GraphQL response:', JSON.stringify(data, null, 2));
77+
78+
const transactions = data.fastUsdcTransactions.edges.map((edge) => edge.node);
79+
console.log(`Fetched ${transactions.length} transactions`);
80+
81+
const rows = transactions.map((txn) => {
82+
return [
83+
txn.id,
84+
txn.sourceAddress,
85+
txn.sourceChainId,
86+
txn.sourceBlockTimestamp,
87+
txn.eud,
88+
txn.usdcAmount,
89+
txn.status,
90+
txn.statusHeight,
91+
txn.contractFee,
92+
txn.poolFee,
93+
Array.isArray(txn.risksIdentified) ? txn.risksIdentified.join(', ') : txn.risksIdentified, // Convert array to string
94+
txn.heightObserved,
95+
txn.heightAdvanced,
96+
txn.heightDisbursed,
97+
txn.timeObserved,
98+
txn.timeAdvanced,
99+
txn.timeDisbursed,
100+
];
101+
});
102+
103+
await appendToGoogleSheet(rows);
104+
105+
res.status(200).send('Transactions stored successfully!');
106+
} catch (error) {
107+
console.error('Error fetching or storing transactions:', error.response?.data || error.message);
108+
res.status(500).send('Error fetching or storing transactions');
109+
}
110+
};

0 commit comments

Comments
 (0)