Skip to content

Commit

Permalink
hot reload enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
kondaurovDev committed Dec 22, 2024
1 parent cceddbe commit 7e9d40f
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 94 deletions.
21 changes: 10 additions & 11 deletions docs/telegram-bot-playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script defer src="https://cdn.jsdelivr.net/npm/@monaco-editor/[email protected]/lib/umd/monaco-loader.min.js"></script>
<script defer src="./scripts/init.js?v=79sgsn" type="module"></script>
<script defer src="./scripts/main.js?v=s4vhmf" type="module"></script>
<script defer src="./scripts/main.js?v=bgip" type="module"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>

<link rel="stylesheet" href="styles.css?v=xa8dtw">
<link rel="stylesheet" href="styles.css?v=oq5lin">
</head>

<body
Expand All @@ -19,16 +19,16 @@
botState: {
name: 'nameless',
status: 'idle',
token: 'your token'
token: ''
}
}"
x-init="
await playground.start();
playground.onCodeChange(() => {
console.log('Code was changed')
playground.runBot(botState);
});
playground.worker.onmessage = (e) => {
console.log('got message from worker', e.data);
console.log('got message from worker', e?.data);
if (!e?.data) return;
if (e.data.botState) {
Object.assign(botState, e.data.botState)
Expand All @@ -43,21 +43,20 @@
<h1>Telegram Bot Playground 🤖 </h1>

<div style="display: flex; gap: 20px; justify-content: center;">
<div x-text="botState.status"></div>

<button @click="playground.runBot(botState)">Run bot</button>

<label>
Bot token
<input
type="text"
x-model="botState.token"
placeholder="your token"
@input.debounce.500ms="playground.checkToken(botState)"
>
>
</label>

<div x-text="botState.name"></div>

<label>Bot name: <span x-text="botState.name"></span></label>
<label>Status: <span x-text="botState.status"></span></label>

</div>

<div style="display: flex; align-items: start;">
Expand Down
6 changes: 3 additions & 3 deletions docs/telegram-bot-playground/metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"styles.css": "xa8dtw",
"styles.css": "oq5lin",
"init.js": "79sgsn",
"main.js": "s4vhmf",
"web-worker.js": "eb7q23"
"main.js": "bgip",
"web-worker.js": "7hqmn5"
}
4 changes: 4 additions & 0 deletions docs/telegram-bot-playground/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ window.playground.checkToken = (state) => {
fetch(`https://api.telegram.org/bot${token}/getMe`).then((_) => _.json()).then((info) => {
if (info.ok) {
state.name = info.result.first_name;
if (window.playground.runBot) {
console.log("Running bot");
window.playground.runBot(state);
}
} else {
state.name = "nameless";
}
Expand Down
151 changes: 97 additions & 54 deletions docs/telegram-bot-playground/scripts/web-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,11 @@ var MicroFiberImpl = class {
var fiberMiddleware = /* @__PURE__ */ globalValue("effect/Micro/fiberMiddleware", () => ({
interruptChildren: void 0
}));
var fiberAwait = (self2) => async((resume) => sync(self2.addObserver((exit2) => resume(succeed(exit2)))));
var fiberInterrupt = (self2) => suspend(() => {
self2.unsafeInterrupt();
return asVoid(fiberAwait(self2));
});
var fiberInterruptAll = (fibers) => suspend(() => {
for (const fiber of fibers) fiber.unsafeInterrupt();
const iter = fibers[Symbol.iterator]();
Expand Down Expand Up @@ -1323,6 +1328,11 @@ var andThen = /* @__PURE__ */ dual(2, (self2, f) => flatMap(self2, (a) => {
const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f;
return isMicro(value) ? value : succeed(value);
}));
var tap = /* @__PURE__ */ dual(2, (self2, f) => flatMap(self2, (a) => {
const value = isMicro(f) ? f : typeof f === "function" ? f(a) : f;
return isMicro(value) ? as(value, a) : succeed(a);
}));
var asVoid = (self2) => flatMap(self2, (_) => exitVoid);
var exit = (self2) => matchCause(self2, {
onFailure: exitFailCause,
onSuccess: exitSucceed
Expand Down Expand Up @@ -1701,6 +1711,12 @@ var runPromiseExit = (effect, options) => new Promise((resolve, _reject) => {
const handle = runFork(effect, options);
handle.addObserver(resolve);
});
var runPromise = (effect, options) => runPromiseExit(effect, options).then((exit2) => {
if (exit2._tag === "Failure") {
throw exit2.cause;
}
return exit2.value;
});

// node_modules/.pnpm/[email protected]/node_modules/effect/dist/esm/String.js
var snakeToCamel = (self2) => {
Expand Down Expand Up @@ -3505,25 +3521,6 @@ var ClientFileServiceDefault = gen(function* () {
}).pipe(
provideServiceEffect(ClientExecuteRequestService, ClientExecuteRequestServiceDefault)
);
var makeClientConfigFrom = (input) => gen(function* () {
if (input.type == "config") {
return makeTgBotClientConfig(input);
}
const config = yield* tryPromise({
try: async () => {
const { readFile } = await import("fs/promises");
return JSON.parse(await readFile("config.json", "utf-8"));
},
catch: (error) => {
console.warn(error);
return "ReadingConfigError";
}
});
if (!isTgBotClientSettingsInput(config)) {
return yield* fail("InvalidConfig");
}
return makeTgBotClientConfig(config);
});
var makeSettingsFrom = (input) => {
let limit = input.batch_size ?? 10;
let timeout = input.timeout ?? 10;
Expand Down Expand Up @@ -3650,36 +3647,67 @@ var pollAndHandle = (input) => {
var BotUpdatePollerService = class extends Tag2("BotUpdatePollerService")() {
};
var BotUpdatesPollerServiceDefault = gen(function* () {
console.log("Initiating BotUpdatesPollerServiceDefault");
const state = {
isActive: false
fiber: void 0
};
const client = yield* service(ClientExecuteRequestService);
const runBot = (messageHandler) => gen(function* () {
if (state.isActive) {
return yield* fail("AlreadyRunning");
}
const fiber = yield* pollAndHandle({
console.log(state);
const startFiber = pollAndHandle({
settings: messageHandler,
execute: client.execute
}).pipe(forkDaemon);
fiber.addObserver((exit2) => {
console.log("bot's fiber has been closed", exit2);
state.isActive = false;
});
console.log("Reading bot's updates...");
return fiber;
}).pipe(
forkDaemon,
tap(
(fiber) => fiber.addObserver((exit2) => {
console.log("bot's fiber has been closed", exit2);
if (messageHandler.onExit) {
messageHandler.onExit(exit2);
}
})
)
);
if (state.fiber) {
console.log("killing previous bot's fiber");
yield* fiberInterrupt(state.fiber);
}
state.fiber = yield* startFiber;
console.log("Reading bot's updates.....", state.fiber == null);
return state.fiber;
});
return {
runBot
};
}).pipe(
provideServiceEffect(ClientExecuteRequestService, ClientExecuteRequestServiceDefault)
);
var makeClientConfigFrom = (input) => gen(function* () {
if (input.type == "config") {
return makeTgBotClientConfig(input);
}
const config = yield* tryPromise({
try: async () => {
const { readFileSync } = await import("fs");
return JSON.parse(await readFileSync("config.json", "utf-8"));
},
catch: (error) => {
console.warn(error);
return "ReadingConfigError";
}
});
if (!isTgBotClientSettingsInput(config)) {
return yield* fail("InvalidConfig");
}
return makeTgBotClientConfig(config);
});
var makeBot = (messageHandler) => gen(function* () {
const { runBot } = yield* service(BotUpdatePollerService);
return yield* runBot(messageHandler);
return {
fiber: yield* runBot(messageHandler),
runBot
};
}).pipe(
provideServiceEffect(BotUpdatePollerService, BotUpdatesPollerServiceDefault),
tapError((error) => {
console.error(error);
return void_;
Expand All @@ -3689,11 +3717,22 @@ var BotFactoryService = class extends Tag2("BotFactoryService")() {
};
var BotFactoryServiceDefault = {
makeBot,
runBot: (input) => makeBot(input).pipe(
provideServiceEffect(TgBotClientConfig, makeClientConfigFrom(input))
)
runBot: (input) => gen(function* () {
console.log("client");
const client = yield* makeClientConfigFrom(input);
const poller = yield* BotUpdatesPollerServiceDefault.pipe(
provideService(TgBotClientConfig, client)
);
const bot = yield* makeBot(input).pipe(
provideService(BotUpdatePollerService, poller)
);
const reload = (input2) => bot.runBot(input2).pipe(runPromise);
return {
reload
};
})
};
var runTgChatBot = (input) => BotFactoryServiceDefault.runBot(input).pipe(runPromiseExit);
var runTgChatBot = (input) => BotFactoryServiceDefault.runBot(input).pipe(runPromise);

// src/tg-bot-playground/utils.ts
var parseJson = (input) => {
Expand Down Expand Up @@ -3727,6 +3766,7 @@ var notifyParent = (input) => {
...input
});
};
var botInstance = void 0;
self.onmessage = async (msg) => {
const command = msg.data;
if (typeof command != "object" || !command.command) {
Expand All @@ -3737,32 +3777,35 @@ self.onmessage = async (msg) => {
}
if (command.command == "run-bot") {
const handlers = deserialize(command.code);
const fiber = await runTgChatBot({
type: "config",
"bot-token": command.token,
...handlers
});
if (fiber._tag == "Failure") {
if (botInstance) {
console.log("reloading...");
await botInstance.reload({
...handlers
});
notifyParent({
error: "Cannot create bot's fiber",
cause: fiber.cause
botState: {
status: "reloaded"
}
});
return;
}
notifyParent({
success: "Bot's fiber has been created",
botState: {
status: "active"
}
});
fiber.value.addObserver((exit2) => {
notifyParent({
botInstance = await runTgChatBot({
type: "config",
"bot-token": command.token,
...handlers,
onExit: (exit2) => notifyParent({
success: "Bot's fiber has been shutdown",
exit: exit2,
botState: {
status: "stopped"
}
});
})
});
notifyParent({
success: "Bot's fiber has been created",
botState: {
status: "active"
}
});
return;
}
Expand Down
8 changes: 5 additions & 3 deletions docs/telegram-bot-playground/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@
display: flex;
background-color: rgb(62, 95, 113);
margin-top: 10px;
width: 100%;
}

#container {
.flex-container > #container {
display: flex;
width: 700px;
flex: 0 1 70%;
height: 600px;
border: 1px solid grey;
}

#worker-updates {
.flex-container > #worker-updates {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/tg-bot-playground/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ window.playground.checkToken =
.then(info => {
if (info.ok) {
state.name = info.result.first_name;
if (window.playground.runBot) {
console.log("Running bot")
window.playground.runBot(state);
}
} else {
state.name = "nameless";
}
Expand Down
Loading

0 comments on commit 7e9d40f

Please sign in to comment.