WORKING: final bugfixes & add stored procedure for prev mission cleanup

This commit is contained in:
2023-06-22 10:27:09 -07:00
parent 3bb8c358fa
commit dbd3d68537
8 changed files with 153 additions and 97 deletions

View File

@@ -18,8 +18,8 @@ class CfgFunctions {
class eventHandlers {}; class eventHandlers {};
class callbackHandler {postInit = 1;}; class callbackHandler {postInit = 1;};
class log {}; class log {};
class logMissionEvent {}; class writeConnect {};
class logServerEvent {}; class writeDisconnect {};
class timestamp {}; class timestamp {};
class getMissionHash {}; class getMissionHash {};
class getWorldInfo {}; class getWorldInfo {};

View File

@@ -46,6 +46,9 @@ addMissionEventHandler ["ExtensionCallback", {
[_response#0, _response#1, _function] call attendanceTracker_fnc_log; [_response#0, _response#1, _function] call attendanceTracker_fnc_log;
if (_response#0 == "SUCCESS") then { if (_response#0 == "SUCCESS") then {
missionNamespace setVariable ["AttendanceTracker_DBConnected", true]; missionNamespace setVariable ["AttendanceTracker_DBConnected", true];
// close any null disconnect values from previous mission
"AttendanceTracker" callExtension ["fillLastMissionNull", []];
// log mission info and get back the row Id to send with future messages // log mission info and get back the row Id to send with future messages
private _response = "AttendanceTracker" callExtension [ private _response = "AttendanceTracker" callExtension [

View File

@@ -15,15 +15,16 @@
}; };
(AttendanceTracker getVariable ["allUsers", createHashMap]) set [_networkId, _userInfo]; (AttendanceTracker getVariable ["allUsers", createHashMap]) set [_networkId, _userInfo];
(AttendanceTracker getVariable ["rowIds", createHashMap]) set [_networkId, [nil, nil]]; // reset rowId on connect
[ [
"Server", "Server",
_playerID, _playerID,
_playerUID, _playerUID,
_profileName, _profileName,
_steamName, _steamName,
nil // send rowId on d/c only nil,
] call attendanceTracker_fnc_logServerEvent; nil
] call attendanceTracker_fnc_writeConnect;
}], }],
["OnUserDisconnected", { ["OnUserDisconnected", {
@@ -45,19 +46,13 @@
[format ["(EventHandler) OnUserDisconnected: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log; [format ["(EventHandler) OnUserDisconnected: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log;
}; };
private _rowId = ((AttendanceTracker getVariable ["rowIds", createHashMap]) getOrDefault [
_networkId,
[nil, nil]
]) select 0;
[ [
"Server", "Server",
_playerID, _playerID,
_playerUID, _playerUID,
_profileName, _profileName,
_steamName, _steamName
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only ] call attendanceTracker_fnc_writeDisconnect;
] call attendanceTracker_fnc_logServerEvent;
}], }],
["PlayerConnected", { ["PlayerConnected", {
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"]; params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
@@ -79,6 +74,7 @@
}; };
(AttendanceTracker getVariable ["allUsers", createHashMap]) set [_playerID, _userInfo]; (AttendanceTracker getVariable ["allUsers", createHashMap]) set [_playerID, _userInfo];
[ [
"Mission", "Mission",
_playerID, _playerID,
@@ -86,9 +82,8 @@
_profileName, _profileName,
_steamName, _steamName,
_jip, _jip,
roleDescription _unit, roleDescription _unit
nil // send rowId on d/c only ] call attendanceTracker_fnc_writeConnect;
] call attendanceTracker_fnc_logMissionEvent;
}], }],
["PlayerDisconnected", { ["PlayerDisconnected", {
// NOTE: HandleDisconnect returns a DIFFERENT _id than PlayerDisconnected and above handlers, so we can't use it here // NOTE: HandleDisconnect returns a DIFFERENT _id than PlayerDisconnected and above handlers, so we can't use it here
@@ -109,11 +104,6 @@
if (_isHC) exitWith { if (_isHC) exitWith {
[format ["(EventHandler) HandleDisconnect: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log; [format ["(EventHandler) HandleDisconnect: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log;
}; };
private _rowId = ((AttendanceTracker getVariable ["rowIds", createHashMap]) getOrDefault [
_idstr,
[nil, nil]
]) select 1;
[ [
"Mission", "Mission",
@@ -122,10 +112,8 @@
_profileName, _profileName,
_steamName, _steamName,
_jip, _jip,
nil, nil
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only ] call attendanceTracker_fnc_writeDisconnect;
] call attendanceTracker_fnc_logMissionEvent;
false; false;
}], }],
@@ -149,32 +137,24 @@
[format ["(EventHandler) OnUserKicked: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log; [format ["(EventHandler) OnUserKicked: %1 is HC, skipping", _playerID], "DEBUG"] call attendanceTracker_fnc_log;
}; };
private _rowId = ((AttendanceTracker getVariable ["rowIds", createHashMap]) getOrDefault [
_networkId,
[nil, nil]
]) select 0;
[ [
"Server", "Server",
_playerID, _playerID,
_playerUID, _playerUID,
_profileName, _profileName,
_steamName, _steamName,
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only nil,
] call attendanceTracker_fnc_logServerEvent; nil
] call attendanceTracker_fnc_writeDisconnect;
private _rowId = ((AttendanceTracker getVariable ["rowIds", createHashMap]) getOrDefault [
_networkId,
[nil, nil]
]) select 1;
[ [
"Mission", "Mission",
_playerID, _playerID,
_playerUID, _playerUID,
_profileName, _profileName,
_steamName, _steamName,
nil // send rowId on d/c only nil,
] call attendanceTracker_fnc_logMissionEvent; nil
] call attendanceTracker_fnc_writeDisconnect;
}] }]
]; ];

