Skip to content

SQL Features

Dominique Debergue edited this page Dec 29, 2018 · 30 revisions

Gopher's SQL features will enable you to use all the database package's functionalities:

  • Account creation
  • Logging users in with their account name, password, and any custom checks
  • Auto-login with generated secure keys
  • Custom account information
  • Friending

If you do not wish to use the SQL features, you will need to implement your own mechanisms for the features listed above.

Set-Up

Before you can use the SQL features, you will need a MySQL or similar database installed and running on your system. You can acquire the latest version of MySQL at: www.mysql.com

Once you've installed and ran SQL database, you will need to make a new user that Gopher will use to log into the database with. Make sure the user has the following privileges granted: SELECT, INSERT, UPDATE, DELETE, EXECUTE, CREATE, ALTER, REFERENCES, and DROP. You also will need to know the following information about your database for later: IP address, port number, and network protocol. If you haven't done so already, make a database where Gopher can create it's tables.

Now, with all this information you can set the required entries in gopher.ServerSettings to enable the SQL features:

package main

import (
    "github.com/hewiefreeman/GopherGameServer"
)

func main() {
    settings := gopher.ServerSettings{
        ServerName: "!s!",
        MaxConnections: 10000,
        
        HostName: "http://example.com",
        HostAlias: "http://www.example.com",
        IP: "192.168.1.1",
        Port: 8080,
        
        OriginOnly: true,

        // Using a TLS/SSL connection is highly recommended when using SQL features!
        TLS: true,
        CertFile: "C:/path/to/certificate.pem",
        PrivKeyFile: "C:/path/to/privkey.pem",
        
        // Enable SQL features
        SqlIP: "localhost",
        SqlPort: 3306,
        SqlProtocol: "tcp",
        SqlUser: "userName",
        SqlPassword: "password",
        SqlDatabase: "databaseName",
    }
    
    //
    gopher.Start(&settings)
}

Warning: As stated in the above comment, it is highly recommended to use an encrypted TLS/SSL connection when using the SQL features, or sensitive account information can be compromised with network "snooping" (AKA "sniffing"). If you are not using an encrypted connection and do not know where to start, you can start by acquiring a free SSL certificate from Let's Encrypt and reading through their (or your web/cloud hosting provider's) documentation and help sections.

Authenticating Clients

Gopher server and the client APIs will take care of most of the work from here. With the above entries in ServerSettings set, Gopher will now use the database to log clients in, enable clients to sign-up, and enable friending. A client will be required to sign-up before logging in unless they log in as a guest. It is highly recommended to not use the users.Login() function, and now rely on the client API to send built-in commands, and let Gopher take care of the rest.

Check out your client API documentation to learn how to send the built-in (sign up, log in, log out, etc) commands from there.

Custom Account Info

You can attach custom info to an account with a database.AccountInfoColumn. An AccountInfoColumn registers a new column on the database in the table where User accounts are stored. You can make a new AccountInfoColumn with the database.NewAccountInfoColumn() method. This (like most set-up functions) can only be called before starting the server:

func main() {
    // Enable required settings
    settings := gopher.ServerSettings{
        ServerName: "!s!",
        // ...
    }
    
    // Register the new AccountInfoColumn "email"
    emailErr := database.NewAccountInfoColumn("email", database.DataTypeVarChar, 255, 0, true, true, false)
    if emailErr != nil {
        Println(emailErr)
        return
    }
    
    //
    gopher.Start(&settings)
}

The NewAccountInfoColumn() method's parameters are shown here as in the documentation:

func NewAccountInfoColumn(name string, dataType int, maxSize int, precision int, notNull bool, unique bool, encrypt bool) error

name is the name of the new info column, dataType should be one of the SQL data types defined in the documentation, maxSize is the maximum size of any data inserted to the column, precision is the decimal precision for numeric types, notNull prevents any new entries in that column from being null, unique makes sure no two of the same values are stored in that column, and encrypt will encrypt the column data before inserting.

The first time booting after registering a new AccountInfoColumn, Gopher will add a column of that name, data type, max size, etc to the User accounts table. With a custom AccountInfoColumn registered, we can continue on to customize the authentication features.

Customize Authentication Features

There are many ways to customize the authentication features, so I think it's most logical to list them in order of relevance:

Sign-Up

Using the "email" AccountInfoColumn we registered before, we can make it required for a client to supply an email as well as an account name and password when signing up by using the 'database.SetCustomSignupRequirements()' method:

func main() {
    // Enable required settings
    settings := gopher.ServerSettings{
        ServerName: "!s!",
        // ...
    }
    
    // Register the new AccountInfoColumn "email"
    database.NewAccountInfoColumn("email", database.DataTypeVarChar, 255, 0, true, true, false)
    
    // Require the "email" AccountInfoColumn when signing up
    custSignupErr := database.SetCustomSignupRequirements([]string{"email"})
    if custSignupErr != nil {
        Println(custSignupErr)
        return
    }
    
    //
    gopher.Start(&settings)
}

Note: You can assign multiple custom AccountInfoColumns to be requirements by adding their names to the []string passed to SetCustomSignupRequirements(), or any other custom requirements setter method.

Now, we can capture the input from the client API by setting the sign up callback with the gopher.SetSignupCallback() method and, for instance, send an email to the provided address:

func main() {
    // Enable required settings
    settings := gopher.ServerSettings{
        ServerName: "!s!",
        // ...
    }
    
    // Register the new AccountInfoColumn "email"
    database.NewAccountInfoColumn("email", database.DataTypeVarChar, 255, 0, true, true, false)
    
    // Require the "email" AccountInfoColumn when signing up
    database.SetCustomSignupRequirements([]string{"email"})

    // Set sign up callback
    cbErr := SetSignupCallback(clientSignUp)
    if cbErr != nil {
        fmt.Println(cbErr)
        return
    }
    
    //
    gopher.Start(&settings)
}

func clientSignUp(userName string, clientColumns map[string]interface{}) bool {
    if email, ok = clientColumns["email"].(string); !ok {
        // Check if valid address format and send an email...
        // You should return false if address is not email format
        
    } else {
        // email is not a string
        return false
        
    }
    
    // Allow sign up
    return true
}

This callback takes two parameters: userName (string), and clientColumns (map[string]interface{}). userName is the account/User name the client wants, and the clientColumns are the client's input for your defined (and in this case required) AccountInfoColumns.

The sign up callback runs before a client can sign up, so you can either have your callback return true to allow the sign up, or false to prevent it. This is useful for verifying correct and/or formatted input.

Note: You can still pass clientColumns from the client API without using SetCustomSignupRequirements() or any other custom database action requirement setters. The difference is that the requirement setters will send an error back to the client if the clientColumns do not match the required ones. For example, if your custom requirements for changing a password include email and securityAnswer, the clientColumns sent from the client API for a password change request must only contain email and securityAnswer. Otherwise, an error will be sent back to the client API, and the sign up will be prevented.

Logging In

If you notice there is lacking information, missing features, or bad explanations, please open an issue. All requests are acceptable and will be taken into consideration.

Clone this wiki locally