mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-19 18:16:45 +00:00
Add basic go client
This commit is contained in:
parent
26dee89672
commit
e7672f47ed
158
client/client.go
Normal file
158
client/client.go
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/simon987/task_tracker/api"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type taskTrackerClient struct {
|
||||||
|
worker *Worker
|
||||||
|
httpClient http.Client
|
||||||
|
serverAddress string
|
||||||
|
|
||||||
|
secretB64 string
|
||||||
|
workerIdStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(serverAddress string) *taskTrackerClient {
|
||||||
|
|
||||||
|
client := new(taskTrackerClient)
|
||||||
|
client.serverAddress = serverAddress
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *taskTrackerClient) SetWorker(worker *Worker) {
|
||||||
|
c.worker = worker
|
||||||
|
c.secretB64 = base64.StdEncoding.EncodeToString(worker.Secret)
|
||||||
|
c.workerIdStr = strconv.FormatInt(worker.Id, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *taskTrackerClient) get(path string) *http.Response {
|
||||||
|
|
||||||
|
url := "http://" + c.serverAddress + path
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
|
||||||
|
if c.worker != nil {
|
||||||
|
req.Header.Add("X-Worker-Id", c.workerIdStr)
|
||||||
|
req.Header.Add("X-Secret", c.secretB64)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := c.httpClient.Do(req)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *taskTrackerClient) post(path string, x interface{}) *http.Response {
|
||||||
|
|
||||||
|
body, err := json.Marshal(x)
|
||||||
|
buf := bytes.NewBuffer(body)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "http://"+c.serverAddress+path, buf)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
if c.worker != nil {
|
||||||
|
req.Header.Add("X-Worker-Id", c.workerIdStr)
|
||||||
|
req.Header.Add("X-Secret", c.secretB64)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := c.httpClient.Do(req)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalResponse(r *http.Response, result interface{}) error {
|
||||||
|
data, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(data))
|
||||||
|
err = json.Unmarshal(data, result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) MakeWorker(alias string) (*Worker, error) {
|
||||||
|
|
||||||
|
httpResp := c.post("/worker/create", api.CreateWorkerRequest{
|
||||||
|
Alias: alias,
|
||||||
|
})
|
||||||
|
var jsonResp CreateWorkerResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
clientWorker := Worker{
|
||||||
|
Alias: jsonResp.Content.Worker.Alias,
|
||||||
|
Secret: jsonResp.Content.Worker.Secret,
|
||||||
|
Id: jsonResp.Content.Worker.Id,
|
||||||
|
}
|
||||||
|
return &clientWorker, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) FetchTask(projectId int) (*AssignTaskResponse, error) {
|
||||||
|
|
||||||
|
httpResp := c.get("/task/get/" + strconv.Itoa(projectId))
|
||||||
|
var jsonResp AssignTaskResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
//TODO: Handle rate limiting here?
|
||||||
|
|
||||||
|
return &jsonResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) ReleaseTask(req api.ReleaseTaskRequest) (*ReleaseTaskResponse, error) {
|
||||||
|
|
||||||
|
httpResp := c.post("/task/release", req)
|
||||||
|
var jsonResp ReleaseTaskResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
return &jsonResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) SubmitTask(req api.SubmitTaskRequest) (AssignTaskResponse, error) {
|
||||||
|
|
||||||
|
httpResp := c.post("/task/submit", req)
|
||||||
|
var jsonResp AssignTaskResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
//TODO: Handle rate limiting here?
|
||||||
|
|
||||||
|
return jsonResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) GetProjectSecret(projectId int) (string, error) {
|
||||||
|
|
||||||
|
httpResp := c.get("/project/secret/" + strconv.Itoa(projectId))
|
||||||
|
var jsonResp ProjectSecretResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
return jsonResp.Content.Secret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c taskTrackerClient) RequestAccess(req api.CreateWorkerAccessRequest) (api.JsonResponse, error) {
|
||||||
|
|
||||||
|
httpResp := c.post("/project/request_access", req)
|
||||||
|
var jsonResp api.JsonResponse
|
||||||
|
err := unmarshalResponse(httpResp, &jsonResp)
|
||||||
|
|
||||||
|
return jsonResp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
42
client/models.go
Normal file
42
client/models.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import "github.com/simon987/task_tracker/storage"
|
||||||
|
|
||||||
|
type Worker struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Alias string `json:"alias,omitempty"`
|
||||||
|
Secret []byte `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateWorkerResponse struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Content struct {
|
||||||
|
Worker *storage.Worker `json:"worker"`
|
||||||
|
} `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssignTaskResponse struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
RateLimitDelay float64 `json:"rate_limit_delay,omitempty"`
|
||||||
|
Content struct {
|
||||||
|
Task *storage.Task `json:"task"`
|
||||||
|
} `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReleaseTaskResponse struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Content struct {
|
||||||
|
Updated bool `json:"updated"`
|
||||||
|
} `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSecretResponse struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Content struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
} `json:"content"`
|
||||||
|
}
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/simon987/task_tracker/api"
|
"github.com/simon987/task_tracker/api"
|
||||||
|
"github.com/simon987/task_tracker/client"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ func TestAssignRateLimit(t *testing.T) {
|
|||||||
}, w)
|
}, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastResp TaskAR
|
var lastResp client.AssignTaskResponse
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
lastResp = getTaskFromProject(project, w)
|
lastResp = getTaskFromProject(project, w)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/simon987/task_tracker/api"
|
"github.com/simon987/task_tracker/api"
|
||||||
|
"github.com/simon987/task_tracker/client"
|
||||||
"github.com/simon987/task_tracker/storage"
|
"github.com/simon987/task_tracker/storage"
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
@ -925,19 +926,19 @@ func createTask(request api.SubmitTaskRequest, worker *storage.Worker) (ar api.J
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTask(worker *storage.Worker) (ar TaskAR) {
|
func getTask(worker *storage.Worker) (ar client.AssignTaskResponse) {
|
||||||
r := Get("/task/get", worker, nil)
|
r := Get("/task/get", worker, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTaskFromProject(project int64, worker *storage.Worker) (ar TaskAR) {
|
func getTaskFromProject(project int64, worker *storage.Worker) (ar client.AssignTaskResponse) {
|
||||||
r := Get(fmt.Sprintf("/task/get/%d", project), worker, nil)
|
r := Get(fmt.Sprintf("/task/get/%d", project), worker, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func releaseTask(request api.ReleaseTaskRequest, worker *storage.Worker) (ar ReleaseAR) {
|
func releaseTask(request api.ReleaseTaskRequest, worker *storage.Worker) (ar client.ReleaseTaskResponse) {
|
||||||
r := Post("/task/release", request, worker, nil)
|
r := Post("/task/release", request, worker, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/simon987/task_tracker/api"
|
"github.com/simon987/task_tracker/api"
|
||||||
|
"github.com/simon987/task_tracker/client"
|
||||||
"github.com/simon987/task_tracker/storage"
|
"github.com/simon987/task_tracker/storage"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
@ -108,13 +109,13 @@ func TestInvalidAccessRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createWorker(req api.CreateWorkerRequest) (ar WorkerAR) {
|
func createWorker(req api.CreateWorkerRequest) (ar client.CreateWorkerResponse) {
|
||||||
r := Post("/worker/create", req, nil, nil)
|
r := Post("/worker/create", req, nil, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getWorker(id int64) (ar WorkerAR) {
|
func getWorker(id int64) (ar client.CreateWorkerResponse) {
|
||||||
r := Get(fmt.Sprintf("/worker/get/%d", id), nil, nil)
|
r := Get(fmt.Sprintf("/worker/get/%d", id), nil, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
@ -125,7 +126,7 @@ func genWid() *storage.Worker {
|
|||||||
return resp.Content.Worker
|
return resp.Content.Worker
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestAccess(req api.CreateWorkerAccessRequest, w *storage.Worker) (ar WorkerAR) {
|
func requestAccess(req api.CreateWorkerAccessRequest, w *storage.Worker) (ar client.CreateWorkerResponse) {
|
||||||
r := Post(fmt.Sprintf("/project/request_access"), req, w, nil)
|
r := Post(fmt.Sprintf("/project/request_access"), req, w, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
|
105
test/client_test.go
Normal file
105
test/client_test.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/simon987/task_tracker/api"
|
||||||
|
"github.com/simon987/task_tracker/client"
|
||||||
|
"github.com/simon987/task_tracker/config"
|
||||||
|
"github.com/simon987/task_tracker/storage"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClientMakeWorker(t *testing.T) {
|
||||||
|
|
||||||
|
c := client.New(config.Cfg.ServerAddr)
|
||||||
|
w, err := c.MakeWorker("test")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.Alias != "test" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientFetchTaskNoTaskAvailable(t *testing.T) {
|
||||||
|
|
||||||
|
c := client.New(config.Cfg.ServerAddr)
|
||||||
|
w, _ := c.MakeWorker("test")
|
||||||
|
c.SetWorker(w)
|
||||||
|
|
||||||
|
_, err := c.FetchTask(89988)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientFetchTask(t *testing.T) {
|
||||||
|
|
||||||
|
c := client.New(config.Cfg.ServerAddr)
|
||||||
|
w, _ := c.MakeWorker("test")
|
||||||
|
c.SetWorker(w)
|
||||||
|
|
||||||
|
createTask(api.SubmitTaskRequest{
|
||||||
|
Project: testProject,
|
||||||
|
Recipe: " ",
|
||||||
|
}, testWorker)
|
||||||
|
|
||||||
|
requestAccess(api.CreateWorkerAccessRequest{
|
||||||
|
Project: testProject,
|
||||||
|
Submit: false,
|
||||||
|
Assign: true,
|
||||||
|
}, &storage.Worker{
|
||||||
|
Secret: w.Secret,
|
||||||
|
Id: w.Id,
|
||||||
|
})
|
||||||
|
acceptAccessRequest(testProject, w.Id, testAdminCtx)
|
||||||
|
|
||||||
|
resp, err := c.FetchTask(int(testProject))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Content.Task == nil {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClientReleaseTask(t *testing.T) {
|
||||||
|
|
||||||
|
c := client.New(config.Cfg.ServerAddr)
|
||||||
|
w, _ := c.MakeWorker("test")
|
||||||
|
c.SetWorker(w)
|
||||||
|
|
||||||
|
createTask(api.SubmitTaskRequest{
|
||||||
|
Project: testProject,
|
||||||
|
Recipe: " ",
|
||||||
|
}, testWorker)
|
||||||
|
|
||||||
|
requestAccess(api.CreateWorkerAccessRequest{
|
||||||
|
Project: testProject,
|
||||||
|
Submit: false,
|
||||||
|
Assign: true,
|
||||||
|
}, &storage.Worker{
|
||||||
|
Secret: w.Secret,
|
||||||
|
Id: w.Id,
|
||||||
|
})
|
||||||
|
acceptAccessRequest(testProject, w.Id, testAdminCtx)
|
||||||
|
|
||||||
|
fetchResp, _ := c.FetchTask(int(testProject))
|
||||||
|
|
||||||
|
resp, err := c.ReleaseTask(api.ReleaseTaskRequest{
|
||||||
|
TaskId: fetchResp.Content.Task.Id,
|
||||||
|
Result: storage.TR_OK,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Content.Updated != true {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
@ -94,14 +94,6 @@ func UnmarshalResponse(r *http.Response, result interface{}) {
|
|||||||
handleErr(err)
|
handleErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerAR struct {
|
|
||||||
Ok bool `json:"ok"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Content struct {
|
|
||||||
Worker *storage.Worker `json:"worker"`
|
|
||||||
} `json:"content"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegisterAR struct {
|
type RegisterAR struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
@ -148,23 +140,6 @@ type ProjectListAR struct {
|
|||||||
} `json:"content"`
|
} `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskAR struct {
|
|
||||||
Ok bool `json:"ok"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
RateLimitDelay float64 `json:"rate_limit_delay,omitempty"`
|
|
||||||
Content struct {
|
|
||||||
Task *storage.Task `json:"task"`
|
|
||||||
} `json:"content"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReleaseAR struct {
|
|
||||||
Ok bool `json:"ok"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Content struct {
|
|
||||||
Updated bool `json:"updated"`
|
|
||||||
} `json:"content"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebhookSecretAR struct {
|
type WebhookSecretAR struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user