mirror of
https://github.com/mattermost/focalboard.git
synced 2025-01-23 18:34:02 +02:00
Add API client, integration tests structure and server lifecycle changes
This commit is contained in:
parent
3c68a97451
commit
1111bd337a
@ -1,13 +1,13 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
||||||
@ -17,7 +17,7 @@ func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
|||||||
fileExtension = ".jpg"
|
fileExtension = ".jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
createdFilename := fmt.Sprintf(`%s%s`, createGUID(), fileExtension)
|
createdFilename := fmt.Sprintf(`%s%s`, utils.CreateGUID(), fileExtension)
|
||||||
|
|
||||||
_, appErr := a.filesBackend.WriteFile(reader, createdFilename)
|
_, appErr := a.filesBackend.WriteFile(reader, createdFilename)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
@ -32,15 +32,3 @@ func (a *App) GetFilePath(filename string) string {
|
|||||||
|
|
||||||
return filepath.Join(folderPath, filename)
|
return filepath.Join(folderPath, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGUID returns a random GUID.
|
|
||||||
func createGUID() string {
|
|
||||||
b := make([]byte, 16)
|
|
||||||
_, err := rand.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
|
||||||
|
|
||||||
return uuid
|
|
||||||
}
|
|
||||||
|
186
server/client/client.go
Normal file
186
server/client/client.go
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
API_URL_SUFFIX = "/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
StatusCode int
|
||||||
|
Error error
|
||||||
|
Header http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildResponse(r *http.Response) *Response {
|
||||||
|
return &Response{
|
||||||
|
StatusCode: r.StatusCode,
|
||||||
|
Header: r.Header,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildErrorResponse(r *http.Response, err error) *Response {
|
||||||
|
statusCode := 0
|
||||||
|
header := make(http.Header)
|
||||||
|
if r != nil {
|
||||||
|
statusCode = r.StatusCode
|
||||||
|
header = r.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Error: err,
|
||||||
|
Header: header,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeBody(r *http.Response) {
|
||||||
|
if r.Body != nil {
|
||||||
|
_, _ = io.Copy(ioutil.Discard, r.Body)
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toJSON(v interface{}) string {
|
||||||
|
b, _ := json.Marshal(v)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
Url string
|
||||||
|
ApiUrl string
|
||||||
|
HttpClient *http.Client
|
||||||
|
HttpHeader map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(url string) *Client {
|
||||||
|
url = strings.TrimRight(url, "/")
|
||||||
|
return &Client{url, url + API_URL_SUFFIX, &http.Client{}, map[string]string{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoApiGet(url string, etag string) (*http.Response, error) {
|
||||||
|
return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoApiPost(url string, data string) (*http.Response, error) {
|
||||||
|
return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doApiPostBytes(url string, data []byte) (*http.Response, error) {
|
||||||
|
return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoApiPut(url string, data string) (*http.Response, error) {
|
||||||
|
return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doApiPutBytes(url string, data []byte) (*http.Response, error) {
|
||||||
|
return c.doApiRequestBytes(http.MethodPut, c.ApiUrl+url, data, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoApiDelete(url string) (*http.Response, error) {
|
||||||
|
return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DoApiRequest(method, url, data, etag string) (*http.Response, error) {
|
||||||
|
return c.doApiRequestReader(method, url, strings.NewReader(data), etag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, error) {
|
||||||
|
return c.doApiRequestReader(method, url, bytes.NewReader(data), etag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) doApiRequestReader(method, url string, data io.Reader, etag string) (*http.Response, error) {
|
||||||
|
rq, err := http.NewRequest(method, url, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.HttpHeader != nil && len(c.HttpHeader) > 0 {
|
||||||
|
for k, v := range c.HttpHeader {
|
||||||
|
rq.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rp, err := c.HttpClient.Do(rq)
|
||||||
|
if err != nil || rp == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if rp.StatusCode == 304 {
|
||||||
|
return rp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if rp.StatusCode >= 300 {
|
||||||
|
defer closeBody(rp)
|
||||||
|
b, err := ioutil.ReadAll(rp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return rp, fmt.Errorf("error when parsing response with code %d: %w", rp.StatusCode, err)
|
||||||
|
}
|
||||||
|
return rp, fmt.Errorf(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return rp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetBlocksRoute() string {
|
||||||
|
return "/blocks"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetBlockRoute(id string) string {
|
||||||
|
return fmt.Sprintf("%s/%s", c.GetBlocksRoute(), id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSubtreeRoute(id string) string {
|
||||||
|
return fmt.Sprintf("%s/subtree", c.GetBlockRoute(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetBlocks() ([]model.Block, *Response) {
|
||||||
|
r, err := c.DoApiGet(c.GetBlocksRoute(), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
return model.BlocksFromJSON(r.Body), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) InsertBlocks(blocks []model.Block) (bool, *Response) {
|
||||||
|
r, err := c.DoApiPost(c.GetBlocksRoute(), toJSON(blocks))
|
||||||
|
if err != nil {
|
||||||
|
return false, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
return true, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteBlock(blockID string) (bool, *Response) {
|
||||||
|
r, err := c.DoApiDelete(c.GetBlockRoute(blockID))
|
||||||
|
if err != nil {
|
||||||
|
return false, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
return true, BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetSubtree(blockID string) ([]model.Block, *Response) {
|
||||||
|
r, err := c.DoApiGet(c.GetSubtreeRoute(blockID), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
return model.BlocksFromJSON(r.Body), BuildResponse(r)
|
||||||
|
}
|
218
server/integrationtests/blocks_test.go
Normal file
218
server/integrationtests/blocks_test.go
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package integrationtests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/model"
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/utils"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetBlocks(t *testing.T) {
|
||||||
|
th := SetupTestHelper().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
blockID1 := utils.CreateGUID()
|
||||||
|
blockID2 := utils.CreateGUID()
|
||||||
|
newBlocks := []model.Block{
|
||||||
|
{
|
||||||
|
ID: blockID1,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: blockID2,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, resp := th.Client.InsertBlocks(newBlocks)
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 2)
|
||||||
|
|
||||||
|
blockIDs := make([]string, len(blocks))
|
||||||
|
for i, b := range blocks {
|
||||||
|
blockIDs[i] = b.ID
|
||||||
|
}
|
||||||
|
require.Contains(t, blockIDs, blockID1)
|
||||||
|
require.Contains(t, blockIDs, blockID2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostBlock(t *testing.T) {
|
||||||
|
th := SetupTestHelper().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
blockID1 := utils.CreateGUID()
|
||||||
|
blockID2 := utils.CreateGUID()
|
||||||
|
blockID3 := utils.CreateGUID()
|
||||||
|
|
||||||
|
t.Run("Create a single block", func(t *testing.T) {
|
||||||
|
block := model.Block{
|
||||||
|
ID: blockID1,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
Title: "New title",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := th.Client.InsertBlocks([]model.Block{block})
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 1)
|
||||||
|
require.Equal(t, blockID1, blocks[0].ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create a couple of blocks in the same call", func(t *testing.T) {
|
||||||
|
newBlocks := []model.Block{
|
||||||
|
{
|
||||||
|
ID: blockID2,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: blockID3,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := th.Client.InsertBlocks(newBlocks)
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 3)
|
||||||
|
|
||||||
|
blockIDs := make([]string, len(blocks))
|
||||||
|
for i, b := range blocks {
|
||||||
|
blockIDs[i] = b.ID
|
||||||
|
}
|
||||||
|
require.Contains(t, blockIDs, blockID1)
|
||||||
|
require.Contains(t, blockIDs, blockID2)
|
||||||
|
require.Contains(t, blockIDs, blockID3)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update a block", func(t *testing.T) {
|
||||||
|
block := model.Block{
|
||||||
|
ID: blockID1,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 20,
|
||||||
|
Type: "board",
|
||||||
|
Title: "Updated title",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := th.Client.InsertBlocks([]model.Block{block})
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 3)
|
||||||
|
|
||||||
|
var updatedBlock model.Block
|
||||||
|
for _, b := range blocks {
|
||||||
|
if b.ID == blockID1 {
|
||||||
|
updatedBlock = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require.NotNil(t, updatedBlock)
|
||||||
|
require.Equal(t, "Updated title", updatedBlock.Title)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteBlock(t *testing.T) {
|
||||||
|
th := SetupTestHelper().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
blockID := utils.CreateGUID()
|
||||||
|
t.Run("Create a block", func(t *testing.T) {
|
||||||
|
block := model.Block{
|
||||||
|
ID: blockID,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
Title: "New title",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := th.Client.InsertBlocks([]model.Block{block})
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 1)
|
||||||
|
require.Equal(t, blockID, blocks[0].ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete a block", func(t *testing.T) {
|
||||||
|
_, resp := th.Client.DeleteBlock(blockID)
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSubtree(t *testing.T) {
|
||||||
|
th := SetupTestHelper().InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
parentBlockID := utils.CreateGUID()
|
||||||
|
childBlockID1 := utils.CreateGUID()
|
||||||
|
childBlockID2 := utils.CreateGUID()
|
||||||
|
t.Run("Create the block structure", func(t *testing.T) {
|
||||||
|
newBlocks := []model.Block{
|
||||||
|
{
|
||||||
|
ID: parentBlockID,
|
||||||
|
CreateAt: 1,
|
||||||
|
UpdateAt: 1,
|
||||||
|
Type: "board",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: childBlockID1,
|
||||||
|
ParentID: parentBlockID,
|
||||||
|
CreateAt: 2,
|
||||||
|
UpdateAt: 2,
|
||||||
|
Type: "card",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: childBlockID2,
|
||||||
|
ParentID: parentBlockID,
|
||||||
|
CreateAt: 2,
|
||||||
|
UpdateAt: 2,
|
||||||
|
Type: "card",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := th.Client.InsertBlocks(newBlocks)
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
|
||||||
|
blocks, resp := th.Client.GetBlocks()
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 1)
|
||||||
|
require.Equal(t, parentBlockID, blocks[0].ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get subtree for parent ID", func(t *testing.T) {
|
||||||
|
blocks, resp := th.Client.GetSubtree(parentBlockID)
|
||||||
|
require.NoError(t, resp.Error)
|
||||||
|
require.Len(t, blocks, 3)
|
||||||
|
|
||||||
|
blockIDs := make([]string, len(blocks))
|
||||||
|
for i, b := range blocks {
|
||||||
|
blockIDs[i] = b.ID
|
||||||
|
}
|
||||||
|
require.Contains(t, blockIDs, parentBlockID)
|
||||||
|
require.Contains(t, blockIDs, childBlockID1)
|
||||||
|
require.Contains(t, blockIDs, childBlockID2)
|
||||||
|
})
|
||||||
|
}
|
54
server/integrationtests/clienttestlib.go
Normal file
54
server/integrationtests/clienttestlib.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package integrationtests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/client"
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/server"
|
||||||
|
"github.com/mattermost/mattermost-octo-tasks/server/services/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestHelper struct {
|
||||||
|
Server *server.Server
|
||||||
|
Client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestConfig() *config.Configuration {
|
||||||
|
return &config.Configuration{
|
||||||
|
ServerRoot: "http://localhost:8888",
|
||||||
|
Port: 8888,
|
||||||
|
DBType: "sqlite3",
|
||||||
|
DBConfigString: ":memory:",
|
||||||
|
WebPath: "./pack",
|
||||||
|
FilesPath: "./files",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupTestHelper() *TestHelper {
|
||||||
|
th := &TestHelper{}
|
||||||
|
srv, err := server.New(getTestConfig())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
th.Server = srv
|
||||||
|
th.Client = client.NewClient(srv.Config().ServerRoot)
|
||||||
|
|
||||||
|
return th
|
||||||
|
}
|
||||||
|
|
||||||
|
func (th *TestHelper) InitBasic() *TestHelper {
|
||||||
|
go func() {
|
||||||
|
if err := th.Server.Start(); err != http.ErrServerClosed {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return th
|
||||||
|
}
|
||||||
|
|
||||||
|
func (th *TestHelper) TearDown() {
|
||||||
|
err := th.Server.Shutdown()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
// Block is the basic data unit.
|
// Block is the basic data unit.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
@ -12,3 +17,9 @@ type Block struct {
|
|||||||
UpdateAt int64 `json:"updateAt"`
|
UpdateAt int64 `json:"updateAt"`
|
||||||
DeleteAt int64 `json:"deleteAt"`
|
DeleteAt int64 `json:"deleteAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BlocksFromJSON(data io.Reader) []Block {
|
||||||
|
var blocks []Block
|
||||||
|
json.NewDecoder(data).Decode(&blocks)
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
@ -135,5 +135,13 @@ func (s *Server) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Shutdown() error {
|
func (s *Server) Shutdown() error {
|
||||||
|
if err := s.webServer.Shutdown(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return s.store.Shutdown()
|
return s.store.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) Config() *config.Configuration {
|
||||||
|
return s.config
|
||||||
|
}
|
||||||
|
19
server/utils/utils.go
Normal file
19
server/utils/utils.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateGUID returns a random GUID.
|
||||||
|
func CreateGUID() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||||
|
|
||||||
|
return uuid
|
||||||
|
}
|
@ -20,6 +20,8 @@ type RoutedService interface {
|
|||||||
|
|
||||||
// Server is the structure responsible for managing our http web server.
|
// Server is the structure responsible for managing our http web server.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
http.Server
|
||||||
|
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
rootPath string
|
rootPath string
|
||||||
port int
|
port int
|
||||||
@ -31,7 +33,10 @@ func NewServer(rootPath string, port int, ssl bool) *Server {
|
|||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
|
||||||
ws := &Server{
|
ws := &Server{
|
||||||
router: r,
|
Server: http.Server{
|
||||||
|
Addr: fmt.Sprintf(`:%d`, port),
|
||||||
|
Handler: r,
|
||||||
|
},
|
||||||
rootPath: rootPath,
|
rootPath: rootPath,
|
||||||
port: port,
|
port: port,
|
||||||
ssl: ssl,
|
ssl: ssl,
|
||||||
@ -40,14 +45,18 @@ func NewServer(rootPath string, port int, ssl bool) *Server {
|
|||||||
return ws
|
return ws
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *Server) Router() *mux.Router {
|
||||||
|
return ws.Server.Handler.(*mux.Router)
|
||||||
|
}
|
||||||
|
|
||||||
// AddRoutes allows services to register themself in the webserver router and provide new endpoints.
|
// AddRoutes allows services to register themself in the webserver router and provide new endpoints.
|
||||||
func (ws *Server) AddRoutes(rs RoutedService) {
|
func (ws *Server) AddRoutes(rs RoutedService) {
|
||||||
rs.RegisterRoutes(ws.router)
|
rs.RegisterRoutes(ws.Router())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Server) registerRoutes() {
|
func (ws *Server) registerRoutes() {
|
||||||
ws.router.PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(filepath.Join(ws.rootPath, "static")))))
|
ws.Router().PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(filepath.Join(ws.rootPath, "static")))))
|
||||||
ws.router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ws.Router().PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
http.ServeFile(w, r, path.Join(ws.rootPath, "index.html"))
|
http.ServeFile(w, r, path.Join(ws.rootPath, "index.html"))
|
||||||
})
|
})
|
||||||
@ -56,14 +65,11 @@ func (ws *Server) registerRoutes() {
|
|||||||
// Start runs the web server and start listening for charsetnnections.
|
// Start runs the web server and start listening for charsetnnections.
|
||||||
func (ws *Server) Start() error {
|
func (ws *Server) Start() error {
|
||||||
ws.registerRoutes()
|
ws.registerRoutes()
|
||||||
http.Handle("/", ws.router)
|
|
||||||
|
|
||||||
urlPort := fmt.Sprintf(`:%d`, ws.port)
|
|
||||||
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
||||||
|
|
||||||
if isSSL {
|
if isSSL {
|
||||||
log.Println("https server started on ", urlPort)
|
log.Printf("https server started on :%d\n", ws.port)
|
||||||
err := http.ListenAndServeTLS(urlPort, "./cert/cert.pem", "./cert/key.pem", nil)
|
err := ws.ListenAndServeTLS("./cert/cert.pem", "./cert/key.pem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -71,8 +77,8 @@ func (ws *Server) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("http server started on ", urlPort)
|
log.Println("http server started on :%d\n", ws.port)
|
||||||
err := http.ListenAndServe(urlPort, nil)
|
err := ws.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -80,6 +86,10 @@ func (ws *Server) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *Server) Shutdown() error {
|
||||||
|
return ws.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// fileExists returns true if a file exists at the path.
|
// fileExists returns true if a file exists at the path.
|
||||||
func fileExists(path string) bool {
|
func fileExists(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user