github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/binding/db.go (about) 1 package binding 2 3 import ( 4 "encoding/json" 5 "sync" 6 "unsafe" 7 ) 8 9 // DB is our database of method bindings 10 type DB struct { 11 // map[packagename] -> map[structname] -> map[methodname]*method 12 store map[string]map[string]map[string]*BoundMethod 13 14 // This uses fully qualified method names as a shortcut for store traversal. 15 // It used for performance gains at runtime 16 methodMap map[string]*BoundMethod 17 18 // This uses ids to reference bound methods at runtime 19 obfuscatedMethodArray []*ObfuscatedMethod 20 21 // Lock to ensure sync access to the data 22 lock sync.RWMutex 23 } 24 25 type ObfuscatedMethod struct { 26 method *BoundMethod 27 methodName string 28 } 29 30 func newDB() *DB { 31 return &DB{ 32 store: make(map[string]map[string]map[string]*BoundMethod), 33 methodMap: make(map[string]*BoundMethod), 34 obfuscatedMethodArray: []*ObfuscatedMethod{}, 35 } 36 } 37 38 // GetMethodFromStore returns the method for the given package/struct/method names 39 // nil is returned if any one of those does not exist 40 func (d *DB) GetMethodFromStore(packageName string, structName string, methodName string) *BoundMethod { 41 // Lock the db whilst processing and unlock on return 42 d.lock.RLock() 43 defer d.lock.RUnlock() 44 45 structMap, exists := d.store[packageName] 46 if !exists { 47 return nil 48 } 49 methodMap, exists := structMap[structName] 50 if !exists { 51 return nil 52 } 53 return methodMap[methodName] 54 } 55 56 // GetMethod returns the method for the given qualified method name 57 // qualifiedMethodName is "packagename.structname.methodname" 58 func (d *DB) GetMethod(qualifiedMethodName string) *BoundMethod { 59 // Lock the db whilst processing and unlock on return 60 d.lock.RLock() 61 defer d.lock.RUnlock() 62 63 return d.methodMap[qualifiedMethodName] 64 } 65 66 // GetObfuscatedMethod returns the method for the given ID 67 func (d *DB) GetObfuscatedMethod(id int) *BoundMethod { 68 // Lock the db whilst processing and unlock on return 69 d.lock.RLock() 70 defer d.lock.RUnlock() 71 72 if len(d.obfuscatedMethodArray) <= id { 73 return nil 74 } 75 76 return d.obfuscatedMethodArray[id].method 77 } 78 79 // AddMethod adds the given method definition to the db using the given qualified path: packageName.structName.methodName 80 func (d *DB) AddMethod(packageName string, structName string, methodName string, methodDefinition *BoundMethod) { 81 // Lock the db whilst processing and unlock on return 82 d.lock.Lock() 83 defer d.lock.Unlock() 84 85 // Get the map associated with the package name 86 structMap, exists := d.store[packageName] 87 if !exists { 88 // Create a new map for this packagename 89 d.store[packageName] = make(map[string]map[string]*BoundMethod) 90 structMap = d.store[packageName] 91 } 92 93 // Get the map associated with the struct name 94 methodMap, exists := structMap[structName] 95 if !exists { 96 // Create a new map for this packagename 97 structMap[structName] = make(map[string]*BoundMethod) 98 methodMap = structMap[structName] 99 } 100 101 // Store the method definition 102 methodMap[methodName] = methodDefinition 103 104 // Store in the methodMap 105 key := packageName + "." + structName + "." + methodName 106 d.methodMap[key] = methodDefinition 107 d.obfuscatedMethodArray = append(d.obfuscatedMethodArray, &ObfuscatedMethod{method: methodDefinition, methodName: key}) 108 } 109 110 // ToJSON converts the method map to JSON 111 func (d *DB) ToJSON() (string, error) { 112 // Lock the db whilst processing and unlock on return 113 d.lock.RLock() 114 defer d.lock.RUnlock() 115 116 d.UpdateObfuscatedCallMap() 117 118 bytes, err := json.Marshal(&d.store) 119 120 // Return zero copy string as this string will be read only 121 result := *(*string)(unsafe.Pointer(&bytes)) 122 return result, err 123 } 124 125 // UpdateObfuscatedCallMap sets up the secure call mappings 126 func (d *DB) UpdateObfuscatedCallMap() map[string]int { 127 mappings := make(map[string]int) 128 129 for id, k := range d.obfuscatedMethodArray { 130 mappings[k.methodName] = id 131 } 132 133 return mappings 134 }