-
-
Notifications
You must be signed in to change notification settings - Fork 365
replace Map with sync.Map to handle concurrent reads/writes (changes generated by Cursor); #2646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package persistence | |
|
||
import ( | ||
"fmt" | ||
"sync" | ||
|
||
"pyrevittelemetryserver/cli" | ||
|
||
|
@@ -21,26 +22,37 @@ type TraceInfoV1 struct { | |
} | ||
|
||
type ScriptTelemetryRecordV1 struct { | ||
Date string `json:"date" bson:"date" valid:"-"` | ||
Time string `json:"time" bson:"time" valid:"-"` | ||
UserName string `json:"username" bson:"username" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
SessionId string `json:"sessionid" bson:"sessionid" valid:"uuidv4~Invalid session id"` | ||
PyRevitVersion string `json:"pyrevit" bson:"pyrevit" valid:"-"` | ||
IsDebugMode bool `json:"debug" bson:"debug"` | ||
IsConfigMode bool `json:"config" bson:"config"` | ||
CommandName string `json:"commandname" bson:"commandname" valid:"-"` | ||
CommandUniqueName string `json:"commanduniquename" bson:"commanduniquename" valid:"-"` | ||
BundleName string `json:"commandbundle" bson:"commandbundle" valid:"-"` | ||
ExtensionName string `json:"commandextension" bson:"commandextension" valid:"-"` | ||
ResultCode int `json:"resultcode" bson:"resultcode" valid:"numeric~Invalid result code"` | ||
CommandResults map[string]string `json:"commandresults" bson:"commandresults" valid:"-"` | ||
ScriptPath string `json:"scriptpath" bson:"scriptpath" valid:"-"` | ||
TraceInfo TraceInfoV1 `json:"trace" bson:"trace"` | ||
Date string `json:"date" bson:"date" valid:"-"` | ||
Time string `json:"time" bson:"time" valid:"-"` | ||
UserName string `json:"username" bson:"username" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
SessionId string `json:"sessionid" bson:"sessionid" valid:"uuidv4~Invalid session id"` | ||
PyRevitVersion string `json:"pyrevit" bson:"pyrevit" valid:"-"` | ||
IsDebugMode bool `json:"debug" bson:"debug"` | ||
IsConfigMode bool `json:"config" bson:"config"` | ||
CommandName string `json:"commandname" bson:"commandname" valid:"-"` | ||
CommandUniqueName string `json:"commanduniquename" bson:"commanduniquename" valid:"-"` | ||
BundleName string `json:"commandbundle" bson:"commandbundle" valid:"-"` | ||
ExtensionName string `json:"commandextension" bson:"commandextension" valid:"-"` | ||
ResultCode int `json:"resultcode" bson:"resultcode" valid:"numeric~Invalid result code"` | ||
CommandResults sync.Map `json:"commandresults" bson:"commandresults" valid:"-"` | ||
ScriptPath string `json:"scriptpath" bson:"scriptpath" valid:"-"` | ||
TraceInfo TraceInfoV1 `json:"trace" bson:"trace"` | ||
} | ||
|
||
func (logrec ScriptTelemetryRecordV1) PrintRecordInfo(logger *cli.Logger, message string) { | ||
// Convert sync.Map to regular map for printing | ||
results := make(map[string]string) | ||
logrec.CommandResults.Range(func(key, value interface{}) bool { | ||
if k, ok := key.(string); ok { | ||
if v, ok := value.(string); ok { | ||
results[k] = v | ||
} | ||
} | ||
return true | ||
}) | ||
|
||
logger.Print(fmt.Sprintf( | ||
"%s %s-%s %q @ %s:%s [%s.%s] code=%d info=%v", | ||
message, | ||
|
@@ -52,7 +64,7 @@ func (logrec ScriptTelemetryRecordV1) PrintRecordInfo(logger *cli.Logger, messag | |
logrec.ExtensionName, | ||
logrec.CommandName, | ||
logrec.ResultCode, | ||
logrec.CommandResults, | ||
results, | ||
)) | ||
} | ||
|
||
|
@@ -66,10 +78,10 @@ func (logrec ScriptTelemetryRecordV1) Validate() error { | |
|
||
// v2.0 | ||
type EngineInfoV2 struct { | ||
Type string `json:"type" bson:"type" valid:"engine~Invalid executor engine type"` | ||
Version string `json:"version" bson:"version" valid:"-"` | ||
SysPaths []string `json:"syspath" bson:"syspath" valid:"-"` | ||
Configs map[string]interface{} `json:"configs" bson:"configs" valid:"-"` | ||
Type string `json:"type" bson:"type" valid:"engine~Invalid executor engine type"` | ||
Version string `json:"version" bson:"version" valid:"-"` | ||
SysPaths []string `json:"syspath" bson:"syspath" valid:"-"` | ||
Configs sync.Map `json:"configs" bson:"configs" valid:"-"` | ||
} | ||
|
||
type TraceInfoV2 struct { | ||
|
@@ -82,33 +94,42 @@ type RecordMetaV2 struct { | |
} | ||
|
||
type ScriptTelemetryRecordV2 struct { | ||
RecordMeta RecordMetaV2 `json:"meta" bson:"meta"` | ||
TimeStamp string `json:"timestamp" bson:"timestamp" valid:"rfc3339~Invalid timestamp"` | ||
UserName string `json:"username" bson:"username" valid:"-"` | ||
HostUserName string `json:"host_user" bson:"host_user" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
SessionId string `json:"sessionid" bson:"sessionid" valid:"uuidv4~Invalid session id"` | ||
PyRevitVersion string `json:"pyrevit" bson:"pyrevit" valid:"-"` | ||
Clone string `json:"clone" bson:"clone" valid:"-"` | ||
IsDebugMode bool `json:"debug" bson:"debug"` | ||
IsConfigMode bool `json:"config" bson:"config"` | ||
IsExecFromGUI bool `json:"from_gui" bson:"from_gui"` | ||
ExecId string `json:"exec_id" bson:"exec_id" valid:"-"` | ||
ExecTimeStamp string `json:"exec_timestamp" bson:"exec_timestamp" valid:"-"` | ||
CommandName string `json:"commandname" bson:"commandname" valid:"-"` | ||
CommandUniqueName string `json:"commanduniquename" bson:"commanduniquename" valid:"-"` | ||
BundleName string `json:"commandbundle" bson:"commandbundle" valid:"-"` | ||
ExtensionName string `json:"commandextension" bson:"commandextension" valid:"-"` | ||
DocumentName string `json:"docname" bson:"docname" valid:"-"` | ||
DocumentPath string `json:"docpath" bson:"docpath" valid:"-"` | ||
ResultCode int `json:"resultcode" bson:"resultcode" valid:"numeric~Invalid result code"` | ||
CommandResults map[string]interface{} `json:"commandresults" bson:"commandresults" valid:"-"` | ||
ScriptPath string `json:"scriptpath" bson:"scriptpath" valid:"-"` | ||
TraceInfo TraceInfoV2 `json:"trace" bson:"trace"` | ||
RecordMeta RecordMetaV2 `json:"meta" bson:"meta"` | ||
TimeStamp string `json:"timestamp" bson:"timestamp" valid:"rfc3339~Invalid timestamp"` | ||
UserName string `json:"username" bson:"username" valid:"-"` | ||
HostUserName string `json:"host_user" bson:"host_user" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
SessionId string `json:"sessionid" bson:"sessionid" valid:"uuidv4~Invalid session id"` | ||
PyRevitVersion string `json:"pyrevit" bson:"pyrevit" valid:"-"` | ||
Clone string `json:"clone" bson:"clone" valid:"-"` | ||
IsDebugMode bool `json:"debug" bson:"debug"` | ||
IsConfigMode bool `json:"config" bson:"config"` | ||
IsExecFromGUI bool `json:"from_gui" bson:"from_gui"` | ||
ExecId string `json:"exec_id" bson:"exec_id" valid:"-"` | ||
ExecTimeStamp string `json:"exec_timestamp" bson:"exec_timestamp" valid:"-"` | ||
CommandName string `json:"commandname" bson:"commandname" valid:"-"` | ||
CommandUniqueName string `json:"commanduniquename" bson:"commanduniquename" valid:"-"` | ||
BundleName string `json:"commandbundle" bson:"commandbundle" valid:"-"` | ||
ExtensionName string `json:"commandextension" bson:"commandextension" valid:"-"` | ||
DocumentName string `json:"docname" bson:"docname" valid:"-"` | ||
DocumentPath string `json:"docpath" bson:"docpath" valid:"-"` | ||
ResultCode int `json:"resultcode" bson:"resultcode" valid:"numeric~Invalid result code"` | ||
CommandResults sync.Map `json:"commandresults" bson:"commandresults" valid:"-"` | ||
ScriptPath string `json:"scriptpath" bson:"scriptpath" valid:"-"` | ||
TraceInfo TraceInfoV2 `json:"trace" bson:"trace"` | ||
} | ||
|
||
func (logrec ScriptTelemetryRecordV2) PrintRecordInfo(logger *cli.Logger, message string) { | ||
// Convert sync.Map to regular map for printing | ||
results := make(map[string]interface{}) | ||
logrec.CommandResults.Range(func(key, value interface{}) bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a potential type safety issue here. The original code has explicit type assertions when converting to a regular map, but the current implementation might assign different types to the results map. The value type should be explicitly checked like it is in the ScriptTelemetryRecordV1.PrintRecordInfo method (lines 46-54). Consider adding proper type assertion for the value parameter similar to: logrec.CommandResults.Range(func(key, value interface{}) bool {
if k, ok := key.(string); ok {
if v, ok := value.(interface{}); ok {
results[k] = v
}
}
return true
}) |
||
if k, ok := key.(string); ok { | ||
results[k] = value | ||
} | ||
return true | ||
}) | ||
|
||
logger.Print(fmt.Sprintf( | ||
"%s %s %q %s:%s (%s) [%s.%s] code=%d info=%v", | ||
message, | ||
|
@@ -120,7 +141,7 @@ func (logrec ScriptTelemetryRecordV2) PrintRecordInfo(logger *cli.Logger, messag | |
logrec.ExtensionName, | ||
logrec.CommandName, | ||
logrec.ResultCode, | ||
logrec.CommandResults, | ||
results, | ||
)) | ||
} | ||
|
||
|
@@ -158,15 +179,15 @@ func (logrec ScriptTelemetryRecordV2) Validate() error { | |
|
||
// introduced with api v2 | ||
type EventTelemetryRecordV2 struct { | ||
RecordMeta RecordMetaV2 `json:"meta" bson:"meta"` | ||
TimeStamp string `json:"timestamp" bson:"timestamp" valid:"rfc3339~Invalid timestamp"` | ||
HandlerId string `json:"handler_id" bson:"handler_id" valid:"-"` | ||
EventType string `json:"type" bson:"type" valid:"-"` | ||
EventArgs map[string]interface{} `json:"args" bson:"args" valid:"-"` | ||
UserName string `json:"username" bson:"username" valid:"-"` | ||
HostUserName string `json:"host_user" bson:"host_user" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
RecordMeta RecordMetaV2 `json:"meta" bson:"meta"` | ||
TimeStamp string `json:"timestamp" bson:"timestamp" valid:"rfc3339~Invalid timestamp"` | ||
HandlerId string `json:"handler_id" bson:"handler_id" valid:"-"` | ||
EventType string `json:"type" bson:"type" valid:"-"` | ||
EventArgs sync.Map `json:"args" bson:"args" valid:"-"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The EventTelemetryRecordV2 PrintRecordInfo method (line 204) doesn't handle the EventArgs sync.Map conversion before printing. Add code similar to what's done in ScriptTelemetryRecordV2.PrintRecordInfo to convert the sync.Map to a regular map before printing, otherwise the logging output may be incorrect or misleading. |
||
UserName string `json:"username" bson:"username" valid:"-"` | ||
HostUserName string `json:"host_user" bson:"host_user" valid:"-"` | ||
RevitVersion string `json:"revit" bson:"revit" valid:"numeric~Invalid revit version"` | ||
RevitBuild string `json:"revitbuild" bson:"revitbuild" valid:"matches(\\d{8}_\\d{4}\\(x\\d{2}\\))~Invalid revit build number"` | ||
|
||
// general | ||
Cancellable bool `json:"cancellable" bson:"cancellable"` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"sync" | ||
|
||
"pyrevittelemetryserver/cli" | ||
"pyrevittelemetryserver/persistence" | ||
|
@@ -37,7 +38,9 @@ func RouteEvents(router *mux.Router, opts *cli.Options, dbConn persistence.Conne | |
// https://stackoverflow.com/a/26212073 | ||
router.HandleFunc("/api/v2/events/", func(w http.ResponseWriter, r *http.Request) { | ||
// parse given json data into a new record | ||
logrec := persistence.EventTelemetryRecordV2{} | ||
logrec := persistence.EventTelemetryRecordV2{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The sync.Map initialization is correct, but there should be proper error handling for JSON deserialization of sync.Map fields. If the incoming JSON contains data intended for EventArgs, the current code might silently ignore it since the unmarshalled data may not properly map to sync.Map. Consider adding custom JSON unmarshalling for this struct or validate that EventArgs is correctly populated after decoding. |
||
EventArgs: sync.Map{}, | ||
} | ||
decodeErr := json.NewDecoder(r.Body).Decode(&logrec) | ||
if decodeErr != nil { | ||
logger.Debug(decodeErr) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using sync.Map with JSON marshaling/unmarshaling may cause issues with serialization. The default Go JSON encoder doesn't have built-in support for sync.Map. You'll need to implement custom MarshalJSON and UnmarshalJSON methods for each struct using sync.Map to properly serialize and deserialize the data. Without this, data might be lost or improperly stored during JSON operations.