View File

@@ -5,11 +5,11 @@ params [
["_profileName", ""], ["_profileName", ""],
["_steamName", ""], ["_steamName", ""],
["_isJIP", false, [true, false]], ["_isJIP", false, [true, false]],
["_roleDescription", ""], ["_roleDescription", ""]
["_rowID", nil]
]; ];
private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]); private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]);
_hash set ["eventType", _eventType]; _hash set ["eventType", _eventType];
_hash set ["playerId", _playerId]; _hash set ["playerId", _playerId];
_hash set ["playerUID", _playerUID]; _hash set ["playerUID", _playerUID];
@@ -19,11 +19,6 @@ _hash set ["isJIP", _isJIP];
_hash set ["roleDescription", _roleDescription]; _hash set ["roleDescription", _roleDescription];
_hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]]; _hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]];
if (!isNil "_rowID") then { "AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
_hash set ["rowID", _rowID];
"AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
} else {
"AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
};
true; true;

View File

@@ -4,26 +4,21 @@ params [
["_playerUID", ""], ["_playerUID", ""],
["_profileName", ""], ["_profileName", ""],
["_steamName", ""], ["_steamName", ""],
["_rowID", nil] ["_isJIP", false, [true, false]],
["_roleDescription", ""]
]; ];
private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]); private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]);
_hash set ["networkId", netID player];
_hash set ["eventType", _eventType]; _hash set ["eventType", _eventType];
_hash set ["playerId", _playerId]; _hash set ["playerId", _playerId];
_hash set ["playerUID", _playerUID]; _hash set ["playerUID", _playerUID];
_hash set ["profileName", _profileName]; _hash set ["profileName", _profileName];
_hash set ["steamName", _steamName]; _hash set ["steamName", _steamName];
_hash set ["isJIP", false]; _hash set ["isJIP", _isJIP];
_hash set ["roleDescription", ""]; _hash set ["roleDescription", _roleDescription];
_hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]]; _hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]];
if (!isNil "_rowID") then { "AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
_hash set ["rowID", _rowID];
"AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
} else {
"AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
};
true; true;

Binary file not shown.

View File

