ctucx.git: trainsearch

web based trip-planner, fork of https://cyberchaos.dev/yuka/trainsearch

commit e0bd11fcd2cd16395b822e5d1d58e95ca8b0a398
parent 1e8e7eff60ab095998cb035296b4ef8aeaef0f76
Author: Yureka <yuka@yuka.dev>
Date: Sat, 19 Feb 2022 11:28:32 +0100

support for multiple endpoints
8 files changed, 64 insertions(+), 23 deletions(-)
M
src/app_functions.js
|
22
++++++++++++----------
M
src/canvas.js
|
3
++-
M
src/hafas_client.js
|
30
+++++++++++++++++++++++++++---
M
src/journeyView.js
|
7
++++---
M
src/journeysView.js
|
6
+++---
M
src/main.js
|
6
+++---
M
src/settings.js
|
1
+
M
src/settingsView.js
|
12
++++++++++++
diff --git a/src/app_functions.js b/src/app_functions.js
@@ -4,7 +4,7 @@ import { showLoader, hideOverlay, showModal, showAlertModal } from './overlays.j
 import { languages } from './languages.js';
 import { html } from 'lit-html';
 import { formatDateTime, getFrom, getTo } from './helpers.js';
-import { client } from './hafas_client.js';
+import { getHafasClient, client } from './hafas_client.js';
 import { trainsearchToHafas, hafasToTrainsearch } from './refresh_token';
 
 let ds100 = {};

