Skip to content

Commit 9532ef7

Browse files
authored
Merge pull request #4214 from thematters/feat/ipns-trigger
IPNS trigger
2 parents 4c468e5 + 84386e9 commit 9532ef7

File tree

10 files changed

+91
-50
lines changed

10 files changed

+91
-50
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ MATTERS_AWS_ARCHIVE_USER_QUEUE_URL="https://sqs.ap-southeast-1.amazonaws.com/903
2323
MATTERS_AWS_LIKECOIN_LIKE_QUEUE_URL="https://sqs.ap-southeast-1.amazonaws.com/903380195283/likecoin-like-dev.fifo"
2424
MATTERS_AWS_LIKECOIN_SEND_PV_QUEUE_URL=""
2525
MATTERS_AWS_LIKECOIN_UPDATE_CIVIC_LIKER_CACHE_QUEUE_URL="https://sqs.ap-southeast-1.amazonaws.com/903380195283/likecoin-update-civic-liker-cache-dev"
26+
MATTERS_AWS_IPNS_USER_PUBLICATION_QUEUE_URL="https://sqs.ap-southeast-1.amazonaws.com/903380195283/ipns-user-publication-dev"
2627

2728
MATTERS_PG_HOST=db
2829
MATTERS_PG_USER=postgres
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const table = 'user'
2+
const ensNameColumn = 'ens_name'
3+
const ensNameUpdatedAtColumn = 'ens_name_updated_at'
4+
5+
exports.up = async (knex) => {
6+
await knex.schema.table(table, (t) => {
7+
t.string(ensNameColumn)
8+
t.timestamp(ensNameUpdatedAtColumn)
9+
})
10+
}
11+
12+
exports.down = async (knex) => {
13+
await knex.schema.table(table, (t) => {
14+
t.dropColumn(ensNameColumn)
15+
t.dropColumn(ensNameUpdatedAtColumn)
16+
})
17+
}

src/common/enums/payment.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { optimism, optimismSepolia, polygon, polygonMumbai } from 'viem/chains'
1+
import {
2+
mainnet,
3+
optimism,
4+
optimismSepolia,
5+
polygon,
6+
polygonMumbai,
7+
sepolia,
8+
} from 'viem/chains'
29

310
import { environment, isProd } from 'common/environment'
411
import { GQLChain } from 'definitions'
@@ -66,6 +73,8 @@ export const BLOCKCHAIN_CHAINID = {
6673
} as const
6774

6875
export const BLOCKCHAIN_RPC: { [chainId: string]: string } = {
76+
[mainnet.id]: `https://eth-mainnet.g.alchemy.com/v2/${environment.alchemyApiKey}`,
77+
[sepolia.id]: `https://eth-sepolia.g.alchemy.com/v2/${environment.alchemyApiKey}`,
6978
[polygon.id]: `https://polygon-mainnet.g.alchemy.com/v2/${environment.alchemyApiKey}`,
7079
[optimism.id]: `https://opt-mainnet.g.alchemy.com/v2/${environment.alchemyApiKey}`,
7180
[optimismSepolia.id]: `https://opt-sepolia.g.alchemy.com/v2/${environment.alchemyApiKey}`,

src/common/enums/sqs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ export const QUEUE_URL = {
1414
// sendmail
1515
mail: environment?.awsMailQueueUrl,
1616
expressMail: environment?.awsExpressMailQueueUrl,
17+
18+
// IPNS
19+
ipnsUserPublication: environment?.awsIpnsUserPublicationQueueUrl,
1720
} as const

src/common/environment.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export const environment = {
5050
process.env.MATTERS_AWS_LIKECOIN_SEND_PV_QUEUE_URL || '',
5151
awsLikecoinUpdateCivicLikerCache:
5252
process.env.MATTERS_AWS_LIKECOIN_UPDATE_CIVIC_LIKER_CACHE_QUEUE_URL || '',
53+
awsIpnsUserPublicationQueueUrl:
54+
process.env.MATTERS_AWS_IPNS_USER_PUBLICATION_QUEUE_URL || '',
5355
tsQiServerUrl: process.env.MATTERS_TSQI_SERVER_URL || '',
5456
awsCloudFrontEndpoint: process.env.MATTERS_AWS_CLOUD_FRONT_ENDPOINT,
5557
cloudflareAccountId: process.env.MATTERS_CLOUDFLARE_ACCOUNT_ID,

src/connectors/articleService.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
USER_ACTION,
4141
USER_STATE,
4242
NODE_TYPES,
43+
QUEUE_URL,
4344
} from 'common/enums'
4445
import { environment } from 'common/environment'
4546
import {
@@ -922,20 +923,29 @@ export class ArticleService extends BaseService<Article> {
922923
throw new NetworkError('failed publishToIPFS')
923924
}
924925

925-
// DEPRECATED, To Be Deleted
926-
// moved to IPNS-Listener
927926
public publishFeedToIPNS = async ({ userName }: { userName: string }) => {
928927
const userService = new UserService(this.connections)
929928

930929
try {
930+
// skip if no ENS name
931+
const ensName = await userService.findEnsName(userName)
932+
if (!ensName) {
933+
return
934+
}
935+
931936
const ipnsKeyRec = await userService.findOrCreateIPNSKey(userName)
932937
if (!ipnsKeyRec) {
933-
// cannot do anything if no ipns key
938+
// cannot do anything if no IPNS key
934939
logger.error('create IPNS key ERROR: %o', ipnsKeyRec)
935940
return
936941
}
942+
943+
this.aws.sqsSendMessage({
944+
messageBody: { userName, useMattersIPNS: true },
945+
queueUrl: QUEUE_URL.ipnsUserPublication,
946+
})
937947
} catch (error) {
938-
logger.error('create IPNS key ERROR: %o', error)
948+
logger.error('publishFeedToIPNS ERROR: %o', error)
939949
return
940950
}
941951
}

src/connectors/queue/publication.ts

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,6 @@ export class PublicationQueue {
7474
}
7575
)
7676

77-
public refreshIPNSFeed = ({
78-
userName,
79-
numArticles = 50,
80-
forceReplace,
81-
}: {
82-
userName: string
83-
numArticles?: number
84-
forceReplace?: boolean
85-
}) =>
86-
this.q.add(QUEUE_JOB.refreshIPNSFeed, {
87-
userName,
88-
numArticles,
89-
forceReplace,
90-
})
91-
9277
/**
9378
* Consumers
9479
*/
@@ -99,12 +84,6 @@ export class PublicationQueue {
9984
QUEUE_CONCURRENCY.publishArticle,
10085
this.handlePublishArticle
10186
)
102-
103-
this.q.process(
104-
QUEUE_JOB.refreshIPNSFeed,
105-
QUEUE_CONCURRENCY.refreshIPNSFeed,
106-
this.handleRefreshIPNSFeed
107-
)
10887
}
10988