@@ -115,7 +115,7 @@ func getMissionHash() string {
functionName := "getMissionHash" functionName := "getMissionHash"
// get md5 hash of string // get md5 hash of string
// https://stackoverflow.com/questions/2377881/how-to-get-a-md5-hash-from-a-string-in-golang // https://stackoverflow.com/questions/2377881/how-to-get-a-md5-hash-from-a-string-in-golang
hash := md5.Sum([]byte(time.Now().Format("2006-01-02 15:04:05"))) hash := md5.Sum([]byte(time.Now().UTC().Format("2006-01-02 15:04:05")))
// convert to string // convert to string
hashString := fmt.Sprintf(`%x`, hash) hashString := fmt.Sprintf(`%x`, hash)
@@ -154,7 +154,7 @@ func connectDB() string {
return "ERROR" return "ERROR"
} }
// Connect and check the server version // Check the server version
var version string var version string
err = db.QueryRow("SELECT VERSION()").Scan(&version) err = db.QueryRow("SELECT VERSION()").Scan(&version)
if err != nil { if err != nil {
@@ -310,23 +310,22 @@ type AttendanceLogItem struct {
IsJIP bool `json:"isJIP"` IsJIP bool `json:"isJIP"`
RoleDescription string `json:"roleDescription"` RoleDescription string `json:"roleDescription"`
MissionHash string `json:"missionHash"` MissionHash string `json:"missionHash"`
//
RowID int64 `json:"rowID"` // optional
} }
func writeAttendance(data string) { func writeAttendance(data string) {
functionName := "writeAttendance" functionName := "writeAttendance"
var err error
// data is json, parse it // data is json, parse it
stringjson := fixEscapeQuotes(trimQuotes(data)) stringjson := fixEscapeQuotes(trimQuotes(data))
var event AttendanceLogItem var event AttendanceLogItem
err := json.Unmarshal([]byte(stringjson), &event) err = json.Unmarshal([]byte(stringjson), &event)
if err != nil { if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
return return
} }
// get MySQL friendly NOW // get MySQL friendly NOW
now := time.Now().Format("2006-01-02 15:04:05") now := time.Now().UTC().Format("2006-01-02 15:04:05")
// prevent crash // prevent crash
if db == nil { if db == nil {
@@ -335,22 +334,44 @@ func writeAttendance(data string) {
} }
// send to DB // send to DB
result, err := db.ExecContext( var result sql.Result
context.Background(),
fmt.Sprintf( if event.EventType == "Server" {
sql := fmt.Sprintf(
`INSERT INTO %s (join_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
ATTENDANCE_TABLE,
)
result, err = db.ExecContext(
context.Background(),
sql,
now,
event.EventType,
event.PlayerId,
event.PlayerUID,
event.ProfileName,
event.SteamName,
event.IsJIP,
event.RoleDescription,
)
} else if event.EventType == "Mission" {
sql := fmt.Sprintf(
`INSERT INTO %s (join_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, `INSERT INTO %s (join_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
ATTENDANCE_TABLE, ATTENDANCE_TABLE,
), )
now, result, err = db.ExecContext(
event.EventType, context.Background(),
event.PlayerId, sql,
event.PlayerUID, now,
event.ProfileName, event.EventType,
event.SteamName, event.PlayerId,
event.IsJIP, event.PlayerUID,
event.RoleDescription, event.ProfileName,
event.MissionHash, event.SteamName,
) event.IsJIP,
event.RoleDescription,
event.MissionHash,
)
}
if err != nil { if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
@@ -373,8 +394,9 @@ func writeAttendance(data string) {
} }
type DisconnectItem struct { type DisconnectItem struct {
PlayerId string `json:"playerId"` EventType string `json:"eventType"`
RowId string `json:"rowId"` PlayerId string `json:"playerId"`
MissionHash string `json:"missionHash"`
} }
func writeDisconnectEvent(data string) { func writeDisconnectEvent(data string) {
@@ -389,7 +411,7 @@ func writeDisconnectEvent(data string) {
} }
// get MySQL friendly NOW // get MySQL friendly NOW
now := time.Now().Format("2006-01-02 15:04:05") now := time.Now().UTC().Format("2006-01-02 15:04:05")
// prevent crash // prevent crash
if db == nil { if db == nil {
@@ -397,31 +419,88 @@ func writeDisconnectEvent(data string) {
return return
} }
// send to DB // first, check if a row exists for this player
result, err := db.ExecContext( var sql string
context.Background(), if event.EventType == "Mission" {
fmt.Sprintf( sql = fmt.Sprintf(
`UPDATE %s SET disconnect_time = ? WHERE id = ?`, `
ATTENDANCE_TABLE, SELECT id FROM attendance
), WHERE player_id = '%s' and event_type = '%s' and mission_hash = '%s' and disconnect_time IS NULL and join_time >= (NOW() - INTERVAL 24 hour)
now, ORDER BY join_time DESC
event.RowId, `,
) event.PlayerId,
event.EventType,
event.MissionHash,
)
} else if event.EventType == "Server" {
sql = fmt.Sprintf(
`
SELECT id FROM attendance
WHERE player_id = '%s' and event_type = '%s' and disconnect_time IS NULL and join_time >= (NOW() - INTERVAL 24 hour)
ORDER BY join_time DESC
`,
event.PlayerId,
event.EventType,
)
} else {
writeLog(functionName, fmt.Sprintf(`["Unknown event type %s", "ERROR"]`, event.EventType))
return
}
rows, err := db.QueryContext(context.Background(), sql)
if err != nil { if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
return return
} }
defer rows.Close()
rowsAffected, err := result.RowsAffected() // if there is a row, update it
if rows.Next() {
// create interface to hold values
var rowId int64
err = rows.Scan(&rowId)
if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
return
}
// update the row
sql = fmt.Sprintf(
`UPDATE attendance SET disconnect_time = '%s' WHERE id = %d`,
now,
rowId,
)
_, err := db.ExecContext(context.Background(), sql)
if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
return
}
writeLog(functionName, fmt.Sprintf(`["Saved disconnect event for %s to row id %d", "INFO"]`, event.PlayerId, rowId))
} else {
// otherwise, log an error
writeLog(functionName, fmt.Sprintf(`["No row found for %s, %s", "ERROR"]`, event.PlayerId, event.EventType))
}
}
func fillLastMissionNull() {
functionName := "fillLastMissionNull"
// prevent crash
if db == nil {
writeLog(functionName, `["db is nil", "ERROR"]`)
return
}
sql := `call proc_filllastmissionnull`
_, err := db.ExecContext(context.Background(), sql)
if err != nil { if err != nil {
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
return return
} }
writeLog(functionName, `["Filled mission event NULLs", "INFO"]`)
if rowsAffected == 1 {
writeLog(functionName, fmt.Sprintf(`["Saved disconnect event for %s to row id %s", "INFO"]`, event.PlayerId, event.RowId))
}
} }
func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int { func runExtensionCallback(name *C.char, function *C.char, data *C.char) C.int {
@@ -452,6 +531,10 @@ func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv
temp := fmt.Sprintf("Function: %s nb params: %d", C.GoString(input), argc) temp := fmt.Sprintf("Function: %s nb params: %d", C.GoString(input), argc)
switch C.GoString(input) { switch C.GoString(input) {
case "fillLastMissionNull":
{
go fillLastMissionNull()
}
case "writeAttendance": case "writeAttendance":
{ // callExtension ["logAttendance", [_hash] call CBA_fnc_encodeJSON]]; { // callExtension ["logAttendance", [_hash] call CBA_fnc_encodeJSON]];
if argc == 1 { if argc == 1 {
@@ -503,7 +586,7 @@ func callBackExample() {
func getTimestamp() string { func getTimestamp() string {
// get the current unix timestamp in nanoseconds // get the current unix timestamp in nanoseconds
// return time.Now().Local().Unix() // return time.Now().Local().Unix()
return time.Now().Format("2006-01-02 15:04:05") return time.Now().UTC().Format("2006-01-02 15:04:05")
} }
func trimQuotes(s string) string { func trimQuotes(s string) string {