UdS Fahrplan Bot Development Log (5) -- Explanations on bot sessions and requests

UdS Fahrplan Bot Development Log (5) -- Explanations on bot sessions and requests

This blog post is trying to tell you:

  • Why session is needed when multiple command using similar workflow?
  • The details of HTTP request
  • Detailed explanations on the implementation of udsfahrbot

Previous post: UdS Fahrplan Bot Development Log (4) – Implementation on /sethome and /home function

Brief Walkthrough on Telegram Bot (Cont.)

In the previous notes, we’ve already implemented all the commands we need! But there’s a question, why we need to format out query in f”{session}:{step}:{loc}”? Also, we haven’t talked about the function that connects to the SaarVV api.

We also have another study notes for all of the telegram bot projects in here, it gives you the basics on how to create your own bot and further descriptions on different functions and attributes on the package python-telegram-bot.

HTTP request on SaarVV

In Application layer, if we send a GET request to the URL, it returns the HTML of the URL. For example:

request.py
1
2
3
4
5
6
7
import requests

try:
res = requests.get("https://greenmeeple.github.io/")
print(res.text)
except Exception as e:
print(f"❌ Error fetching location matches: {e}")

Then we are basically retriving the source code the website.

Extra work is needed to perform a POST request

But if simply change the function from GET to POST, it won’t work:

Instead of getting data, a POST requestis typically used for forms, APIs, or uploading data. So we can’t simply ping a website with POST request. For example, if you are sending POST request to a website, you should locate the form and include the correct information. And for API, you should have correct header, user agent, etc.

How can I construct my own POST request?

TLDR: In hafas-client, there’s a lot profiles used by various public transportation networks. However, some of them are deprecated so be careful to verify before you use.

Here, we introduce another approach. We go to the Saarfahrplan website, and try to investigate how a POST request is constructed and sent.

$\text{Press F12}\Rightarrow\text{Network tab}\Rightarrow\text{Select filter}\textbf{Fetch/XHR}$ We can then inspect the details of the request.

We can see the URL here is not a website, but ends with .exe, which indicates that is an API. Next, we specified the data type we are sending (JSON), and the user agent we are using (HAFAS). Another important attribute is the "auth": {"type": "AID", "aid": "yCW9qZFSye1wIv3gCzm5r7d2kJ3LIF"}, which are used by the api to verify the connection.

Select the request we want to inspect, and then we can see attibutes like Content-Encoding and Content-Type. Also, we can see the entire request payload, which will be useful for our template when constructing the POST request.

Now back to our first development log, we talked about the following function:

getTrip.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
import json

def LocMatch():
url = "https://www.saarfahrplan.de/bin/mgate.exe"
headers = {
"Content-Type": "application/json",
"Accept-Encoding": "gzip",
"User-Agent": "HAFAS"
}
body = {
"ver": "1.63",
"lang": "en",
"auth": {"type": "AID", "aid": "yCW9qZFSye1wIv3gCzm5r7d2kJ3LIF"},
"client": {
"id": "ZPS-SAAR",
"type": "WEB",
"name": "webapp",
"l": "vs_webapp",
"v": 10004
},
"formatted": False,
"svcReqL": [{
"meth": "LocMatch",
"req": {
"input": {
"field": "S",
"loc": {
"type": "ALL",
"name": keyword,
},
"maxLoc": 5
}
},
"id": "1|3|"
}]
}

try:
res = requests.post(url, headers=headers, data=json.dumps(body))
data = res.json()
return data
except Exception as e:
print(f"❌ Error fetching location matches: {e}")
return None

Here, we basically visiting the API via Saarfahrplan by using its credentials and headers. On top of that we customized the attributes and methods so that we can fetch the customized data we want.

Session in Telegram Bot

Now back to our bot, since we implemented our commands seperately. They works fine when users execute them safely. However, we also need to be aware of unexpected usage. For example, what if our user started with the /depart command, but instead of finishing it, he/she chooses to start another new /trip command at the same time? When a station is parsed to the context.user_data, which function should it send to? This is reason we need make sure the function is always passing data correctly.

getDepart.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async def handle_depart_stations(query, context, data):
trip_start = context.user_data.get("trip_session", {}).get("start")
home_start = context.user_data.get("home_session", {}).get("start")
spawn_start = context.user_data.get("spawn_session", {}).get("start")

context.user_data["depart_session"]["start"] = "more"

if spawn_start == "more" or trip_start == "more" or home_start == "more":
await query.edit_message_text("You had a previous session, resume the search?",reply_markup=build_session_keyboard("depart"))
else:
await query.edit_message_text(f"Please Type your keyword to search the station")

async def handle_depart_session(query, context, data):
if data == "resume":
context.user_data["depart_session"] = {}
await query.edit_message_text("Departure search terminated, resume the previous search.\n Please Type your keyword to search the station")
elif data == "continue":
context.user_data["trip_session"] = {}
context.user_data["spawn_session"] = {}
context.user_data["home_session"] = {}
context.user_data["depart_session"]["start"] = "more"
await query.edit_message_text(f"Previous search terminated, continue the departure search.\nPlease Type your keyword to search the station")

Reference

UdS Fahrplan Bot Development Log (5) -- Explanations on bot sessions and requests

https://greenmeeple.github.io/projects/udsfahrplan-log5/

Author

Alex Li

Posted on

2025-05-03

Updated on

2025-05-14

Licensed under

Comments

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×