@@ -89,15 +89,15 @@ const processJourney = journey => {
 
 export const getJourneys = async slug => {
 	let data = await db.get('journeysOverview', slug);
-	data.journeys = await Promise.all(data.journeys.map(getJourney));
+	data.journeys = await Promise.all(data.journeys.map(x => getJourney(x, data.profile)));
 	return data;
 };
 
-export const getJourney = async refreshToken => {
+export const getJourney = async (refreshToken, profile) => {
 	let data = await db.get('journey', refreshToken);
 	const settings = mkSettings();
 	if (!data || JSON.stringify(data.settings) != JSON.stringify(settings)) {
-		data = await refreshJourney(refreshToken);
+		data = await refreshJourney(refreshToken, profile);
 	}
 	return processJourney(data);
 };

@@ -109,7 +109,7 @@ export const getMoreJourneys = async (slug, mode) => {
 	let { departure, arrival, from, to, ...moreOpt } = params;
 	const [newData, ...existingJourneys] = await Promise.all(
 		[ client.journeys(from, to, moreOpt) ]
-			.concat(saved.journeys.map(getJourney))
+			.concat(saved.journeys.map(x => getJourney(x, saved.profile)))
 	);
 
 	const res = {

@@ -134,9 +134,10 @@ export const getMoreJourneys = async (slug, mode) => {
 };
 export const refreshJourneys = async (slug) => {
 	const saved = await db.get('journeysOverview', slug);
-	await Promise.all(saved.journeys.map(refreshJourney));
+	await Promise.all(saved.journeys.map(x => refreshJourney(saved.profile || "db", x)));
 };
-export const refreshJourney = async (refreshToken) => {
+export const refreshJourney = async (refreshToken, profile) => {
+	const client = await getHafasClient(profile || settings.profile || "db");
 	const settings = mkSettings();
 	const [saved, data] = await Promise.all([
 		db.get('journey', refreshToken),

@@ -159,17 +160,18 @@ const generateSlug = () => {
 };
 
 export const newJourneys = async (params) => {
-	const settings = mkSettings();
+	const requestSettings = mkSettings();
 	const { from, to, ...moreOpts } = params;
 	let data;
-	data = await client.journeys(from, to, { ...settings, ...moreOpts });
+	data = await client.journeys(from, to, { ...requestSettings, ...moreOpts });
 	for (const journey of data.journeys) {
 		journey.refreshToken = hafasToTrainsearch(journey.refreshToken);
 	}
 	data.slug = generateSlug();
 	data.indexOffset = 0;
 	data.params = params;
-	data.settings = settings;
+	data.settings = requestSettings;
+	data.profile = settings.profile;
 	await addJourneys(data);
 	return processJourneys(data);
 };
diff --git a/src/canvas.js b/src/canvas.js
@@ -67,6 +67,7 @@ export const setupCanvas = (data, isUpdate) => {
 	canvasState.indexOffset = data.indexOffset;
 	canvasState.journeys = Object.keys(data.journeys).sort((a, b) => Number(a) - Number(b)).map(k => data.journeys[k]);
 	canvasState.slug = data.slug;
+	canvasState.profile = data.profile || "db";
 
 	canvas.addEventListener('mousedown', mouseDownHandler, {passive: true});
 	canvas.addEventListener('touchstart', mouseDownHandler, {passive: true});

@@ -339,7 +340,7 @@ const mouseUpHandler = (evt) => {
 		if (num >= 0) {
 			if (num < canvasState.journeys.length) {
 				const j = canvasState.journeys[num];
-				go(`/j/db/${j.refreshToken}`);
+				go(`/j/${canvasState.profile || "db"}/${j.refreshToken}`);
 			} else {
 				moreJourneys(canvasState.slug, 'later');
 			}
diff --git a/src/hafas_client.js b/src/hafas_client.js
@@ -1,6 +1,30 @@
+const clients = {};
 export let client;
 
-export const initHafasClient = async () => {
-	const { JsFetchRequester, DbProfile, HafasClient } = await import('../hafas-rs/pkg/index.js');
-	client = new HafasClient(new DbProfile(), new JsFetchRequester("/", false));
+export const getHafasClient = async profileName => {
+	if (!clients[profileName]) {
+		const { JsFetchRequester, DbProfile, SncfProfile, VbbProfile, HafasClient } = await import('../hafas-rs/pkg/index.js');
+		let profile;
+		switch(profileName) {
+			case "db":
+				profile = new DbProfile();
+				break;
+			case "sncf":
+				profile = new SncfProfile();
+				break;
+			case "vbb":
+				profile = new VbbProfile();
+				break;
+			default:
+				throw "Unknown profile name: " + profileName;
+		}
+		clients[profileName] = new HafasClient(profile, new JsFetchRequester("https://trainsear.ch/", false));
+	}
+
+	console.info("initialized hafas client with profile " + profileName);
+	return clients[profileName];
+}
+
+export const initHafasClient = async profileName => {
+	client = await getHafasClient(profileName);
 };
diff --git a/src/journeyView.js b/src/journeyView.js
@@ -202,10 +202,11 @@ const stopPlatformTemplate = (data) => {
 
 export const journeyView = async (match, isUpdate) => {
 	if (!isUpdate) showLoader();
-	let refreshToken, data;
+	let profile, refreshToken, data;
 	try {
-		refreshToken = decodeURIComponent(match[0]);
-		data = await getJourney(refreshToken);
+		profile = match[0];
+		refreshToken = decodeURIComponent(match[1]);
+		data = await getJourney(refreshToken, profile);
 	} catch(e) {
 		showAlertModal(e.toString());
 		throw e;
diff --git a/src/journeysView.js b/src/journeysView.js
@@ -61,7 +61,7 @@ const journeysTemplate = (data) => html`
 					</tr>
 				</thead>
 				<tbody>
-					${Object.entries(data.journeys).map(([key, val]) => journeyOverviewTemplate(val, data.slug, key - data.indexOffset))}
+					${Object.entries(data.journeys).map(([key, val]) => journeyOverviewTemplate(data.profile || "db", val, data.slug, key - data.indexOffset))}
 				</tbody>
 			</table>
 			</div>

@@ -71,7 +71,7 @@ const journeysTemplate = (data) => html`
 	</div>
 `;
 
-const journeyOverviewTemplate = (entry, slug, key) => {
+const journeyOverviewTemplate = (profile, entry, slug, key) => {
 	const firstLeg = entry.legs[0];
 	const lastLeg = entry.legs[entry.legs.length - 1];
 	let changes = 0;

@@ -105,7 +105,7 @@ const journeyOverviewTemplate = (entry, slug, key) => {
 	}).join(', ');
 
 	return html`
-	<tr @click=${() => go('/j/db/'+entry.refreshToken)}">
+	<tr @click=${() => go(`/j/${profile}/${entry.refreshToken}`)}>
 		<td class="${cancelled ? 'cancelled' : ''}"><span>${timeTemplate(firstLeg, 'departure')}</span></td>
 		${cancelled ? html`
 			<td><span class="cancelled-text">${t('cancelled-ride')}</span></td>
diff --git a/src/main.js b/src/main.js
@@ -2,7 +2,7 @@ import { route, go, start } from './router.js';
 import { searchView } from './searchView.js';
 import { journeysView } from './journeysView.js';
 import { journeyView } from './journeyView.js';
-import { initSettings } from './settings.js';
+import { initSettings, settings } from './settings.js';
 import { initDataStorage } from './dataStorage.js';
 import { initHafasClient } from './hafas_client.js';
 import { initRefreshTokenLib } from './refresh_token.js';

@@ -14,14 +14,14 @@ import { showDiv, hideDiv, ElementById } from './helpers.js';
 		((async () => {
 			await initDataStorage();
 			await initSettings();
+			await initHafasClient(settings.profile || "db");
 		}) ()),
-		initHafasClient(),
 		initRefreshTokenLib(),
 	]);
 
 	route(/^\/$/, searchView);
 	route(/^\/([a-zA-Z0-9]+)\/([a-z]+)$/, journeysView);
-	route(/^\/j\/db\/(.+)$/, journeyView);
+	route(/^\/j\/([a-z]+)\/(.+)$/, journeyView);
 
 	hideDiv('overlay');
 	if (!window.location.hash.length) go('/');
diff --git a/src/settings.js b/src/settings.js
@@ -29,6 +29,7 @@ const defaultSettings = {
 	journeysViewMode: 'canvas',
 	showMap: false,
 	showPrices: false,
+	profile: "db",
 };
 
 const subscribers = [];
diff --git a/src/settingsView.js b/src/settingsView.js
@@ -5,6 +5,7 @@ import { hideDiv, ElementById } from './helpers.js';
 import { ConsoleLog, t } from './app_functions.js';
 import { html, render } from 'lit-html';
 import { searchView } from './searchView.js';
+import { initHafasClient } from './hafas_client.js';
 
 export const showSettings = async () => {
 	showModal(t('settings'), settingsTemplate());

@@ -23,6 +24,13 @@ const settingsTemplate = () => html`
 		<label><input type="radio" name="language" ?checked=${settings.language === 'de'} value="de"> ${t('de')}</label><br>
 		<label><input type="radio" name="language" ?checked=${settings.language === 'nl'} value="nl"> ${t('nl')}</label><br>
 		<br>
+		<b>${t('endpoint')}:</b><br>
+		<label><input type="radio" name="profile" ?checked=${settings.profile === 'db'} value="db"> DB</label><br>
+		<label><input type="radio" name="profile" ?checked=${settings.profile === 'vbb'} value="vbb"> VBB (${t("experimental")})</label><br>
+		<label><input type="radio" name="profile" ?checked=${settings.profile === 'nahsh'} value="nahsh"> NAH.SH (${t("experimental")})</label><br>
+		<label><input type="radio" name="profile" ?checked=${settings.profile === 'bvg'} value="bvg"> BVG (${t("experimental")})</label><br>
+		<label><input type="radio" name="profile" ?checked=${settings.profile === 'sncf'} value="sncf"> SNCF (${t("experimental")})</label><br>
+		<br>
 		<b>${t('experimental-features')}:</b><br>
 		<label><input type="checkbox" ?checked=${settings.showMap} id="feature-map"> ${t('show-map')}</label><br>
 		<label><input type="checkbox" ?checked=${settings.showPrices} id="feature-prices"> ${t('show-prices')}</label><br>

@@ -55,6 +63,9 @@ const saveSettings = async () => {
 		const language = document.querySelector('input[name="language"]:checked').value;
 		settings.language = language;
 
+		const profile = document.querySelector('input[name="profile"]:checked').value;
+		settings.profile = profile;
+
 		const showMap = ElementById('feature-map').checked;
 		settings.showMap = showMap;
 

@@ -63,6 +74,7 @@ const saveSettings = async () => {
 
 		return settings;
 	});
+	await initHafasClient(settings.profile);
 	searchView();
 	hideDiv('overlay');
 };