mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 21:38:13 +00:00
Added serverless scheduled functions with Firebase
This commit is contained in:
@@ -7,5 +7,11 @@
|
|||||||
"**/.*",
|
"**/.*",
|
||||||
"**/node_modules/**"
|
"**/node_modules/**"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"functions": {
|
||||||
|
"predeploy": [
|
||||||
|
"npm --prefix \"$RESOURCE_DIR\" run lint",
|
||||||
|
"npm --prefix \"$RESOURCE_DIR\" run build"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Generated
+2371
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "functions",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "tslint --project tsconfig.json",
|
||||||
|
"build": "tsc",
|
||||||
|
"serve": "npm run build && firebase emulators:start --only functions",
|
||||||
|
"shell": "npm run build && firebase functions:shell",
|
||||||
|
"start": "npm run shell",
|
||||||
|
"deploy": "firebase deploy --only functions",
|
||||||
|
"logs": "firebase functions:log"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "10"
|
||||||
|
},
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"firebase-admin": "^8.10.0",
|
||||||
|
"firebase-functions": "^3.6.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"firebase-functions-test": "^0.2.0",
|
||||||
|
"tslint": "^5.12.0",
|
||||||
|
"typescript": "^3.8.0"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import * as functions from "firebase-functions";
|
||||||
|
import * as admin from "firebase-admin";
|
||||||
|
|
||||||
|
admin.initializeApp();
|
||||||
|
const db = admin.firestore();
|
||||||
|
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
exports.scheduledUpdate = functions.pubsub
|
||||||
|
.schedule("5 * * * *")
|
||||||
|
.onRun(async (context) => {
|
||||||
|
const stationData: {
|
||||||
|
stationName: string;
|
||||||
|
dispatcherName: string;
|
||||||
|
}[] = await (
|
||||||
|
await axios.get("https://api.td2.info.pl:9640/?method=getStationsOnline")
|
||||||
|
).data.message;
|
||||||
|
|
||||||
|
const historyRef = db.collection("history");
|
||||||
|
|
||||||
|
stationData.forEach(async (station) => {
|
||||||
|
const docRef = historyRef.doc(station.stationName);
|
||||||
|
const docSnapshot = await docRef.get();
|
||||||
|
|
||||||
|
if (!docSnapshot.exists) {
|
||||||
|
docRef.set({
|
||||||
|
occupiedFrom: Date.now(),
|
||||||
|
currentDispatcherName: station.dispatcherName,
|
||||||
|
});
|
||||||
|
|
||||||
|
docRef.collection("dispatcherHistory").add({
|
||||||
|
dispatcherName: station.dispatcherName,
|
||||||
|
occupiedFrom: Date.now(),
|
||||||
|
occupiedTo: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const snapshot = await historyRef.get();
|
||||||
|
|
||||||
|
snapshot.forEach(async (doc) => {
|
||||||
|
const docData = doc.data();
|
||||||
|
const docRef = historyRef.doc(doc.id);
|
||||||
|
|
||||||
|
const APIStationData = stationData.find(
|
||||||
|
(station) => station.stationName == doc.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (docData.currentDispatcherName != "") {
|
||||||
|
if (
|
||||||
|
!APIStationData ||
|
||||||
|
APIStationData.dispatcherName != docData.currentDispatcherName
|
||||||
|
) {
|
||||||
|
docRef.update({
|
||||||
|
currentDispatcherName: !APIStationData
|
||||||
|
? ""
|
||||||
|
: APIStationData.dispatcherName,
|
||||||
|
occupiedFrom: !APIStationData ? 0 : Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
docRef.collection("dispatcherHistory").add({
|
||||||
|
currentDispatcherName: docData.currentDispatcherName,
|
||||||
|
occupiedFrom: docData.occupiedFrom,
|
||||||
|
occupiedTo: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (APIStationData) {
|
||||||
|
docRef.update({
|
||||||
|
currentDispatcherName: APIStationData.dispatcherName,
|
||||||
|
occupiedFrom: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"outDir": "lib",
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"target": "es2017"
|
||||||
|
},
|
||||||
|
"compileOnSave": true,
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
// -- Strict errors --
|
||||||
|
// These lint rules are likely always a good idea.
|
||||||
|
|
||||||
|
// Force function overloads to be declared together. This ensures readers understand APIs.
|
||||||
|
"adjacent-overload-signatures": true,
|
||||||
|
|
||||||
|
// Do not allow the subtle/obscure comma operator.
|
||||||
|
"ban-comma-operator": true,
|
||||||
|
|
||||||
|
// Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules.
|
||||||
|
"no-namespace": true,
|
||||||
|
|
||||||
|
// Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars.
|
||||||
|
"no-parameter-reassignment": true,
|
||||||
|
|
||||||
|
// Force the use of ES6-style imports instead of /// <reference path=> imports.
|
||||||
|
"no-reference": true,
|
||||||
|
|
||||||
|
// Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the
|
||||||
|
// code currently being edited (they may be incorrectly handling a different type case that does not exist).
|
||||||
|
"no-unnecessary-type-assertion": true,
|
||||||
|
|
||||||
|
// Disallow nonsensical label usage.
|
||||||
|
"label-position": true,
|
||||||
|
|
||||||
|
// Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }.
|
||||||
|
"no-conditional-assignment": true,
|
||||||
|
|
||||||
|
// Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed).
|
||||||
|
"no-construct": true,
|
||||||
|
|
||||||
|
// Do not allow super() to be called twice in a constructor.
|
||||||
|
"no-duplicate-super": true,
|
||||||
|
|
||||||
|
// Do not allow the same case to appear more than once in a switch block.
|
||||||
|
"no-duplicate-switch-case": true,
|
||||||
|
|
||||||
|
// Do not allow a variable to be declared more than once in the same block. Consider function parameters in this
|
||||||
|
// rule.
|
||||||
|
"no-duplicate-variable": [true, "check-parameters"],
|
||||||
|
|
||||||
|
// Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should
|
||||||
|
// instead use a separate variable name.
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
|
||||||
|
// Empty blocks are almost never needed. Allow the one general exception: empty catch blocks.
|
||||||
|
"no-empty": [true, "allow-empty-catch"],
|
||||||
|
|
||||||
|
// Functions must either be handled directly (e.g. with a catch() handler) or returned to another function.
|
||||||
|
// This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on.
|
||||||
|
"no-floating-promises": false,
|
||||||
|
|
||||||
|
// Do not allow any imports for modules that are not in package.json. These will almost certainly fail when
|
||||||
|
// deployed.
|
||||||
|
"no-implicit-dependencies": true,
|
||||||
|
|
||||||
|
// The 'this' keyword can only be used inside of classes.
|
||||||
|
"no-invalid-this": true,
|
||||||
|
|
||||||
|
// Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead.
|
||||||
|
"no-string-throw": true,
|
||||||
|
|
||||||
|
// Disallow control flow statements, such as return, continue, break, and throw in finally blocks.
|
||||||
|
"no-unsafe-finally": true,
|
||||||
|
|
||||||
|
// Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid();
|
||||||
|
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
|
||||||
|
|
||||||
|
// Disallow duplicate imports in the same file.
|
||||||
|
"no-duplicate-imports": true,
|
||||||
|
|
||||||
|
// -- Strong Warnings --
|
||||||
|
// These rules should almost never be needed, but may be included due to legacy code.
|
||||||
|
// They are left as a warning to avoid frustration with blocked deploys when the developer
|
||||||
|
// understand the warning and wants to deploy anyway.
|
||||||
|
|
||||||
|
// Warn when an empty interface is defined. These are generally not useful.
|
||||||
|
"no-empty-interface": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Warn when an import will have side effects.
|
||||||
|
"no-import-side-effect": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for
|
||||||
|
// most values and let for values that will change.
|
||||||
|
"no-var-keyword": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Prefer === and !== over == and !=. The latter operators support overloads that are often accidental.
|
||||||
|
"triple-equals": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Warn when using deprecated APIs.
|
||||||
|
"deprecation": { "severity": "warning" },
|
||||||
|
|
||||||
|
// -- Light Warnings --
|
||||||
|
// These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info"
|
||||||
|
// if TSLint supported such a level.
|
||||||
|
|
||||||
|
// prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array.
|
||||||
|
// (Even better: check out utils like .map if transforming an array!)
|
||||||
|
"prefer-for-of": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Warns if function overloads could be unified into a single function with optional or rest parameters.
|
||||||
|
"unified-signatures": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Prefer const for values that will not change. This better documents code.
|
||||||
|
"prefer-const": { "severity": "warning" },
|
||||||
|
|
||||||
|
// Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts.
|
||||||
|
"trailing-comma": { "severity": "warning" }
|
||||||
|
},
|
||||||
|
|
||||||
|
"defaultSeverity": "error"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Web / API server started at http://localhost:4000
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import * as firebase from "firebase/app";
|
||||||
|
import "firebase/firestore";
|
||||||
|
|
||||||
|
firebase.initializeApp({
|
||||||
|
apiKey: "AIzaSyBI36X2-p7vU1flxoJdCEc0noByyTe1mpw",
|
||||||
|
authDomain: "stacjownik-td2.firebaseapp.com",
|
||||||
|
databaseURL: "https://stacjownik-td2.firebaseio.com",
|
||||||
|
projectId: "stacjownik-td2",
|
||||||
|
});
|
||||||
|
|
||||||
|
export default firebase.firestore();
|
||||||
@@ -29,6 +29,8 @@ import Options from "@/components/ui/Options.vue";
|
|||||||
import Loading from "@/components/states/Loading.vue";
|
import Loading from "@/components/states/Loading.vue";
|
||||||
import Error from "@/components/states/Error.vue";
|
import Error from "@/components/states/Error.vue";
|
||||||
|
|
||||||
|
import db from "@/scripts/firebase/firebaseInit";
|
||||||
|
|
||||||
enum ConnState {
|
enum ConnState {
|
||||||
Loading = 0,
|
Loading = 0,
|
||||||
Error = 1,
|
Error = 1,
|
||||||
@@ -65,7 +67,13 @@ export default class StationsView extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
|
const { docs } = await db.collection("history").get();
|
||||||
|
|
||||||
|
docs.forEach((doc) => {
|
||||||
|
console.log(doc.data());
|
||||||
|
});
|
||||||
|
|
||||||
// this.$store.watch(
|
// this.$store.watch(
|
||||||
// (state, getters) => getters.getConnectionState,
|
// (state, getters) => getters.getConnectionState,
|
||||||
// (state: ConnState) => {
|
// (state: ConnState) => {
|
||||||
|
|||||||
+95
-81
@@ -2,84 +2,100 @@
|
|||||||
<section class="trains-view">
|
<section class="trains-view">
|
||||||
<Loading v-if="!listLoaded" message="Liczenie pociągów..." />
|
<Loading v-if="!listLoaded" message="Liczenie pociągów..." />
|
||||||
|
|
||||||
<ul class="list" v-else>
|
<div class="body-wrapper" v-else>
|
||||||
<li class="item" v-for="train in computedTrains" :key="train.timetableId">
|
<div class="train-sorter">
|
||||||
<a :href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" target="_blank">
|
<select name="sort-type" class="sort-type">
|
||||||
<span class="info">
|
<option>Masa składu</option>
|
||||||
<div class="info-category">
|
<option>Długość składu</option>
|
||||||
<span>
|
<option>Numer pociągu</option>
|
||||||
<strong>{{train.category}}</strong>
|
<option>Kilometraż</option>
|
||||||
{{train.trainNo}} |
|
</select>
|
||||||
|
|
||||||
|
<select name="sort-dir" class="sort-dir">
|
||||||
|
<option>Rosnąco</option>
|
||||||
|
<option>Malejąco</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="list">
|
||||||
|
<li class="item" v-for="train in computedTrains" :key="train.timetableId">
|
||||||
|
<a :href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" target="_blank">
|
||||||
|
<span class="info">
|
||||||
|
<div class="info-category">
|
||||||
|
<span>
|
||||||
|
<strong>{{train.category}}</strong>
|
||||||
|
{{train.trainNo}} |
|
||||||
|
</span>
|
||||||
|
<span style=" color: gold;">{{train.routeDistance}} km</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-warnings">
|
||||||
|
<span class="warning twr" v-if="train.TWR">TWR</span>
|
||||||
|
<span class="warning skr" v-if="train.SKR">SKR</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-route">
|
||||||
|
<strong>{{train.route && train.route.replace("|", " - ")}}</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-stations">
|
||||||
|
<i v-if="train.sceneries.length > 0">Przez: {{train.sceneries}}</i>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<span class="driver">
|
||||||
|
<span class="driver-name">
|
||||||
|
{{train.driverName}}
|
||||||
|
<span style="color: #bbb; margin-left: 1em;">{{train.locoType}}</span>
|
||||||
|
</span>
|
||||||
|
<span class="driver-loco">
|
||||||
|
<img :src="train.locoURL" @error="onImageError" />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stats">
|
||||||
|
<div class="stats-general">
|
||||||
|
<span class="mass">
|
||||||
|
<img :src="massIcon" alt="icon-mass" />
|
||||||
|
{{train.mass/1000}}t
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="speed">
|
||||||
|
<img :src="speedIcon" alt="icon-speed" />
|
||||||
|
{{train.speed}} km/h
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="length">
|
||||||
|
<img :src="lengthIcon" alt="icon-length" />
|
||||||
|
{{train.length}}m
|
||||||
</span>
|
</span>
|
||||||
<span style=" color: gold;">{{train.routeDistance}} km</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-warnings">
|
<div class="stats-position">
|
||||||
<span class="warning twr" v-if="train.TWR">TWR</span>
|
<span class="station">
|
||||||
<span class="warning skr" v-if="train.SKR">SKR</span>
|
<p>
|
||||||
</div>
|
<strong>SCENERIA</strong>
|
||||||
|
</p>
|
||||||
<div class="info-route">
|
{{train.currentStationName}}
|
||||||
<strong>{{train.route && train.route.replace("|", " - ")}}</strong>
|
</span>
|
||||||
</div>
|
<span class="track">
|
||||||
|
<p>
|
||||||
<div class="info-stations">
|
<strong>SZLAK</strong>
|
||||||
<i v-if="train.sceneries.length > 0">Przez: {{train.sceneries}}</i>
|
</p>
|
||||||
|
{{train.connectedTrack || "---"}}
|
||||||
|
</span>
|
||||||
|
<span class="signal">
|
||||||
|
<p>
|
||||||
|
<strong>SEMAFOR</strong>
|
||||||
|
</p>
|
||||||
|
{{train.signal || "---"}}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</li>
|
||||||
|
</ul>
|
||||||
<span class="driver">
|
</div>
|
||||||
<span class="driver-name">
|
|
||||||
{{train.driverName}}
|
|
||||||
<span style="color: #bbb; margin-left: 1em;">{{train.locoType}}</span>
|
|
||||||
</span>
|
|
||||||
<span class="driver-loco">
|
|
||||||
<img :src="train.locoURL" @error="onImageError" />
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="stats">
|
|
||||||
<div class="stats-general">
|
|
||||||
<span class="mass">
|
|
||||||
<img :src="massIcon" alt="icon-mass" />
|
|
||||||
{{train.mass/1000}}t
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="speed">
|
|
||||||
<img :src="speedIcon" alt="icon-speed" />
|
|
||||||
{{train.speed}} km/h
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="length">
|
|
||||||
<img :src="lengthIcon" alt="icon-length" />
|
|
||||||
{{train.length}}m
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stats-position">
|
|
||||||
<span class="station">
|
|
||||||
<p>
|
|
||||||
<strong>SCENERIA</strong>
|
|
||||||
</p>
|
|
||||||
{{train.currentStationName}}
|
|
||||||
</span>
|
|
||||||
<span class="track">
|
|
||||||
<p>
|
|
||||||
<strong>SZLAK</strong>
|
|
||||||
</p>
|
|
||||||
{{train.connectedTrack || "---"}}
|
|
||||||
</span>
|
|
||||||
<span class="signal">
|
|
||||||
<p>
|
|
||||||
<strong>SEMAFOR</strong>
|
|
||||||
</p>
|
|
||||||
{{train.signal || "---"}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -276,19 +292,17 @@ export default class TrainsView extends Vue {
|
|||||||
@import "../styles/responsive.scss";
|
@import "../styles/responsive.scss";
|
||||||
|
|
||||||
.trains-view {
|
.trains-view {
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.body-wrapper {
|
||||||
margin: 2rem 0;
|
margin: 0 auto;
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
width: 90%;
|
|
||||||
max-width: 1024px;
|
max-width: 1024px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Web / API server started at http://localhost:4000
|
||||||
Reference in New Issue
Block a user