social-network
social-network/data-generator.mjs
1
import {setTimeout} from "node:timers/promises";
2
import {SignatureV4} from "@aws-sdk/signature-v4";
3
import {HttpRequest} from "@aws-sdk/protocol-http";
4
import {defaultProvider} from "@aws-sdk/credential-provider-node";
5
import {URL} from "url";
6
import {Hash} from "@aws-sdk/hash-node";
7
8
const {APIURL, APIREGION} = process.env;
9
10
export const getIAMAuthRequest = async (APIURL, region, data) => {
11
	const url = new URL(APIURL);
12
	const httpRequest = new HttpRequest({
13
		body: JSON.stringify(data),
14
		headers: {
15
			"content-type": "application/json; charset=UTF-8",
16
			"content-encoding": "amz-1.0",
17
			"accept": "application/json, text/javascript",
18
			host: url.hostname,
19
		},
20
		hostname: url.hostname,
21
		method: "POST",
22
		path: url.pathname,
23
		protocol: url.protocol,
24
		query: {},
25
	});
26
	
27
	const signer = new SignatureV4({
28
		credentials: defaultProvider(),
29
		service: "appsync",
30
		region: region,
31
		sha256: Hash.bind(null, "sha256"),
32
	});
33
	const req = await signer.sign(httpRequest);
34
	return req;
35
};
36
37
const sendQuery = async (query, operationName, variables) => {
38
	const req = await getIAMAuthRequest(APIURL, APIREGION, {query, operationName, variables});
39
	const res = await fetch(`${req.protocol}//${req.hostname}${req.path}`, {
40
		method: req.method,
41
		body: req.body,
42
		headers: req.headers,
43
	});
44
45
	if (!res.ok) {
46
		throw new Error("Failed");
47
	}
48
	const resJson = await res.json();
49
	if (resJson.errors) {
50
		throw new Error(resJson);
51
	}
52
	return resJson;
53
};
54
55
const getPaginatedResults = async (fn) => {
56
	const EMPTY = Symbol("empty");
57
	const res = [];
58
	for await (const lf of (async function*() {
59
		let NextMarker = EMPTY;
60
		while (NextMarker || NextMarker === EMPTY) {
61
			const {marker, results} = await fn(NextMarker !== EMPTY ? NextMarker : undefined);
62
63
			yield* results;
64
			NextMarker = marker;
65
		}
66
	})()) {
67
		res.push(lf);
68
	}
69
70
	return res;
71
};
72
73
const randomComment = () => {
74
	const possibilities = [
75
		"Comment Ipsum!",
76
		"Hell yeah!",
77
		"Great!",
78
		"Good!",
79
		"Yeah!",
80
		"Commenting!",
81
		"Hmmm....",
82
		"Interesting!",
83
	];
84
	return possibilities[Math.floor(Math.random() * possibilities.length)];
85
};
86
87
const randomPost = () => {
88
	const possibilities = [
89
		"Lorem Ipsum",
90
		"Dolor set ameth",
91
		"Hello World!",
92
		"Something",
93
		"Something interesting",
94
		"What's up?",
95
		"All good!",
96
	];
97
	return possibilities[Math.floor(Math.random() * possibilities.length)];
98
};
99
100
const updateData = async () => {
101
	const userIds = JSON.parse(process.env.USERIDS);
102
	await Promise.all(userIds.map(async (userId) => {
103
		const myPostsQuery = await sendQuery(`
104
query MyQuery($userId: ID!) {
105
  user(id: $userId) {
106
		name
107
    posts(limit: 20) {
108
      posts {
109
        id
110
      }
111
    }
112
  }
113
}
114
			`, "MyQuery", {userId});
115
		// comment on own posts
116
		const posts = myPostsQuery.data.user.posts.posts;
117
		await Promise.all(posts.map(async ({id}, index) => {
118
			if (Math.random() < (0.05 * (1 / 2 ** index))) {
119
				console.log(`${myPostsQuery.data.user.name}: Adding a new comment to a user's own post`);
120
				await sendQuery(`
121
mutation MyMutation($userId: ID!, $postId: ID!, $text: String!) {
122
  addComment(userId: $userId, postId: $postId, text: $text) {
123
    id
124
  }
125
}
126
			`, "MyMutation", {userId, postId: id, text: randomComment()});
127
			}
128
		}));
129
		await setTimeout(2000);
130
		// add new post
131
		if (Math.random() < 0.1) {
132
			console.log(`${myPostsQuery.data.user.name}: Adding a new post`);
133
			await sendQuery(`
134
mutation MyMutation($userId: ID!, $text: String!) {
135
  createPost(userId: $userId, text: $text) {
136
    id
137
  }
138
}
139
			`, "MyMutation", {userId, text: randomPost()});
140
		}
141
		await setTimeout(2000);
142
		// write comment for friends
143
		const friendsPostsQuery = await sendQuery(`
144
query MyQuery($userId: ID!) {
145
  user(id: $userId) {
146
    friends {
147
      users {
148
				name
149
        posts(limit: 10) {
150
          posts {
151
            id
152
          }
153
        }
154
      }
155
    }
156
  }
157
}
158
			`, "MyQuery", {userId});
159
		await Promise.all(friendsPostsQuery.data.user.friends.users.map(async (friend) => {
160
			await Promise.all(friend.posts.posts.map(async ({id}, index) => {
161
				if (Math.random() < (0.05 * (1 / 2 ** index))) {
162
					await setTimeout(100);
163
					console.log(`${myPostsQuery.data.user.name} => ${friend.name}: Adding a comment to another user's post`);
164
					await sendQuery(`
165
mutation MyMutation($userId: ID!, $postId: ID!, $text: String!) {
166
  addComment(userId: $userId, postId: $postId, text: $text) {
167
    id
168
  }
169
}
170
			`, "MyMutation", {userId, postId: id, text: randomComment()});
171
				}
172
			}));
173
		}));
174
	}));
175
};
176
177
export const handler = async (event, context) => {
178
	await updateData();
179
	while(context.getRemainingTimeInMillis() > 15000) {
180
		console.log(context.getRemainingTimeInMillis());
181
		await setTimeout(10000);
182
		await updateData();
183
	}
184
};
185
186
187