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  }