Skip to content

Commit

Permalink
Merge pull request #18 from tomrpl/feat/fixing-warning-return-error
Browse files Browse the repository at this point in the history
feat(location): adding implem
  • Loading branch information
tomrpl authored Aug 1, 2024
2 parents 328a7a4 + 6cc0e9f commit bfbf62d
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*

.env
.env
/read
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@testing-library/user-event": "^13.5.0",
"@types/file-saver": "^2.0.7",
"@types/react-modal": "^3.16.3",
"@upstash/redis": "^1.34.0",
"crypto-browserify": "^3.12.0",
"ethers": "^6.13.1",
"ethers-multicall-provider": "^6.4.0",
Expand Down
13 changes: 12 additions & 1 deletion src/component/OracleDecoder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import CheckItemFeeds from "./common/CheckItemFeeds";
import useRouteMatch from "../hooks/testor/useRouteMatch";
import CheckItemPrice from "./common/CheckItemPrice";
import useOraclePriceCheck from "../hooks/testor/useOraclePriceCheck";
import { initializeUser, recordQuery } from "../services/rate/userClick";

const ethLogo = "https://cdn.morpho.org/assets/chains/eth.svg";
const baseLogo = "https://cdn.morpho.org/assets/chains/base.png";
Expand All @@ -34,6 +35,7 @@ const OracleDecoder = () => {
const [countdown, setCountdown] = useState(5);
const [submitStarted, setSubmitStarted] = useState(false);
const [triggerCheck, setTriggerCheck] = useState(false);
const [userId, setUserId] = useState<string | null>(null);

const [selectedNetwork, setSelectedNetwork] = useState<{
value: number;
Expand Down Expand Up @@ -147,7 +149,16 @@ const OracleDecoder = () => {
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
resetState();

try {
const locationAddress = window.location.hostname;
if (!userId) {
const newUserId = await initializeUser(locationAddress);
setUserId(newUserId);
}
await recordQuery(userId || "", locationAddress);
} catch (error) {
console.log("Error updating click count");
}
setIsSubmitting(true);
setSubmitStarted(true);

Expand Down
14 changes: 12 additions & 2 deletions src/component/OracleTestor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CheckItemFeeds from "./common/CheckItemFeeds";
import { Asset } from "../hooks/types";
import useOracleDeploymentCheck from "../hooks/testor/useOracleDeploymentCheck";
import CheckItemDeployment from "./common/CheckItemDeployment";
import { initializeUser, recordQuery } from "../services/rate/userClick";

const ethLogo = "https://cdn.morpho.org/assets/chains/eth.svg";
const baseLogo = "https://cdn.morpho.org/assets/chains/base.png";
Expand All @@ -33,7 +34,7 @@ const OracleTestor = () => {
const [submitStarted, setSubmitStarted] = useState(false);
const [formSubmitted, setFormSubmitted] = useState(false);
const [showPayload, setShowPayload] = useState(false);

const [userId, setUserId] = useState<string | null>(null);
const [selectedNetwork, setSelectedNetwork] = useState<{
value: number;
label: JSX.Element;
Expand Down Expand Up @@ -167,7 +168,16 @@ const OracleTestor = () => {
event.preventDefault();

resetState();

try {
const locationAddress = window.location.hostname;
if (!userId) {
const newUserId = await initializeUser(locationAddress);
setUserId(newUserId);
}
await recordQuery(userId || "", locationAddress);
} catch (error) {
console.log("Error updating click count");
}
setIsSubmitting(true);
setSubmitStarted(true);
setFormSubmitted(true);
Expand Down
140 changes: 140 additions & 0 deletions src/services/rate/userClick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
class RedisManager {
private static instance: RedisManager;
private readonly UPSTASH_REDIS_REST_URL: string;
private readonly UPSTASH_REDIS_REST_TOKEN: string;

private constructor() {
this.UPSTASH_REDIS_REST_URL =
process.env.REACT_APP_UPSTASH_REDIS_REST_URL || "";
this.UPSTASH_REDIS_REST_TOKEN =
process.env.REACT_APP_UPSTASH_REDIS_REST_TOKEN || "";

if (!this.UPSTASH_REDIS_REST_URL || !this.UPSTASH_REDIS_REST_TOKEN) {
throw new Error("Redis environment variables are not set");
}
}

public static getInstance(): RedisManager {
if (!RedisManager.instance) {
RedisManager.instance = new RedisManager();
}
return RedisManager.instance;
}

private getAuthHeaders() {
return {
Authorization: `Bearer ${this.UPSTASH_REDIS_REST_TOKEN}`,
};
}

public async getRedisValue(key: string): Promise<string | null> {
try {
const response = await fetch(
`${this.UPSTASH_REDIS_REST_URL}/get/${key}`,
{
headers: this.getAuthHeaders(),
}
);
if (!response.ok) return null;
const data = await response.json();
return data.result;
} catch {
return null;
}
}

public async incrementRedisValue(key: string): Promise<number | null> {
try {
const response = await fetch(
`${this.UPSTASH_REDIS_REST_URL}/incr/${key}`,
{
headers: this.getAuthHeaders(),
}
);
if (!response.ok) return null;
const data = await response.json();
return data.result;
} catch {
return null;
}
}

public async setRedisValue(key: string, value: string): Promise<void> {
try {
await fetch(`${this.UPSTASH_REDIS_REST_URL}/set/${key}/${value}`, {
headers: this.getAuthHeaders(),
});
} catch {
// Silently fail
}
}

public async getUserIdByLocation(
locationAddress: string
): Promise<string | null> {
const totalUsers = await this.getRedisValue("totalUsers");
if (totalUsers === null) return null;

for (let i = 1; i <= parseInt(totalUsers); i++) {
const userId = `user:${i}`;
const storedLocation = await this.getRedisValue(`${userId}:location`);
if (storedLocation === locationAddress) {
return userId;
}
}
return null;
}

public async initializeUser(locationAddress: string): Promise<string | null> {
try {
// Check if user already exists
const existingUserId = await this.getUserIdByLocation(locationAddress);
if (existingUserId) {
return existingUserId;
}

const totalUsers = await this.incrementRedisValue("totalUsers");
if (totalUsers === null) return null;
const userId = `user:${totalUsers}`;
await this.setRedisValue(`${userId}:location`, locationAddress);
await this.setRedisValue(`${userId}:queries`, "0");
await this.setRedisValue(`${userId}:createdAt`, new Date().toISOString());
return userId;
} catch {
return null;
}
}

public async recordQuery(
userId: string,
locationAddress: string
): Promise<void> {
try {
const date = new Date().toISOString().split("T")[0]; // Get current date in YYYY-MM-DD format
await this.incrementRedisValue(`${userId}:queries`);
await this.incrementRedisValue(`${userId}:queries:${date}`);
await this.incrementRedisValue("totalQueries");
await this.setRedisValue(`${userId}:location`, locationAddress);
await this.setRedisValue(
`${userId}:lastQueryAt`,
new Date().toISOString()
);
} catch {
// Silently fail
}
}
}

// Export functions that use the RedisManager instance
export const initializeUser = async (
locationAddress: string
): Promise<string | null> => {
return RedisManager.getInstance().initializeUser(locationAddress);
};

export const recordQuery = async (
userId: string,
locationAddress: string
): Promise<void> => {
return RedisManager.getInstance().recordQuery(userId, locationAddress);
};
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3597,6 +3597,13 @@
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==

"@upstash/redis@^1.34.0":
version "1.34.0"
resolved "https://registry.yarnpkg.com/@upstash/redis/-/redis-1.34.0.tgz#f32cd53ebeeafbba7eca10f8597a573d5a2fed0d"
integrity sha512-TrXNoJLkysIl8SBc4u9bNnyoFYoILpCcFJcLyWCccb/QSUmaVKdvY0m5diZqc3btExsapcMbaw/s/wh9Sf1pJw==
dependencies:
crypto-js "^4.2.0"

"@vercel/nft@^0.27.0", "@vercel/nft@^0.27.1":
version "0.27.2"
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.27.2.tgz#b5f7881a1c33b813fdc83e7112082411d2eb524b"
Expand Down Expand Up @@ -5665,6 +5672,11 @@ crypto-browserify@^3.12.0:
randombytes "^2.0.0"
randomfill "^1.0.3"

crypto-js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==

crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
Expand Down

0 comments on commit bfbf62d

Please sign in to comment.