11089
/**
@@ -587,17 +566,4 @@ export class PublicationQueue {
587566
// logger.error(e)
588567
// }
589568
// }
590-
591-
private handleRefreshIPNSFeed: ProcessCallbackFunction<unknown> = async (
592-
job // use Promise based job processing instead of `done`
593-
) => {
594-
const articleService = new ArticleService(this.connections)
595-
return articleService.publishFeedToIPNS(
596-
job.data as {
597-
userName: string
598-
numArticles: number
599-
forceReplace?: boolean
600-
}
601-
)
602-
}
603569
}

src/connectors/userService.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
recoverMessageAddress,
3636
trim,
3737
} from 'viem'
38-
import { polygon } from 'viem/chains'
38+
import { mainnet, polygon, sepolia } from 'viem/chains'
3939

4040
import {
4141
OFFICIAL_NOTICE_EXTEND_TYPE,
@@ -75,6 +75,7 @@ import {
7575
AUDIT_LOG_STATUS,
7676
METRICS_NAMES,
7777
BLOCKCHAIN_RPC,
78+
DAY,
7879
} from 'common/enums'
7980
import { environment, isProd } from 'common/environment'
8081
import {
@@ -2074,6 +2075,39 @@ export class UserService extends BaseService<User> {
20742075
})
20752076
}
20762077

2078+
public findEnsName = async (userName: string) => {
2079+
const user = await this.findByUserName(userName)
2080+
if (!user || !user.ethAddress) {
2081+
return
2082+
}
2083+
2084+
const now = new Date()
2085+
const oneDayAgo = new Date(now.getTime() - 1 * DAY)
2086+
2087+
if (
2088+
user.userName &&
2089+
user.ensNameUpdatedAt &&
2090+
user.ensNameUpdatedAt > oneDayAgo
2091+
) {
2092+
return user.ensName
2093+
}
2094+
2095+
// Query ENS if data is stale or missing
2096+
const client = createPublicClient({
2097+
chain: isProd ? mainnet : sepolia,
2098+
transport: http(BLOCKCHAIN_RPC[isProd ? mainnet.id : sepolia.id]),
2099+
})
2100+
const ensName = await client.getEnsName({
2101+
address: user.ethAddress as `0x${string}`,
2102+
})
2103+
await this.models.update({
2104+
table: 'user',
2105+
where: { id: user.id },
2106+
data: { ensName, ensNameUpdatedAt: now },
2107+
})
2108+
return ensName
2109+
}
2110+
20772111
/*********************************
20782112
* *
20792113
* Restrictions *

src/definitions/user.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ interface UserBase {
2727
state: UserState
2828
agreeOn: string
2929
ethAddress: string | null
30+
ensName: string | null
31+
ensNameUpdatedAt: Date | null
3032
currency: 'HKD' | 'TWD' | 'USD' | null
3133
profileCover?: string
3234
// eslint-disable-next-line @typescript-eslint/no-explicit-any

src/mutations/user/refreshIPNSFeed.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
import type { GQLMutationResolvers } from 'definitions'
22

3+
import { QUEUE_URL } from 'common/enums'
4+
import { aws } from 'connectors'
5+
36
const resolver: GQLMutationResolvers['refreshIPNSFeed'] = async (
47
_,
58
{ input: { userName, numArticles = 50 } },
6-
{
7-
dataSources: {
8-
userService,
9-
queues: { publicationQueue },
10-
},
11-
}
9+
{ dataSources: { userService } }
1210
) => {
1311
const ipnsKeyRec = await userService.findOrCreateIPNSKey(userName)
1412

1513
if (ipnsKeyRec) {
16-
publicationQueue.refreshIPNSFeed({
17-
userName,
18-
numArticles,
19-
forceReplace: true,
14+
aws.sqsSendMessage({
15+
messageBody: { userName, useMattersIPNS: true },
16+
queueUrl: QUEUE_URL.ipnsUserPublication,
2017
})
2118
}
2219

0 commit comments

Comments
 (0)