static void process_vstp(const char * string, const jsmntok_t * tokens) { char zs[128]; stats[GoodMessage]++; jsmn_find_extract_token(string, tokens, 0, "transaction_type", zs, sizeof(zs)); if(zs[0]) { // printf(" Transaction type: \"%s\"", zs); if(!strcasecmp(zs, "Delete")) process_delete_schedule(string, tokens); else if(!strcasecmp(zs, "Create")) process_create_schedule(string, tokens, false); else if(!strcasecmp(zs, "Update")) process_update_schedule(string, tokens); else { _log(MAJOR, "process_schedule(): Unrecognised transaction type \"%s\".", zs); jsmn_dump_tokens(body, tokens, 0); stats[NotTransaction]++; } } else { _log(MAJOR, "process_schedule(): Failed to determine transaction type."); jsmn_dump_tokens(body, tokens, 0); stats[NotTransaction]++; } }
static void process_object(const char * object_string) { // Passed a string containing a JSON object. // Parse it and process it. char zs[256]; _log(PROC, "process_object()"); jsmn_parser parser; jsmn_init(&parser); int r = jsmn_parse(&parser, object_string, tokens, MAX_TOKENS); if(r != JSMN_SUCCESS) { sprintf(zs, "Parser result %d. ", r); switch(r) { case JSMN_SUCCESS: strcat(zs, "Success. "); break; case JSMN_ERROR_INVAL: strcat(zs, "Error - Invalid. "); break; case JSMN_ERROR_NOMEM: strcat(zs, "Error - Nomem. "); break; case JSMN_ERROR_PART: strcat(zs, "Error - Part JSON. "); break; default: strcat(zs, "Unknown response. "); break; } _log(MAJOR, zs); return; } if(tokens[1].type == JSMN_NAME) { char message_name[128]; stats[JSONRecords]++; // NB This INCLUDES ones we don't use, like TiplocV1 jsmn_extract_token(object_string, tokens, 1, message_name, sizeof(message_name)); if(!strcmp(message_name, "JsonTimetableV1")) process_timetable(object_string, tokens); else if(!strcmp(message_name, "JsonAssociationV1")) ; else if(!strcmp(message_name, "JsonScheduleV1")) process_schedule(object_string, tokens); else if(!strcmp(message_name, "TiplocV1")) ; else if(!strcmp(message_name, "EOF")) ; else { _log(MINOR, "Unrecognised message name \"%s\".", message_name); jsmn_dump_tokens(object_string, tokens, 0); stats[JSONRecords]--; } } else { _log(MAJOR, "Unrecognised message."); jsmn_dump_tokens(object_string, tokens, 0); } return; }
static void process_frame(const char * body) { jsmn_parser parser; time_t elapsed = time(NULL); jsmn_init(&parser); int r = jsmn_parse(&parser, body, tokens, NUM_TOKENS); if(r != 0) { _log(MAJOR, "Parser result %d. Message discarded.", r); stats[NotVSTP]++; } else { // Good message char message_name[128]; jsmn_extract_token(body, tokens, 1, message_name, sizeof(message_name)); if(!strcmp(message_name, "VSTPCIFMsgV1")) { process_vstp(body, tokens); } else { _log(MINOR, "Unrecognised message name \"%s\".", message_name); jsmn_dump_tokens(body, tokens, 0); stats[NotVSTP]++; } } elapsed = time(NULL) - elapsed; if(elapsed > 1 || debug) { _log(MINOR, "Transaction took %ld seconds.", elapsed); } }
static void process_update_schedule(const char * string, const jsmntok_t * tokens) { char query[1024], CIF_train_uid[16], schedule_start_date[16], schedule_end_date[16], CIF_stp_indicator[8]; dword id; MYSQL_RES * result0; MYSQL_ROW row0; EXTRACT("CIF_train_uid", CIF_train_uid); EXTRACT("schedule_start_date", schedule_start_date); EXTRACT("schedule_end_date", schedule_end_date); EXTRACT("CIF_stp_indicator", CIF_stp_indicator); time_t schedule_start_date_stamp = parse_datestamp(schedule_start_date); // time_t schedule_end_date_stamp = parse_datestamp(schedule_end_date); sprintf(query, "SELECT id FROM cif_schedules WHERE update_id = 0 AND CIF_train_uid = '%s' AND CIF_stp_indicator = '%s' AND schedule_start_date = %ld AND deleted > %ld", CIF_train_uid, CIF_stp_indicator, schedule_start_date_stamp, time(NULL)); if(!db_query(query)) { result0 = db_store_result(); word num_rows = mysql_num_rows(result0); if(num_rows != 1) { _log(MAJOR, "Update for schedule \"%s\" found %d existing records. Delete phase skipped.", CIF_train_uid, num_rows); jsmn_dump_tokens(string, tokens, 0); if(num_rows) stats[UpdateDeleteMulti]++; else stats[UpdateDeleteMiss]++; } else { row0 = mysql_fetch_row(result0); id = atol(row0[0]); //sprintf(query, "DELETE FROM cif_schedule_locations WHERE cif_schedule_id = %ld", id); //db_query(query); sprintf(query, "UPDATE cif_schedules SET deleted = %ld WHERE id = %ld", time(NULL), id); db_query(query); } mysql_free_result(result0); } // Create phase. process_create_schedule(string, tokens, true); _log(DEBUG, "Updated schedule \"%s\".", CIF_train_uid); }
static void process_create_schedule(const char * string, const jsmntok_t * tokens, const word update) { // update true indicates this is as the result of a VSTP update. char zs[128], zs1[128]; char query[2048]; word i; char uid[16], stp_indicator[2]; char signalling_id[8]; if(debug) jsmn_dump_tokens(string, tokens, 0); time_t now = time(NULL); sprintf(query, "INSERT INTO cif_schedules VALUES(0, %ld, %lu", now, NOT_DELETED); // update_id == 0 => VSTP EXTRACT_APPEND_SQL("CIF_bank_holiday_running"); //EXTRACT_APPEND_SQL("CIF_stp_indicator"); EXTRACT("CIF_stp_indicator", stp_indicator); sprintf(zs1, ", '%s'", stp_indicator); strcat(query, zs1); //EXTRACT_APPEND_SQL("CIF_train_uid"); EXTRACT("CIF_train_uid", uid); sprintf(zs1, ", '%s'", uid); strcat(query, zs1); EXTRACT_APPEND_SQL("applicable_timetable"); EXTRACT_APPEND_SQL("atoc_code"); // EXTRACT_APPEND_SQL("traction_class"); EXTRACT_APPEND_SQL("uic_code"); EXTRACT("schedule_days_runs", zs); for(i=0; i<7; i++) { strcat(query, ", "); strcat(query, (zs[i]=='1')?"1":"0"); } EXTRACT("schedule_end_date", zs); time_t z = parse_datestamp(zs); sprintf(zs1, ", %ld", z); strcat(query, zs1); EXTRACT("signalling_id", signalling_id); sprintf(zs1, ", '%s'", signalling_id); strcat(query, zs1); EXTRACT_APPEND_SQL("CIF_train_category"); EXTRACT_APPEND_SQL("CIF_headcode"); //EXTRACT_APPEND_SQL("CIF_course_indicator"); EXTRACT_APPEND_SQL("CIF_train_service_code"); EXTRACT_APPEND_SQL("CIF_business_sector"); EXTRACT_APPEND_SQL("CIF_power_type"); EXTRACT_APPEND_SQL("CIF_timing_load"); EXTRACT_APPEND_SQL("CIF_speed"); EXTRACT_APPEND_SQL("CIF_operating_characteristics"); EXTRACT_APPEND_SQL("CIF_train_class"); EXTRACT_APPEND_SQL("CIF_sleepers"); EXTRACT_APPEND_SQL("CIF_reservations"); EXTRACT_APPEND_SQL("CIF_connection_indicator"); EXTRACT_APPEND_SQL("CIF_catering_code"); EXTRACT_APPEND_SQL("CIF_service_branding"); EXTRACT("schedule_start_date", zs); z = parse_datestamp(zs); sprintf(zs1, ", %ld", z); strcat(query, zs1); EXTRACT_APPEND_SQL("train_status"); strcat(query, ", 0, '', '')"); // id filled by MySQL if(!db_query(query)) { stats[update?UpdateCreate:Create]++; } dword id = db_insert_id(); word index = jsmn_find_name_token(string, tokens, 0, "schedule_location"); word locations = tokens[index+1].size; huyton_flag = false; index += 2; for(i = 0; i < locations; i++) { index = process_create_schedule_location(string, tokens, index, id); } if(stp_indicator[0] == 'O' && (signalling_id[0] == '\0' || signalling_id[0] == ' ')) { // Search db for schedules with a deduced headcode, and add it to this one, status = D // Bug: Really this should also look for schedules with a signalling_id MYSQL_RES * result; MYSQL_ROW row; sprintf(query, "SELECT deduced_headcode FROM cif_schedules WHERE CIF_train_uid = '%s' AND deduced_headcode != '' AND schedule_end_date > %ld ORDER BY created DESC", uid, now - (64L * 24L * 60L * 60L)); if(!db_query(query)) { result = db_store_result(); if((row = mysql_fetch_row(result))) { sprintf(query, "UPDATE cif_schedules SET deduced_headcode = '%s', deduced_headcode_status = 'D' WHERE id = %ld", row[0], id); db_query(query); _log(DEBUG, "Deduced headcode \"%s\" applied to overlay schedule %ld, uid \"%s\".", row[0], id, uid); stats[HeadcodeDeduced]++; } else { _log(DEBUG, "Deduced headcode not found for overlay schedule %ld, uid \"%s\".", id, uid); } mysql_free_result(result); } } sprintf(query, "UPDATE status SET last_vstp_processed = %ld", now); db_query(query); if(huyton_flag) { _log(DEBUG, "Created schedule %ld%s. +++ Passes Huyton +++", id, update?" as a result of an Update transaction":""); } if(huyton_flag) { char title[64], message[512]; MYSQL_RES * result0; MYSQL_ROW row0; char stp[4]; sprintf(title, "Huyton Schedule Created."); sprintf(message, "Created schedule which passes Huyton."); if(update) strcat(message, " Due to a VSTP Update transaction."); strcat(message, "\n\n"); EXTRACT("CIF_train_uid", zs1); EXTRACT("CIF_stp_indicator", stp); sprintf(zs, "%ld (%s %s) ", id, zs1, stp); EXTRACT("signalling_id", zs1); strcat(zs, zs1); sprintf(query, "SELECT tiploc_code, departure FROM cif_schedule_locations WHERE record_identity = 'LO' AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { sprintf(zs1, " %s %s to ", show_time_text(row0[1]), tiploc_name(row0[0])); strcat(zs, zs1); } mysql_free_result(result0); } sprintf(query, "SELECT tiploc_code FROM cif_schedule_locations WHERE record_identity = 'LT' AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { strcat (zs, tiploc_name(row0[0])); } mysql_free_result(result0); } strcat(message, zs); sprintf(query, "SELECT schedule_start_date, schedule_end_date, CIF_stp_indicator FROM cif_schedules WHERE id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); if((row0 = mysql_fetch_row(result0))) { dword from = atol(row0[0]); dword to = atol(row0[1]); if(from == to) { strcat(message, " Runs on "); strcat(message, date_text(from, true)); } else { strcat(message, " Runs from "); strcat(message, date_text(from, true)); strcat(message, " to "); strcat(message, date_text(to, true)); } if(row0[2][0] == 'C') strcat(message, " CANCELLED"); strcat(message, "\n"); } mysql_free_result(result0); } sprintf(query, "SELECT departure, arrival, pass, tiploc_code FROM cif_schedule_locations WHERE (tiploc_code = 'HUYTON' OR tiploc_code = 'HUYTJUN') AND cif_schedule_id = %ld", id); if(!db_query(query)) { result0 = db_store_result(); while((row0 = mysql_fetch_row(result0))) { char where[32], z[128]; if(row0[3][4] == 'J') strcpy(where, "Huyton Junction"); else strcpy(where, "Huyton"); if(row0[0][0]) { sprintf(z, "Depart %s at %s.\n", where, row0[0]); strcat(message, z); } else if(row0[1][0]) { sprintf(z, "Arrive %s at %s.\n", where, row0[1]); strcat(message, z); } else if(row0[2][0]) { sprintf(z, "Pass %s at %s.\n", where, row0[2]); strcat(message, z); } } mysql_free_result(result0); } email_alert(NAME, BUILD, title, message); } }
static void process_delete_schedule(const char * string, const jsmntok_t * tokens) { char query[1024], CIF_train_uid[16], schedule_start_date[16], schedule_end_date[16], CIF_stp_indicator[8]; dword id; word update_id; MYSQL_RES * result0; MYSQL_ROW row0; word deleted = 0; EXTRACT("CIF_train_uid", CIF_train_uid); EXTRACT("schedule_start_date", schedule_start_date); EXTRACT("schedule_end_date", schedule_end_date); EXTRACT("CIF_stp_indicator", CIF_stp_indicator); time_t schedule_start_date_stamp = parse_datestamp(schedule_start_date); time_t schedule_end_date_stamp = parse_datestamp(schedule_end_date); // Find the id sprintf(query, "SELECT id, update_id FROM cif_schedules where CIF_train_uid = '%s' and schedule_start_date = '%ld' and schedule_end_date = %ld and CIF_stp_indicator = '%s' AND update_id = 0 AND deleted > %ld", CIF_train_uid, schedule_start_date_stamp, schedule_end_date_stamp, CIF_stp_indicator, time(NULL)); // DO WE NEED DAYS RUNS AS WELL???? // Note: Only find VSTP ones. if (db_query(query)) { db_disconnect(); return; } result0 = db_store_result(); word num_rows = mysql_num_rows(result0); if(num_rows > 1) { char zs[256]; sprintf(zs, "Delete schedule found %d matches.", num_rows); _log(MAJOR, zs); jsmn_dump_tokens(string, tokens, 0); stats[DeleteMulti]++; // Bodge! query[7] = '*'; query[8] = ' '; dump_mysql_result_query(query); } while((row0 = mysql_fetch_row(result0)) && row0[0]) { id = atol(row0[0]); update_id = atoi(row0[1]); //sprintf(query, "DELETE FROM cif_schedule_locations WHERE cif_schedule_id = %ld", id); //if(!db_query(query)) //{ //} sprintf(query, "UPDATE cif_schedules SET deleted = %ld where id = %ld", time(NULL), id); if(!db_query(query)) { deleted++; if(update_id) { // Can never happen! _log(MAJOR, "Deleted non-VSTP schedule %ld.", id); } else { _log(DEBUG, "Deleted VSTP schedule %ld \"%s\".", id, CIF_train_uid); } } } mysql_free_result(result0); if(deleted) { stats[DeleteHit]++; } else { _log(MAJOR, "Delete schedule miss."); jsmn_dump_tokens(string, tokens, 0); stats[DeleteMiss]++; } }
static void process_trust_0001(const char * const string, const jsmntok_t * const tokens, const int index) { char zs[128], zs1[128], report[1024]; char train_id[64], train_uid[64]; char query[1024]; dword cif_schedule_id; MYSQL_RES * result0; MYSQL_ROW row0; sprintf(report, "Activation message:"); jsmn_find_extract_token(string, tokens, index, "train_id", train_id, sizeof(train_id)); sprintf(zs1, " train_id=\"%s\"", train_id); strcat(report, zs1); jsmn_find_extract_token(string, tokens, index, "schedule_start_date", zs, sizeof(zs)); time_t schedule_start_date_stamp = parse_datestamp(zs); sprintf(zs1, " schedule_start_date=\"%s\" %ld", zs, schedule_start_date_stamp); strcat(report, zs1); jsmn_find_extract_token(string, tokens, index, "schedule_end_date", zs, sizeof(zs)); time_t schedule_end_date_stamp = parse_datestamp(zs); sprintf(zs1, " schedule_end_date=\"%s\" %ld", zs, schedule_end_date_stamp); strcat(report, zs1); jsmn_find_extract_token(string, tokens, index, "train_uid", train_uid, sizeof(train_uid)); sprintf(zs1, " train_uid=\"%s\"", train_uid); strcat(report, zs1); jsmn_find_extract_token(string, tokens, index, "schedule_source", zs, sizeof(zs)); sprintf(zs1, " schedule_source=\"%s\"", zs); strcat(report, zs1); jsmn_find_extract_token(string, tokens, index, "schedule_wtt_id", zs, sizeof(zs)); sprintf(zs1, " schedule_wtt_id=\"%s\"", zs); strcat(report, zs1); // Bodge. The ORDER BY here will *usually* get the correct one out first! // Idea: If we store and index on cif_train_uid, we can guarantee to get the right one. sprintf(query, "select id from cif_schedules where cif_train_uid = '%s' AND schedule_start_date = %ld AND schedule_end_date = %ld AND deleted > %ld ORDER BY LOCATE(CIF_stp_indicator, 'OCPN')", train_uid, schedule_start_date_stamp, schedule_end_date_stamp, time(NULL)); if(!db_query(query)) { result0 = db_store_result(); word num_rows = mysql_num_rows(result0); sprintf(zs, " Schedule hit count %d. Message contents:", num_rows); strcat(report, zs); if(num_rows < 1) { stats[Mess1Miss]++; _log(MINOR, report); time_t now = time(NULL); sprintf(query, "INSERT INTO trust_activation VALUES(%ld, '%s', %ld, 0)", now, train_id, 0L); db_query(query); jsmn_dump_tokens(string, tokens, index); } else { row0 = mysql_fetch_row(result0); cif_schedule_id = atol(row0[0]); time_t now = time(NULL); sprintf(query, "INSERT INTO trust_activation VALUES(%ld, '%s', %ld, 0)", now, train_id, cif_schedule_id); db_query(query); } mysql_free_result(result0); } return; }
static void process_message(const char * const body) { jsmn_parser parser; time_t elapsed = time(NULL); log_message(body); jsmn_init(&parser); int r = jsmn_parse(&parser, body, tokens, NUM_TOKENS); if(r != 0) { sprintf(zs, "Parser result %d. Message discarded.", r); _log(MAJOR, zs); stats[NotRecog]++; } else { size_t messages, i, index; // Is it an array? if(tokens[0].type == JSMN_ARRAY) { messages = tokens[0].size; index = 1; sprintf(zs, "STOMP message is array of %d TRUST messages.", messages); } else { messages = 1; index = 0; sprintf(zs, "STOMP message contains a single TRUST message."); } _log(DEBUG,zs); for(i=0; i < messages; i++) { char message_name[128]; jsmn_find_extract_token(body, tokens, index, "msg_type", message_name, sizeof(message_name)); word message_type = atoi(message_name); if(debug) { sprintf(zs, "Processing TRUST message %d", i); _log(DEBUG, zs); } if(!strncmp(message_name, "000", 3) && message_type > 0 && message_type < 9) { stats[GoodMessage]++; stats[GoodMessage + message_type]++; switch(message_type) { case 1: process_trust_0001(body, tokens, index); break; case 2: process_trust_0002(body, tokens, index); break; case 3: process_trust_0003(body, tokens, index); break; case 5: process_trust_0005(body, tokens, index); break; case 6: process_trust_0006(body, tokens, index); break; case 7: process_trust_0007(body, tokens, index); break; default: sprintf(zs, "Message type \"%s\" discarded.", message_name); _log(MINOR, zs); break; } } else { sprintf(zs, "Unrecognised message type \"%s\".", message_name); _log(MINOR, zs); jsmn_dump_tokens(body, tokens, index); stats[NotRecog]++; } size_t message_ends = tokens[index].end; do index++; while ( tokens[index].start < message_ends && tokens[index].start >= 0 && index < NUM_TOKENS); } } elapsed = time(NULL) - elapsed; if(debug || elapsed > 1) { char zs[128]; sprintf(zs, "Transaction took %ld seconds.", elapsed); _log(MINOR, zs); } }