mirror of
https://github.com/indig0fox/Arma3-AttendanceTracker.git/
synced 2025-12-08 09:51:47 -06:00
WORKING: final bugfixes & add stored procedure for prev mission cleanup
This commit is contained in:
Binary file not shown.
@@ -18,8 +18,8 @@ class CfgFunctions {
|
||||
class eventHandlers {};
|
||||
class callbackHandler {postInit = 1;};
|
||||
class log {};
|
||||
class logMissionEvent {};
|
||||
class logServerEvent {};
|
||||
class writeConnect {};
|
||||
class writeDisconnect {};
|
||||
class timestamp {};
|
||||
class getMissionHash {};
|
||||
class getWorldInfo {};
|
||||
|
||||
@@ -47,6 +47,9 @@ addMissionEventHandler ["ExtensionCallback", {
|
||||
if (_response#0 == "SUCCESS") then {
|
||||
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
|
||||
private _response = "AttendanceTracker" callExtension [
|
||||
"logMission",
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
};
|
||||
|
||||
(AttendanceTracker getVariable ["allUsers", createHashMap]) set [_networkId, _userInfo];
|
||||
(AttendanceTracker getVariable ["rowIds", createHashMap]) set [_networkId, [nil, nil]]; // reset rowId on connect
|
||||
|
||||
[
|
||||
"Server",
|
||||
_playerID,
|
||||
_playerUID,
|
||||
_profileName,
|
||||
_steamName,
|
||||
nil // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logServerEvent;
|
||||
nil,
|
||||
nil
|
||||
] call attendanceTracker_fnc_writeConnect;
|
||||
|
||||
}],
|
||||
["OnUserDisconnected", {
|
||||
@@ -45,19 +46,13 @@
|
||||
[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",
|
||||
_playerID,
|
||||
_playerUID,
|
||||
_profileName,
|
||||
_steamName,
|
||||
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logServerEvent;
|
||||
_steamName
|
||||
] call attendanceTracker_fnc_writeDisconnect;
|
||||
}],
|
||||
["PlayerConnected", {
|
||||
params ["_id", "_uid", "_name", "_jip", "_owner", "_idstr"];
|
||||
@@ -79,6 +74,7 @@
|
||||
};
|
||||
|
||||
(AttendanceTracker getVariable ["allUsers", createHashMap]) set [_playerID, _userInfo];
|
||||
|
||||
[
|
||||
"Mission",
|
||||
_playerID,
|
||||
@@ -86,9 +82,8 @@
|
||||
_profileName,
|
||||
_steamName,
|
||||
_jip,
|
||||
roleDescription _unit,
|
||||
nil // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logMissionEvent;
|
||||
roleDescription _unit
|
||||
] call attendanceTracker_fnc_writeConnect;
|
||||
}],
|
||||
["PlayerDisconnected", {
|
||||
// NOTE: HandleDisconnect returns a DIFFERENT _id than PlayerDisconnected and above handlers, so we can't use it here
|
||||
@@ -110,11 +105,6 @@
|
||||
[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",
|
||||
_playerID,
|
||||
@@ -122,10 +112,8 @@
|
||||
_profileName,
|
||||
_steamName,
|
||||
_jip,
|
||||
nil,
|
||||
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logMissionEvent;
|
||||
|
||||
nil
|
||||
] call attendanceTracker_fnc_writeDisconnect;
|
||||
|
||||
false;
|
||||
}],
|
||||
@@ -149,32 +137,24 @@
|
||||
[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",
|
||||
_playerID,
|
||||
_playerUID,
|
||||
_profileName,
|
||||
_steamName,
|
||||
(if (!isNil "_rowId") then {_rowId} else {nil}) // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logServerEvent;
|
||||
nil,
|
||||
nil
|
||||
] call attendanceTracker_fnc_writeDisconnect;
|
||||
|
||||
|
||||
private _rowId = ((AttendanceTracker getVariable ["rowIds", createHashMap]) getOrDefault [
|
||||
_networkId,
|
||||
[nil, nil]
|
||||
]) select 1;
|
||||
[
|
||||
"Mission",
|
||||
_playerID,
|
||||
_playerUID,
|
||||
_profileName,
|
||||
_steamName,
|
||||
nil // send rowId on d/c only
|
||||
] call attendanceTracker_fnc_logMissionEvent;
|
||||
nil,
|
||||
nil
|
||||
] call attendanceTracker_fnc_writeDisconnect;
|
||||
}]
|
||||
];
|
||||
@@ -5,11 +5,11 @@ params [
|
||||
["_profileName", ""],
|
||||
["_steamName", ""],
|
||||
["_isJIP", false, [true, false]],
|
||||
["_roleDescription", ""],
|
||||
["_rowID", nil]
|
||||
["_roleDescription", ""]
|
||||
];
|
||||
|
||||
private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]);
|
||||
|
||||
_hash set ["eventType", _eventType];
|
||||
_hash set ["playerId", _playerId];
|
||||
_hash set ["playerUID", _playerUID];
|
||||
@@ -19,11 +19,6 @@ _hash set ["isJIP", _isJIP];
|
||||
_hash set ["roleDescription", _roleDescription];
|
||||
_hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]];
|
||||
|
||||
if (!isNil "_rowID") then {
|
||||
_hash set ["rowID", _rowID];
|
||||
"AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
} else {
|
||||
"AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
};
|
||||
"AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
|
||||
true;
|
||||
@@ -4,26 +4,21 @@ params [
|
||||
["_playerUID", ""],
|
||||
["_profileName", ""],
|
||||
["_steamName", ""],
|
||||
["_rowID", nil]
|
||||
["_isJIP", false, [true, false]],
|
||||
["_roleDescription", ""]
|
||||
];
|
||||
|
||||
|
||||
private _hash = + (AttendanceTracker getVariable ["missionContext", createHashMap]);
|
||||
_hash set ["networkId", netID player];
|
||||
|
||||
_hash set ["eventType", _eventType];
|
||||
_hash set ["playerId", _playerId];
|
||||
_hash set ["playerUID", _playerUID];
|
||||
_hash set ["profileName", _profileName];
|
||||
_hash set ["steamName", _steamName];
|
||||
_hash set ["isJIP", false];
|
||||
_hash set ["roleDescription", ""];
|
||||
_hash set ["isJIP", _isJIP];
|
||||
_hash set ["roleDescription", _roleDescription];
|
||||
_hash set ["missionHash", missionNamespace getVariable ["AttendanceTracker_missionHash", ""]];
|
||||
|
||||
if (!isNil "_rowID") then {
|
||||
_hash set ["rowID", _rowID];
|
||||
"AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
} else {
|
||||
"AttendanceTracker" callExtension ["writeAttendance", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
};
|
||||
"AttendanceTracker" callExtension ["writeDisconnectEvent", [[_hash] call CBA_fnc_encodeJSON]];
|
||||
|
||||
true;
|
||||
Binary file not shown.
@@ -115,7 +115,7 @@ func getMissionHash() string {
|
||||
functionName := "getMissionHash"
|
||||
// get md5 hash of string
|
||||
// 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
|
||||
hashString := fmt.Sprintf(`%x`, hash)
|
||||
@@ -154,7 +154,7 @@ func connectDB() string {
|
||||
return "ERROR"
|
||||
}
|
||||
|
||||
// Connect and check the server version
|
||||
// Check the server version
|
||||
var version string
|
||||
err = db.QueryRow("SELECT VERSION()").Scan(&version)
|
||||
if err != nil {
|
||||
@@ -310,23 +310,22 @@ type AttendanceLogItem struct {
|
||||
IsJIP bool `json:"isJIP"`
|
||||
RoleDescription string `json:"roleDescription"`
|
||||
MissionHash string `json:"missionHash"`
|
||||
//
|
||||
RowID int64 `json:"rowID"` // optional
|
||||
}
|
||||
|
||||
func writeAttendance(data string) {
|
||||
functionName := "writeAttendance"
|
||||
var err error
|
||||
// data is json, parse it
|
||||
stringjson := fixEscapeQuotes(trimQuotes(data))
|
||||
var event AttendanceLogItem
|
||||
err := json.Unmarshal([]byte(stringjson), &event)
|
||||
err = json.Unmarshal([]byte(stringjson), &event)
|
||||
if err != nil {
|
||||
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
|
||||
return
|
||||
}
|
||||
|
||||
// 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
|
||||
if db == nil {
|
||||
@@ -335,12 +334,33 @@ func writeAttendance(data string) {
|
||||
}
|
||||
|
||||
// send to DB
|
||||
result, err := db.ExecContext(
|
||||
var result sql.Result
|
||||
|
||||
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(),
|
||||
fmt.Sprintf(
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
ATTENDANCE_TABLE,
|
||||
),
|
||||
)
|
||||
result, err = db.ExecContext(
|
||||
context.Background(),
|
||||
sql,
|
||||
now,
|
||||
event.EventType,
|
||||
event.PlayerId,
|
||||
@@ -351,6 +371,7 @@ func writeAttendance(data string) {
|
||||
event.RoleDescription,
|
||||
event.MissionHash,
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
|
||||
@@ -373,8 +394,9 @@ func writeAttendance(data string) {
|
||||
}
|
||||
|
||||
type DisconnectItem struct {
|
||||
EventType string `json:"eventType"`
|
||||
PlayerId string `json:"playerId"`
|
||||
RowId string `json:"rowId"`
|
||||
MissionHash string `json:"missionHash"`
|
||||
}
|
||||
|
||||
func writeDisconnectEvent(data string) {
|
||||
@@ -389,7 +411,7 @@ func writeDisconnectEvent(data string) {
|
||||
}
|
||||
|
||||
// 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
|
||||
if db == nil {
|
||||
@@ -397,31 +419,88 @@ func writeDisconnectEvent(data string) {
|
||||
return
|
||||
}
|
||||
|
||||
// send to DB
|
||||
result, err := db.ExecContext(
|
||||
context.Background(),
|
||||
fmt.Sprintf(
|
||||
`UPDATE %s SET disconnect_time = ? WHERE id = ?`,
|
||||
ATTENDANCE_TABLE,
|
||||
),
|
||||
// first, check if a row exists for this player
|
||||
var sql string
|
||||
if event.EventType == "Mission" {
|
||||
sql = fmt.Sprintf(
|
||||
`
|
||||
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)
|
||||
ORDER BY join_time DESC
|
||||
`,
|
||||
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 {
|
||||
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// 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,
|
||||
event.RowId,
|
||||
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))
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
} 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 {
|
||||
writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err))
|
||||
return
|
||||
}
|
||||
|
||||
if rowsAffected == 1 {
|
||||
writeLog(functionName, fmt.Sprintf(`["Saved disconnect event for %s to row id %s", "INFO"]`, event.PlayerId, event.RowId))
|
||||
}
|
||||
writeLog(functionName, `["Filled mission event NULLs", "INFO"]`)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
switch C.GoString(input) {
|
||||
case "fillLastMissionNull":
|
||||
{
|
||||
go fillLastMissionNull()
|
||||
}
|
||||
case "writeAttendance":
|
||||
{ // callExtension ["logAttendance", [_hash] call CBA_fnc_encodeJSON]];
|
||||
if argc == 1 {
|
||||
@@ -503,7 +586,7 @@ func callBackExample() {
|
||||
func getTimestamp() string {
|
||||
// get the current unix timestamp in nanoseconds
|
||||
// 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 {
|
||||
|
||||
Reference in New Issue
Block a user