Skip to content

Commit

Permalink
Merge pull request #17 from goeuropa/last_updates_2024-07
Browse files Browse the repository at this point in the history
Merged The latest changes
  • Loading branch information
TsimurSh authored Jul 10, 2024
2 parents a2e0aba + bf869dd commit cc6b80a
Show file tree
Hide file tree
Showing 19 changed files with 493 additions and 539 deletions.
46 changes: 0 additions & 46 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,3 @@ jobs:

- name: Build with Maven
run: mvn -B package --file pom.xml

# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
# - name: Update dependency graph
# uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6

container-image:
if: github.repository_owner == 'goeuropa' && github.event_name == 'push' && (github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
needs:
- build
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
cache: maven
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Build container image with Jib, push to Dockerhub
env:
CONTAINER_REPO: docker.io/wkulesza/transitclock-server
CONTAINER_REGISTRY_USER: ${{secrets.DOCKER_USER}}
CONTAINER_REGISTRY_PASSWORD: ${{secrets.DOCKER_AUTH}}
run: |
# we give the container two tags
# - "latest"
# - a string like "2.3_2022-12-12T21-38"
version_with_snapshot=`mvn -q help:evaluate -Dexpression=project.version -q -DforceStdout`
version=${version_with_snapshot/-SNAPSHOT/}
image_version=${version}
## if the Maven version contains SNAPSHOT, then add date to tag
if [[ $version_with_snapshot == *"SNAPSHOT"* ]]; then
image_date=`date +%Y-%m-%dT%H-%M`
image_version="${version}_${image_date}"
echo "Maven version ${version_with_snapshot} contains SNAPSHOT, adding date to container image tag"
fi
mvn install jib:build -Djib.to.tags=latest,$image_version
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.class
*.project
*.classpath
.fastRequest
*.iml
.idea/
# Package Files #
Expand Down
503 changes: 251 additions & 252 deletions app/src/main/java/org/transitclock/api/resources/TransitimeApi.java

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions app/src/main/jib/app/config/transitclock.properties
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
transitclock.gtfs.url=https://data.opentransport.ro/routing/gtfs/gtfs-stpt.zip
##!!! STATIC GTFS FEED
transitclock.gtfs.url=${GTFS_URL}
transitclock.gtfs.dirName=/var/transitclock/cache
transitclock.gtfs.intervalMsec=86400000
transitclock.autoBlockAssigner.autoAssignerEnabled=true
transitclock.autoBlockAssigner.ignoreAvlAssignments=false
transitclock.autoBlockAssigner.allowableEarlySeconds=600
transitclock.autoBlockAssigner.allowableLateSeconds=600
transitclock.blockAssigner.manualAssignmentEnabled=false

transitclock.avl.feedTimeoutInMSecs=30000
transitclock.avl.gtfsRealtimeFeedURI=GTFSRTVEHICLEPOSITIONS
# - RT FEED URI -
transitclock.avl.gtfsRealtimeFeedURI=${GTFSRTVEHICLEPOSITIONS}
transitclock.avl.maxSpeed=100
transitclock.avl.numThreads=1
transitclock.avl.queueSize=2400
Expand All @@ -21,7 +24,7 @@ transitclock.blockLoading.agressive=false

transitclock.cache.core.daysPopulateHistoricalCache=0

transitclock.core.agencyId=stpt
transitclock.core.agencyId=${AGENCYID}
transitclock.core.allowableEarlyDepartureTimeForLoggingEvent=180
transitclock.core.allowableEarlyForLayoverSeconds=1800
transitclock.core.allowableEarlySecondsForInitialMatching=1200
Expand Down Expand Up @@ -61,10 +64,10 @@ transitclock.core.trackHistoricalCaches=false
transitclock.core.useArrivalPredictionsForNormalStops=false

transitclock.db.batchSize=4000
transitclock.db.dbName=AGENCYNAME
transitclock.db.dbPassword=PGPASSWORD
transitclock.db.dbName=${AGENCYNAME}
transitclock.db.dbPassword=${PGPASSWORD}
transitclock.db.dbUserName=postgres
transitclock.db.dbHost=POSTGRES_PORT_5432_TCP_ADDR:POSTGRES_PORT_5432_TCP_PORT
transitclock.db.dbHost=${POSTGRES_PORT_5432_TCP_ADDR:POSTGRES_PORT_5432_TCP_PORT}
transitclock.db.storeDataInDatabase=true
transitclock.db.dbType=postgresql

Expand All @@ -82,7 +85,10 @@ transitclock.prediction.rls.lambda=0.9
transitclock.timeout.pollingRateSecs=60

transitclock.modules.optionalModulesList=org.transitclock.core.avl.GtfsRealtimeModule;org.transitclock.core.predAccuracy.PredictionAccuracyModule;org.transitclock.gtfs.GtfsUpdatedModule
#transitclock.modules.optionalModulesList=org.transitclock.core.avl.TraccarAVLModule;org.transitclock.core.predAccuracy.PredictionAccuracyModule
transitclock.hibernate.configFile=/app/config/hibernate.cfg.xml
transitclock.logging.dir=/var/transitclock/logs
transitclock.web.mapTileUrl=http://tile.openstreetmap.org/{z}/{x}/{y}.png

#transitclock.avl.traccar.email=
#transitclock.avl.traccar.password=
#transitclock.avl.traccar.baseurl=
17 changes: 9 additions & 8 deletions core/src/main/java/org/transitclock/core/AvlProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -331,17 +331,17 @@ public void matchNewFixForPredictableVehicle(VehicleState vehicleState) {
}
// Record this match unless the match was null and haven't
// reached number of bad matches.
else if (bestTemporalMatch != null || vehicleState.overLimitOfBadMatches()) {
else if (bestTemporalMatch != null || vehicleState.overLimitOfBadMatches()) {
// If not over the limit of bad matches then handle normally
if (bestTemporalMatch != null || !vehicleState.overLimitOfBadMatches()) {
// Set the match of the vehicle.
vehicleState.setMatch(bestTemporalMatch);
} else {
if (BlockAssignerConfig.isManualAssignmentEnabled() && vehicleState.getBlock() != null &&
vehicleState.getAvlReport().getAssignmentId() != null && vehicleState.getPreviousMatch() != null &&
vehicleState.getAvlReport().getAssignmentId() != null && vehicleState.getMatches().get(0) != null &&
vehicleState.getBlock().getBlockId().equals(vehicleState.getAvlReport().getAssignmentId())) {
// Set the previous match if match is null.
vehicleState.setMatch(vehicleState.getPreviousMatch());
// Set the previous match if bestTemporalMatch is null.
vehicleState.setMatch(vehicleState.getMatches().get(0));

logger.info(
"Got another bad match, but the manual assignment is enabled then vehicleId={} mustn't unset blockId={}.",
Expand All @@ -360,11 +360,11 @@ else if (bestTemporalMatch != null || vehicleState.overLimitOfBadMatches()) {

logger.warn("For vehicleId={} {}", vehicleState.getVehicleId(), eventDescription);

// Remove the predictions for the vehicle
makeVehicleUnpredictable(vehicleState.getVehicleId(), eventDescription, VehicleEvent.NO_MATCH);
// Remove the predictions for the vehicle
makeVehicleUnpredictable(vehicleState.getVehicleId(), eventDescription, VehicleEvent.NO_MATCH);

// Remove block assignment from vehicle
vehicleState.unsetBlock(BlockAssignmentMethod.COULD_NOT_MATCH);
// Remove block assignment from vehicle
vehicleState.unsetBlock(BlockAssignmentMethod.COULD_NOT_MATCH);
}
} else {
logger.info(
Expand Down Expand Up @@ -725,6 +725,7 @@ private boolean matchVehicleToBlockAssignment(Block block, VehicleState vehicleS
// Update the state of the vehicle
updateVehicleStateFromAssignment(
bestMatch, vehicleState, BlockAssignmentMethod.AVL_FEED_BLOCK_ASSIGNMENT, block.getId(), "block");

// Return true if predictable
return bestMatch != null;
}
Expand Down
101 changes: 59 additions & 42 deletions core/src/main/java/org/transitclock/core/avl/TraccarAVLModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,31 @@
*/
package org.transitclock.core.avl;

import io.swagger.client.ApiClient;
import io.swagger.client.ApiException;
import io.swagger.client.api.DefaultApi;
import io.swagger.client.model.Device;
import io.swagger.client.model.Position;
import io.swagger.client.model.User;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.auth.AuthCache;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.http.HttpHost;
import org.transitclock.domain.structs.AvlReport;
import org.transitclock.extension.traccar.ApiClient;
import org.transitclock.extension.traccar.ApiException;
import org.transitclock.extension.traccar.api.DefaultApi;
import org.transitclock.extension.traccar.model.DeviceDto;
import org.transitclock.extension.traccar.model.PositionDto;
import org.transitclock.extension.traccar.model.UserDto;

import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import static org.transitclock.config.data.TraccarConfig.*;

Expand All @@ -47,68 +56,75 @@
*/
@Slf4j
public class TraccarAVLModule extends PollUrlAvlModule {
public TraccarAVLModule(String agencyId) {
super(agencyId);
@NonNull
private final DefaultApi api;
@NonNull
private final UserDto user;

public TraccarAVLModule(String agencyId) throws URISyntaxException {
super(agencyId);
useCompression = false;
}
ApiClient client;
try {
var host = HttpHost.create(TRACCARBASEURL.getValue());
var httpClientBuilder = HttpClientBuilder.create();

final AuthCache authCache = new BasicAuthCache();
authCache.put(host, new BasicScheme());

var provider = new BasicCredentialsProvider();
provider.setCredentials(new AuthScope(host), new UsernamePasswordCredentials(TRACCAREMAIL.getValue(), TRACCARPASSWORD.getValue().toCharArray()));
httpClientBuilder.setDefaultCredentialsProvider(provider);

private DefaultApi initApiClient() throws RuntimeException {
DefaultApi api = new DefaultApi();
ApiClient client = new ApiClient();
client = new ApiClient(httpClientBuilder.build());
} catch (Exception ex) {
logger.warn("Unsuccessful traccar authorisation: {} ", ex.toString());
client = new ApiClient();
}
client.setBasePath(TRACCARBASEURL.getValue());
client.setUsername(TRACCAREMAIL.getValue());
client.setPassword(TRACCARPASSWORD.getValue());
api.setApiClient(client);
return api;
}
this.api = new DefaultApi(client);


private User initUser(DefaultApi api) throws RuntimeException {
User user;
try {
user = api
this.user = this.api
.sessionPost(TRACCAREMAIL.getValue(), TRACCARPASSWORD.getValue());
logger.info("Traccar login succeeded.");
return user;
} catch (ApiException e) {
logger.error(e.getMessage() + e.getCause());
throw new RuntimeException("Traccar login denied", e);
}
throw new RuntimeException("Traccar login deny");
}

@NonNull
private final DefaultApi API = initApiClient();
@NonNull
private final User USER = initUser(API);

@Override
protected void getAndProcessData() throws Exception {

Collection<AvlReport> avlReportsReadIn = new ArrayList<>();

List<Device> devices = API.devicesGet(true, USER.getId(), null, null);
List<DeviceDto> devices = api.devicesGet(true, user.getId(), null, null);
List<PositionDto> results = api.positionsGet(null, null, null, null);

List<Position> results = API.positionsGet(null, null, null, null);
for (Position result : results) {
Device device = findDeviceById(devices, result.getDeviceId());
for (PositionDto result : results) {
DeviceDto device = findDeviceById(devices, result.getDeviceId());

AvlReport avlReport;

// If have device details use name.
if (device != null && device.getUniqueId() != null && !device.getUniqueId().isEmpty()) {
//Traccar return speed in kt
avlReport = new AvlReport(device.getUniqueId(), device.getName(),
result.getDeviceTime().toDate().getTime(), result.getLatitude().doubleValue(),
result.getLongitude().doubleValue(), result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(), result.getCourse().floatValue(), TRACCARSOURCE.toString());
result.getDeviceTime().toEpochSecond() * 1000,
result.getLatitude().doubleValue(),
result.getLongitude().doubleValue(),
result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(),
result.getCourse().floatValue(), TRACCARSOURCE.toString());
} else {
avlReport = new AvlReport(result.getDeviceId().toString(),
result.getDeviceTime().toDate().getTime(), result.getLatitude().doubleValue(),
result.getLongitude().doubleValue(), result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(), result.getCourse().floatValue(), TRACCARSOURCE.toString());
result.getDeviceTime().toEpochSecond() * 1000,
result.getLatitude().doubleValue(),
result.getLongitude().doubleValue(),
result.getSpeed().multiply(BigDecimal.valueOf(0.5144444)).floatValue(),
result.getCourse().floatValue(), TRACCARSOURCE.toString());
}
if (avlReport != null)
avlReportsReadIn.add(avlReport);
avlReportsReadIn.add(avlReport);
}
forwardAvlReports(avlReportsReadIn);
}
Expand All @@ -117,10 +133,11 @@ protected void forwardAvlReports(Collection<AvlReport> avlReportsReadIn) {
processAvlReports(avlReportsReadIn);
}

private Device findDeviceById(List<Device> devices, Integer id) {
for (Device device : devices) {
if (device.getId().equals(id))
private DeviceDto findDeviceById(List<DeviceDto> devices, Integer id) {
for (DeviceDto device : devices) {
if (Objects.equals(device.getId(), id)) {
return device;
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -803,4 +803,3 @@ public static boolean hasLastAvlJsonInHours(String agencyId, String vehicleId, i
return json.length() > 50;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,16 @@ public static String timeRangeClause(

SimpleDateFormat currentFormat = new SimpleDateFormat("MM-dd-yyyy");
SimpleDateFormat requiredFormat = new SimpleDateFormat("yyyy-MM-dd");
if (beginDate.charAt(4) != '-') {
try {
if (beginDate.charAt(4) != '-') {
beginDate = requiredFormat.format(currentFormat.parse(beginDate));
} else {
requiredFormat.parse(beginDate);
}
} catch (ParseException e) {
logger.error("Exception happened while processing time-range clause", e);
}
}

return " AND %s BETWEEN '%s' AND TIMESTAMP '%s' + INTERVAL '%d day' %s "
.formatted(timeColumnName, beginDate, beginDate, numDays, timeSql);
}
Expand Down
Loading

0 comments on commit cc6b80a

Please sign in to comment.