github.com/Laplace-Game-Development/Laplace-Entangled-Environment@v0.0.3/internal/policy/policy.go (about) 1 // Policy is the type definitions and decoupling pattern for route and data. 2 // routes listen and inquire for commands to send to data 3 // data then sends back the responses for routes to use 4 // the format of communication between these modules is described here. 5 // It helps to define the structures used in requests and responses so 6 // the functions can be used internall (like with schedule) 7 package policy 8 9 import ( 10 "encoding/json" 11 "reflect" 12 "time" 13 ) 14 15 //// Configurables 16 17 // The amount of time a game can go without an action for. If nothing occurs 18 // for x time on a game then it should be deleted 19 const StaleGameDuration time.Duration = time.Duration(time.Minute * 5) 20 21 // UserID For Request Made From the Server rather than 22 // from a user. Useful for papertrails. 23 const SuperUserID string = "-1" 24 25 /////////////////////////////////////////////////////////////////////////////////////////////////// 26 //// 27 //// Request Definitions 28 //// 29 /////////////////////////////////////////////////////////////////////////////////////////////////// 30 31 //// Incomming Request Definitions 32 33 // Establish which endpoint/action the request is for 34 // 35 // Typically the 2nd and 3rd bytes of a TCP Request 36 type ClientCmd int64 37 38 // TCP Request Attachment 39 // JSON or ASN1 Attachment for Authentication and Regulation 40 // 41 // Parsed Into Request Header 42 type RequestAttachment struct { 43 // Who the Command is From 44 UserID string 45 46 // Request Signature for Authentication 47 Sig string 48 } 49 50 //// Private Request Definitions For Parsing 51 52 // The Request Header represents the metadata for requests that 53 // all requests need. This represents the selected endpoint and 54 // authentication data needed for some commands (these values) 55 // may be empty for public commands. 56 type RequestHeader struct { 57 // Command To Be Handled (i.e. Sent in TCP Prefix) 58 Command ClientCmd 59 60 // Who the Command is From 61 UserID string 62 63 // Request Signature for Authenticated Requests 64 Sig string 65 } 66 67 // The Request Body Represents the data for the command. Since 68 // each command has different arguments (and using byte slices 69 // can only go so far) we use factory functions to gather all 70 // the required data. (I use Factories here but they are more 71 // defered Transformation/Map Functions). 72 type RequestBodyFactories struct { 73 // Interface Parameter should be a pointer 74 ParseFactory func(ptr interface{}) error 75 76 SigVerify func(userID string, userSig string) error 77 } 78 79 // Required Fields for any connection 80 // see calculateResponse 81 // or see switchOnCommand 82 // 83 // The structure is wrapped for easy of returning from a 84 // constructing function. 85 type InternalUserRequest struct { 86 Header RequestHeader 87 BodyFactories RequestBodyFactories 88 IsSecureConnection bool 89 } 90 91 /////////////////////////////////////////////////////////////////////////////////////////////////// 92 //// 93 //// Response Definitions 94 //// 95 /////////////////////////////////////////////////////////////////////////////////////////////////// 96 97 // Abstracted Response Information from a Command 98 // 99 // The Command Response is a structure that with certain 100 // values filled is communicable back to the route/listner 101 // module functions to then transform back into 102 // packets/bytes/http whatever. 103 // 104 // While you are perfectly allowed to define these on your own 105 // there are premade functions below for common responses. 106 type CommandResponse struct { 107 // Data to be Digested 108 Data interface{} 109 110 // Digesting method for Data Field 111 Digest func(interface{}) ([]byte, error) 112 113 // Raw Data to be written without Digest 114 Raw []byte 115 116 // Response with Data + Digest or use Raw Field 117 UseRaw bool 118 119 // Server Error to be Logged, rejecting request. 120 ServerError error 121 } 122 123 // Data Interface for JSON parsing. Isn't really used 124 // to communicate within the Application, but makes 125 // creating the Json with golangs Json package easier. 126 // 127 // The Struct has to be public so the package can parse, 128 // but refrain from using in parameters/return types etc. 129 type SuccessfulData struct { 130 Successful bool 131 Err string 132 } 133 134 /////////////////////////////////////////////////////////////////////////////////////////////////// 135 //// 136 //// Command Switch 137 //// 138 /////////////////////////////////////////////////////////////////////////////////////////////////// 139 140 /* Commands will be 2 byte codes */ 141 142 // Enum Consisting of all the ClientCommands. 143 // The comments also map what each command should map to in TCP 144 const ( 145 CmdError ClientCmd = iota 146 // //===================== 147 // Empty Command 148 // //===================== 149 CmdEmpty // //0000_0000_0000_0000 150 // //===================== 151 // TLS Commands 152 // //===================== 153 CmdRegister // //0000_0000_0000_0001 154 CmdLogin // //0000_0000_0000_0010 155 // //===================== 156 // Through Commands (To Third Party) 157 // //===================== 158 CmdAction // //0000_0000_0001_0000 159 CmdObserve // //0000_0000_0001_0001 160 // //===================== 161 // User Management Commands 162 // //===================== 163 CmdGetUser // //0000_0001_0000_0000 164 // //===================== 165 // Game Management Commands 166 // //===================== 167 CmdGameCreate // //0000_0010_0000_0000 168 CmdGameJoin // //0000_0010_0000_0001 169 CmdGameLeave // //0000_0010_0000_0010 170 CmdGameDelete // //0000_0010_0000_0011 171 // //===================== 172 ) 173 174 /////////////////////////////////////////////////////////////////////////////////////////////////// 175 //// 176 //// Utility Response Functions 177 //// 178 /////////////////////////////////////////////////////////////////////////////////////////////////// 179 180 // Reject the request and tell the user to come back tomorrow... 181 // there are server issues today 182 // 183 // err : Error received from doing something 184 // (something that contains a string to be logged) 185 func RespWithError(err error) CommandResponse { 186 return CommandResponse{ServerError: err} 187 } 188 189 // Reject the request by telling the user what they did wrong... 190 // "Sorry Hacker but our server doesn't work like that" 191 // ... 192 // Maybe something a bit nicer... 193 // 194 // err : Error received from doing something 195 // (something that contains a string to be sent to the user) 196 func UnSuccessfulResponseError(err error) CommandResponse { 197 return CommandResponse{ 198 Data: SuccessfulData{false, err.Error()}, 199 Digest: json.Marshal, 200 } 201 } 202 203 // Reject the request by telling the user what they did wrong... 204 // "Sorry Hacker but our server doesn't work like that" 205 // ... 206 // Maybe something a bit nicer... 207 // 208 // err : a string to be sent to the user 209 func UnSuccessfulResponse(err string) CommandResponse { 210 return CommandResponse{ 211 Data: SuccessfulData{false, err}, 212 Digest: json.Marshal, 213 } 214 } 215 216 // Accept the request and respond with the mystical "Successful: true" 217 func SuccessfulResponse() CommandResponse { 218 return CommandResponse{ 219 Data: SuccessfulData{Successful: true}, 220 Digest: json.Marshal, 221 } 222 } 223 224 // Send bytes back to the user 225 // 226 // msg :: byte slice of what you want to be sent back 227 func RawSuccessfulResponseBytes(msg *[]byte) CommandResponse { 228 return CommandResponse{ 229 UseRaw: true, 230 Raw: *msg, 231 } 232 } 233 234 // Send bytes back to the user 235 // 236 // msg :: string of what you want to be sent back 237 // 238 // WARNING: msg should not be a constant string! 239 func RawSuccessfulResponse(msg string) CommandResponse { 240 return CommandResponse{ 241 UseRaw: true, 242 Raw: []byte(msg), 243 } 244 } 245 246 // Send bytes back to the user 247 // 248 // msg :: string of what you want to be sent back 249 // 250 // WARNING: msg should not be a constant string! 251 // No different from RawSuccessfulResponse, but we may 252 // change that in the future. 253 func RawUnsuccessfulResponse(err string) CommandResponse { 254 return CommandResponse{ 255 UseRaw: true, 256 Raw: []byte(err), 257 } 258 } 259 260 /////////////////////////////////////////////////////////////////////////////////////////////////// 261 //// 262 //// Internal Request Functions 263 //// 264 /////////////////////////////////////////////////////////////////////////////////////////////////// 265 266 // Function to construct internal request with from a "Super User". Useful for 267 // using endpoints with a specific papertrail. Super Users have a lot 268 // more privaledges in checks than other users, but they can do this because 269 // they skip the parsing steps. SigVerify automatically returns a nil error. 270 // This could(/should) never happen from outside the system. 271 // 272 // isTask :: true if task is making the request and false otherwise 273 // (old parameter and not necessary) 274 // cmd :: Selected Endpoint to be requested 275 // args :: struct to use for args for endpoint 276 // returns -> InternalUserRequest struct for making the request. 277 func RequestWithSuperUser(isTask bool, cmd ClientCmd, args interface{}) (InternalUserRequest, error) { 278 // shortcut bodyfactory using reflection 279 bodyFactories := RequestBodyFactories{ 280 ParseFactory: func(ptr interface{}) error { 281 ptrValue := reflect.ValueOf(ptr) 282 argsVal := reflect.ValueOf(args) 283 ptrValue.Elem().Set(argsVal) 284 return nil 285 }, 286 SigVerify: func(userID string, userSig string) error { 287 return nil 288 }, 289 } 290 291 // Body Start is only used in main.go and is not necessary for a manual request command 292 header := RequestHeader{Command: cmd, UserID: SuperUserID} 293 294 return InternalUserRequest{Header: header, BodyFactories: bodyFactories, IsSecureConnection: true}, nil 295 } 296 297 // Function to construct internal request with from a given user. 298 // Used for unit testing 299 // 300 // userID :: String User ID for Database 301 // isTask :: true if task is making the request and false otherwise 302 // (old parameter and not necessary) 303 // cmd :: Selected Endpoint to be requested 304 // args :: struct to use for args for endpoint 305 // returns -> InternalUserRequest struct for making the request. 306 func RequestWithUserForTesting(userID string, isTask bool, cmd ClientCmd, args interface{}) (InternalUserRequest, error) { 307 // shortcut bodyfactory using reflection 308 bodyFactories := RequestBodyFactories{ 309 ParseFactory: func(ptr interface{}) error { 310 if args == nil { 311 return nil 312 } 313 314 ptrValue := reflect.ValueOf(ptr) 315 argsVal := reflect.ValueOf(args) 316 ptrValue.Elem().Set(argsVal) 317 return nil 318 }, 319 SigVerify: func(userID string, userSig string) error { 320 return nil 321 }, 322 } 323 324 // Body Start is only used in main.go and is not necessary for a manual request command 325 header := RequestHeader{Command: cmd, UserID: userID} 326 327 return InternalUserRequest{Header: header, BodyFactories: bodyFactories, IsSecureConnection: true}, nil 328 }