summaryrefslogtreecommitdiff
path: root/src/react-native-app/gateways
diff options
context:
space:
mode:
authorSaumit <justsaumit@protonmail.com>2025-09-27 02:14:26 +0530
committerSaumit <justsaumit@protonmail.com>2025-09-27 02:14:26 +0530
commit82e03978b89938219958032efb1448cc76baa181 (patch)
tree626f3e54d52ecd49be0ed3bee30abacc0453d081 /src/react-native-app/gateways
Initial snapshot - OpenTelemetry demo 2.1.3 -f
Diffstat (limited to 'src/react-native-app/gateways')
-rw-r--r--src/react-native-app/gateways/Api.gateway.ts150
-rw-r--r--src/react-native-app/gateways/Session.gateway.ts43
2 files changed, 193 insertions, 0 deletions
diff --git a/src/react-native-app/gateways/Api.gateway.ts b/src/react-native-app/gateways/Api.gateway.ts
new file mode 100644
index 0000000..96f898b
--- /dev/null
+++ b/src/react-native-app/gateways/Api.gateway.ts
@@ -0,0 +1,150 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copied with modification from src/frontend/gateways/Api.gateway.ts
+ *
+ * TODO The React Native example only implements a subset of the functionality defined here, missing in particular is:
+ * - showing ads
+ * - showing recommendations
+ * - calculating shipping costs
+ * - currency conversion
+ */
+import {
+ Ad,
+ Address,
+ Cart,
+ CartItem,
+ Money,
+ PlaceOrderRequest,
+ Product,
+} from "@/protos/demo";
+import { IProductCart, IProductCartItem, IProductCheckout } from "@/types/Cart";
+import request from "@/utils/Request";
+import SessionGateway from "./Session.gateway";
+import { context, propagation } from "@opentelemetry/api";
+
+const basePath = "/api";
+
+const Apis = () => ({
+ async getCart(currencyCode: string) {
+ const { userId } = await SessionGateway.getSession();
+ return request<IProductCart>({
+ url: `${basePath}/cart`,
+ queryParams: { sessionId: userId, currencyCode },
+ });
+ },
+ async addCartItem({
+ currencyCode,
+ ...item
+ }: CartItem & { currencyCode: string }) {
+ const { userId } = await SessionGateway.getSession();
+ return request<Cart>({
+ url: `${basePath}/cart`,
+ body: { item, userId },
+ queryParams: { currencyCode },
+ method: "POST",
+ });
+ },
+ async emptyCart() {
+ const { userId } = await SessionGateway.getSession();
+ return request<undefined>({
+ url: `${basePath}/cart`,
+ method: "DELETE",
+ body: { userId },
+ });
+ },
+
+ getSupportedCurrencyList() {
+ return request<string[]>({
+ url: `${basePath}/currency`,
+ });
+ },
+
+ getShippingCost(
+ itemList: IProductCartItem[],
+ currencyCode: string,
+ address: Address,
+ ) {
+ return request<Money>({
+ url: `${basePath}/shipping`,
+ queryParams: {
+ itemList: JSON.stringify(
+ itemList.map(({ productId, quantity }) => ({ productId, quantity })),
+ ),
+ currencyCode,
+ address: JSON.stringify(address),
+ },
+ });
+ },
+
+ placeOrder({
+ currencyCode,
+ ...order
+ }: PlaceOrderRequest & { currencyCode: string }) {
+ return request<IProductCheckout>({
+ url: `${basePath}/checkout`,
+ method: "POST",
+ queryParams: { currencyCode },
+ body: order,
+ });
+ },
+
+ listProducts(currencyCode: string) {
+ return request<Product[]>({
+ url: `${basePath}/products`,
+ queryParams: { currencyCode },
+ });
+ },
+ getProduct(productId: string, currencyCode: string) {
+ return request<Product>({
+ url: `${basePath}/products/${productId}`,
+ queryParams: { currencyCode },
+ });
+ },
+ async listRecommendations(productIds: string[], currencyCode: string) {
+ const { userId } = await SessionGateway.getSession();
+ return request<Product[]>({
+ url: `${basePath}/recommendations`,
+ queryParams: {
+ productIds,
+ sessionId: userId,
+ currencyCode,
+ },
+ });
+ },
+ listAds(contextKeys: string[]) {
+ return request<Ad[]>({
+ url: `${basePath}/data`,
+ queryParams: {
+ contextKeys,
+ },
+ });
+ },
+});
+
+/**
+ * Extends all the API calls to set baggage automatically.
+ */
+const ApiGateway = new Proxy(Apis(), {
+ get(target, prop, receiver) {
+ const originalFunction = Reflect.get(target, prop, receiver);
+
+ if (typeof originalFunction !== "function") {
+ return originalFunction;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return async function (...args: any[]) {
+ const { userId } = await SessionGateway.getSession();
+ const baggage =
+ propagation.getActiveBaggage() || propagation.createBaggage();
+ const newBaggage = baggage.setEntry("session.id", { value: userId });
+ const newContext = propagation.setBaggage(context.active(), newBaggage);
+ return context.with(newContext, () => {
+ return Reflect.apply(originalFunction, undefined, args);
+ });
+ };
+ },
+});
+
+export default ApiGateway;
diff --git a/src/react-native-app/gateways/Session.gateway.ts b/src/react-native-app/gateways/Session.gateway.ts
new file mode 100644
index 0000000..d6da9e1
--- /dev/null
+++ b/src/react-native-app/gateways/Session.gateway.ts
@@ -0,0 +1,43 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copied with modification from src/frontend/gateways/Session.gateway.ts
+ */
+import "react-native-get-random-values"; // Must be imported before 'uuid', see https://stackoverflow.com/a/68097811
+import { v4 } from "uuid";
+import AsyncStorage from "@react-native-async-storage/async-storage";
+
+interface ISession {
+ userId: string;
+ currencyCode: string;
+}
+
+const sessionKey = "session";
+const defaultSession = {
+ userId: v4(),
+ currencyCode: "USD",
+};
+
+const SessionGateway = () => ({
+ async getSession(): Promise<ISession> {
+ const sessionString = await AsyncStorage.getItem(sessionKey);
+
+ if (!sessionString) {
+ await AsyncStorage.setItem(sessionKey, JSON.stringify(defaultSession));
+ }
+
+ return JSON.parse(
+ sessionString || JSON.stringify(defaultSession),
+ ) as ISession;
+ },
+ setSessionValue<K extends keyof ISession>(key: K, value: ISession[K]) {
+ const session = this.getSession();
+
+ return AsyncStorage.setItem(
+ sessionKey,
+ JSON.stringify({ ...session, [key]: value }),
+ );
+ },
+});
+
+export default SessionGateway();