@@ -2,6 +2,8 @@ package database
22
33import (
44 "context"
5+ "errors"
6+ "regexp"
57 "wwfc/logging"
68
79 "github.com/jackc/pgx/v4/pgxpool"
@@ -10,12 +12,13 @@ import (
1012)
1113
1214const (
13- GetHashes = `SELECT * FROM hashes`
14- InsertHash = `INSERT
15+ QueryHashes = `SELECT * FROM hashes`
16+ InsertHash = `INSERT
1517 INTO hashes (pack_id, version, hash_ntscu, hash_ntscj, hash_ntsck, hash_pal)
1618 VALUES ($1, $2, $3, $4, $5, $6)
1719 ON CONFLICT (pack_id, version)
1820 DO UPDATE SET hash_ntscu = $3, hash_ntscj = $4, hash_ntsck = $5, hash_pal = $6`
21+ DeleteHash = `DELETE FROM hashes WHERE pack_id = $1 AND version = $2`
1922)
2023
2124type Region byte
@@ -27,18 +30,56 @@ const (
2730 R_PAL
2831)
2932
33+ func IndexByRegionByte (hbr HashesByRegion , b Region ) string {
34+ switch b {
35+ case R_NTSCU :
36+ return hbr .NTSCU
37+ case R_NTSCJ :
38+ return hbr .NTSCJ
39+ case R_NTSCK :
40+ return hbr .NTSCK
41+ case R_PAL :
42+ return hbr .PAL
43+ default :
44+ return ""
45+ }
46+ }
47+
48+ type HashesByRegion struct {
49+ NTSCU string
50+ NTSCJ string
51+ NTSCK string
52+ PAL string
53+ }
54+
55+ type HashStore map [uint32 ]map [uint32 ]HashesByRegion
56+
3057var (
31- mutex = deadlock.Mutex {}
32- hashes = map [uint32 ]map [uint32 ]map [Region ]string {}
58+ mutex = deadlock.Mutex {}
59+ hashes = HashStore {}
60+ emptyRegexp * regexp.Regexp
3361)
3462
63+ // Used to flatten the 40-wide empty strings returned by the db, and to filter
64+ // whitespace potentially submitted over the api
65+ func flattenBlank (str string ) string {
66+ if emptyRegexp .MatchString (str ) {
67+ return ""
68+ }
69+
70+ return str
71+ }
72+
3573func HashInit (pool * pgxpool.Pool , ctx context.Context ) error {
3674 mutex .Lock ()
3775 defer mutex .Unlock ()
3876
39- logging .Info ("DB" , "Populating hashes from the database" )
77+ // Populate regexp once
78+ emptyRegexp = regexp .MustCompile ("^\\ s+$" )
79+
80+ logging .Info ("DATABASE" , "Populating hashes from the database" )
4081
41- rows , err := pool .Query (ctx , GetHashes )
82+ rows , err := pool .Query (ctx , QueryHashes )
4283 defer rows .Close ()
4384 if err != nil {
4485 return err
@@ -60,61 +101,87 @@ func HashInit(pool *pgxpool.Pool, ctx context.Context) error {
60101 versions , exists := hashes [packID ]
61102
62103 if ! exists {
63- temp := map [uint32 ]map [ Region ] string {}
104+ temp := map [uint32 ]HashesByRegion {}
64105 hashes [packID ] = temp
65106 versions = temp
66107 }
67108
68- regions , exists := versions [version ]
69-
70- if ! exists {
71- temp := map [Region ]string {}
72- versions [version ] = temp
73- regions = temp
109+ versions [version ] = HashesByRegion {
110+ NTSCU : flattenBlank (hashNTSCU ),
111+ NTSCJ : flattenBlank (hashNTSCJ ),
112+ NTSCK : flattenBlank (hashNTSCK ),
113+ PAL : flattenBlank (hashPAL ),
74114 }
75115
76- regions [R_NTSCU ] = hashNTSCU
77- regions [R_NTSCJ ] = hashNTSCJ
78- regions [R_NTSCK ] = hashNTSCK
79- regions [R_PAL ] = hashPAL
80-
81- logging .Info ("DB" , "Populated hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ), "\n NTSCU:" , aurora .Cyan (hashNTSCU ), "\n NTSCJ:" , aurora .Cyan (hashNTSCJ ), "\n NTSCK:" , aurora .Cyan (hashNTSCK ), "\n PAL:" , aurora .Cyan (hashPAL ))
116+ logging .Info ("DATABASE" , "Populated hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ), "\n NTSCU:" , aurora .Cyan (hashNTSCU ), "\n NTSCJ:" , aurora .Cyan (hashNTSCJ ), "\n NTSCK:" , aurora .Cyan (hashNTSCK ), "\n PAL:" , aurora .Cyan (hashPAL ))
82117 }
83118
84119 return nil
85120}
86121
122+ func GetHashes () HashStore {
123+ mutex .Lock ()
124+ defer mutex .Unlock ()
125+
126+ // Create a copy while the mutex is locked. Defer runs before return
127+ ret := hashes
128+
129+ return ret
130+ }
131+
132+ var (
133+ ErrPackIDMissing = errors .New ("The specified PackID does not exist" )
134+ ErrVersionMissing = errors .New ("The specified version does not exist" )
135+ )
136+
137+ func RemoveHash (pool * pgxpool.Pool , ctx context.Context , packID uint32 , version uint32 ) error {
138+ mutex .Lock ()
139+ defer mutex .Unlock ()
140+
141+ if versions , exists := hashes [packID ]; exists {
142+ if _ , exists := versions [version ]; exists {
143+ delete (versions , version )
144+ } else {
145+ return ErrVersionMissing
146+ }
147+ } else {
148+ return ErrPackIDMissing
149+ }
150+
151+ _ , err := pool .Exec (ctx , DeleteHash , packID , version )
152+ if err != nil {
153+ logging .Error ("DATABASE" , "Failure to remove hash for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ), "Error:" , err .Error ())
154+ } else {
155+ logging .Warn ("DATABASE" , "Removed hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ))
156+ }
157+ return err
158+ }
159+
87160func UpdateHash (pool * pgxpool.Pool , ctx context.Context , packID uint32 , version uint32 , hashNTSCU string , hashNTSCJ string , hashNTSCK string , hashPAL string ) error {
88161 mutex .Lock ()
89162 defer mutex .Unlock ()
90163
91164 versions , exists := hashes [packID ]
92165
93166 if ! exists {
94- temp := map [uint32 ]map [ Region ] string {}
167+ temp := map [uint32 ]HashesByRegion {}
95168 hashes [packID ] = temp
96169 versions = temp
97170 }
98171
99- regions , exists := versions [packID ]
100-
101- if ! exists {
102- temp := map [Region ]string {}
103- versions [packID ] = temp
104- regions = temp
172+ versions [version ] = HashesByRegion {
173+ NTSCU : flattenBlank (hashNTSCU ),
174+ NTSCJ : flattenBlank (hashNTSCJ ),
175+ NTSCK : flattenBlank (hashNTSCK ),
176+ PAL : flattenBlank (hashPAL ),
105177 }
106178
107- regions [R_NTSCU ] = hashNTSCU
108- regions [R_NTSCJ ] = hashNTSCJ
109- regions [R_NTSCK ] = hashNTSCK
110- regions [R_PAL ] = hashPAL
111-
112179 _ , err := pool .Exec (ctx , InsertHash , packID , version , hashNTSCU , hashNTSCJ , hashNTSCK , hashPAL )
113180
114181 if err != nil {
115- logging .Error ("DB " , "Failed to update hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ), "error:" , err .Error ())
182+ logging .Error ("DATABASE " , "Failed to update hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ), "error:" , err .Error ())
116183 } else {
117- logging .Info ("DB " , "Successfully updated hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ))
184+ logging .Info ("DATABASE " , "Successfully updated hashes for PackID:" , aurora .Cyan (packID ), "Version:" , aurora .Cyan (version ))
118185 }
119186
120187 return err
@@ -126,9 +193,9 @@ func ValidateHash(packID uint32, version uint32, region Region, hash string) boo
126193
127194 if versions , exists := hashes [packID ]; exists {
128195 if regions , exists := versions [version ]; exists {
129- if hash_real , exists := regions [ region ]; exists {
130- return hash_real != "" && hash_real == hash
131- }
196+ hash_real := IndexByRegionByte ( regions , region )
197+
198+ return hash_real != "" && hash_real == hash
132199 }
133200 }
134201
0 commit comments