Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint code and add linting configuration #13

Merged
merged 11 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ jobs:

- name: Display Go version
run: go version

- name: Code Lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.55.2
- name: Build
run: go build -v .
- name: Test
Expand Down
67 changes: 67 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
linters-settings:
exhaustive:
default-signifies-exhaustive: true
errcheck:
check-type-assertions: true
goconst:
min-len: 2
min-occurrences: 3
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
govet:
check-shadowing: true
enable:
- fieldalignment
nolintlint:
require-explanation: true
require-specific: true

linters:
disable-all: true
enable:
- bodyclose
- dogsled
- dupl
- errcheck
- exportloopref
- exhaustive
- goconst
- gocritic
- gofmt
- goimports
- gomnd
- gocyclo
- gosec
- gosimple
- govet
- ineffassign
- misspell
- nolintlint
- nakedret
- prealloc
- predeclared
- revive
- staticcheck
- stylecheck
- thelper
- tparallel
- typecheck
- unconvert
- unparam
- unused
- whitespace
- wsl

issues:
exclude-rules:
- path: _test\.go$
linters:
- goconst

run:
issues-exit-code: 1
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ coverage:
cat coverage.out | grep -v "/calls.go" | grep -v "custom_subscription_calls.go" | grep -v "subscription_calls.go" > coverage.final.out
go tool cover -func=coverage.final.out
rm coverage.out coverage.final.out

lint:
golangci-lint run
95 changes: 47 additions & 48 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,42 @@ import (
"github.com/ksysoev/deriv-api/schema"
)

const (
// DefaultKeepAliveInterval is the default interval for sending ping requests to keep the connection alive.
keepAliveInterval = 25 * time.Second
defaultTimeout = 30 * time.Second
)

// DerivAPI is the main struct for the DerivAPI client.
type DerivAPI struct {
Origin *url.URL // The origin URL for the DerivAPI server
Endpoint *url.URL // The WebSocket endpoint URL for the DerivAPI server
AppID int // The app ID for the DerivAPI server
Lang string // The language code (ISO 639-1) for the DerivAPI server
ws *websocket.Conn // The WebSocket connection to the DerivAPI server
lastRequestID int64 // The last request ID used for the DerivAPI server
TimeOut time.Duration // The timeout duration for the DerivAPI server api calls
connectionLock sync.Mutex // A lock for the DerivAPI server connection
reqChan chan ApiReqest // A channel for sending requests to the DerivAPI server
closingChan chan int // A channel for closing the DerivAPI server connection
keepAlive bool // A flag to keep the connection alive
keepAliveOnDisconnect chan bool // A channel to keep the connection alive
keepAliveInterval time.Duration // The interval to send ping requests
debugEnabled bool // A flag to print debug messages
type DerivAPI struct { //nolint:revive // don't want to change the name for now
reqChan chan APIReqest
Endpoint *url.URL
keepAliveOnDisconnect chan bool
Origin *url.URL
ws *websocket.Conn
closingChan chan int
Lang string
TimeOut time.Duration
lastRequestID int64
AppID int
keepAliveInterval time.Duration
connectionLock sync.Mutex
keepAlive bool
debugEnabled bool
}

// ApiReqest is an interface for all API requests.
type ApiReqest struct {
id int
msg []byte
// APIReqest is an interface for all API requests.
type APIReqest struct {
respChan chan []byte
msg []byte
id int
}

type APIResponseReqID struct {
ReqID int `json:"req_id"`
}

type DerivApiOption func(api *DerivAPI)
type APIOption func(api *DerivAPI)

// NewDerivAPI creates a new instance of DerivAPI by parsing and validating the given
// endpoint URL, appID, language, and origin URL. It returns a pointer to a DerivAPI object
Expand All @@ -56,9 +62,9 @@ type DerivApiOption func(api *DerivAPI)
// - appID: int - The app ID for the DerivAPI server
// - lang: string - The language code (ISO 639-1) for the DerivAPI server
// - origin: string - The origin URL for the DerivAPI server
// - opts: DerivApiOption - A variadic list of DerivApiOption functions to configure the DerivAPI object (optional)
// - KeepAlive: A DerivApiOption function to keep the connection alive by sending ping requests.
// - Debug: A DerivApiOption function to enable debug messages.
// - opts: APIOption - A variadic list of APIOption functions to configure the DerivAPI object (optional)
// - KeepAlive: A APIOption function to keep the connection alive by sending ping requests.
// - Debug: A APIOption function to enable debug messages.
//
// Returns:
// - *DerivAPI: A pointer to a new instance of DerivAPI with the validated endpoint, appID,
Expand All @@ -71,7 +77,7 @@ type DerivApiOption func(api *DerivAPI)
// if err != nil {
// log.Fatal(err)
// }
func NewDerivAPI(endpoint string, appID int, lang string, origin string, opts ...DerivApiOption) (*DerivAPI, error) {
func NewDerivAPI(endpoint string, appID int, lang, origin string, opts ...APIOption) (*DerivAPI, error) {
urlEnpoint, err := url.Parse(endpoint)
if err != nil {
return nil, err
Expand All @@ -91,7 +97,7 @@ func NewDerivAPI(endpoint string, appID int, lang string, origin string, opts ..
}

if lang == "" || len(lang) != 2 {
return nil, fmt.Errorf("Invalid language")
return nil, fmt.Errorf("invalid language")
}

query := urlEnpoint.Query()
Expand All @@ -106,10 +112,10 @@ func NewDerivAPI(endpoint string, appID int, lang string, origin string, opts ..
AppID: appID,
Lang: lang,
lastRequestID: 0,
TimeOut: 30 * time.Second,
TimeOut: defaultTimeout,
connectionLock: sync.Mutex{},
closingChan: make(chan int),
keepAliveInterval: 25 * time.Second,
keepAliveInterval: keepAliveInterval,
}

for _, opt := range opts {
Expand Down Expand Up @@ -167,7 +173,7 @@ func (api *DerivAPI) Connect() error {

api.ws = ws

api.reqChan = make(chan ApiReqest)
api.reqChan = make(chan APIReqest)
respChan := make(chan []byte)
outputChan := make(chan []byte)

Expand All @@ -189,7 +195,6 @@ func (api *DerivAPI) Connect() error {
case <-onDisconnect:
return
}

}
}(api.keepAliveInterval, api.keepAliveOnDisconnect)
}
Expand Down Expand Up @@ -229,11 +234,10 @@ func (api *DerivAPI) requestSender(wsConn *websocket.Conn, reqChan chan []byte)
for req := range reqChan {
api.logDebugf("Sending request: %s", req)

err := wsConn.Write(context.TODO(), websocket.MessageText, req)

if err != nil {
if err := wsConn.Write(context.TODO(), websocket.MessageText, req); err != nil {
api.logDebugf("Failed to send request: %s", err.Error())
api.Disconnect()

return
}
}
Expand Down Expand Up @@ -277,7 +281,7 @@ func (api *DerivAPI) handleResponses(wsConn *websocket.Conn, respChan chan []byt

// requestMapper forward requests to the Deriv API server and
// responses from the WebSocket server to the appropriate channels.
func (api *DerivAPI) requestMapper(respChan chan []byte, outputChan chan []byte, reqChan chan ApiReqest, closingChan chan int) {
func (api *DerivAPI) requestMapper(respChan, outputChan chan []byte, reqChan chan APIReqest, closingChan chan int) {
responseMap := make(map[int]chan []byte)

defer func() {
Expand All @@ -291,29 +295,26 @@ func (api *DerivAPI) requestMapper(respChan chan []byte, outputChan chan []byte,
select {
case rawResp := <-respChan:
var response APIResponseReqID
err := json.Unmarshal(rawResp, &response)
if err != nil {

if err := json.Unmarshal(rawResp, &response); err != nil {
continue
}
channel, ok := responseMap[response.ReqID]

if ok {
if channel, ok := responseMap[response.ReqID]; ok {
channel <- rawResp
}
case req, ok := <-reqChan:
if !ok {
return
}

responseMap[req.id] = req.respChan
outputChan <- req.msg
case reqID := <-closingChan:
channel, okGet := responseMap[reqID]

if okGet {
if channel, ok := responseMap[reqID]; ok {
close(channel)
delete(responseMap, reqID)
}

}
}
}
Expand All @@ -333,19 +334,19 @@ func (api *DerivAPI) Send(reqID int, request any) (chan []byte, error) {

respChan := make(chan []byte)

ApiReqest := ApiReqest{
req := APIReqest{
id: reqID,
msg: msg,
respChan: respChan,
}

api.reqChan <- ApiReqest
api.reqChan <- req

return respChan, nil
}

// SendRequest sends a request to the Deriv API and returns the response
func (api *DerivAPI) SendRequest(reqID int, request any, response any) (err error) {
func (api *DerivAPI) SendRequest(reqID int, request, response any) error {
respChan, err := api.Send(reqID, request)

if err != nil {
Expand All @@ -364,18 +365,16 @@ func (api *DerivAPI) SendRequest(reqID int, request any, response any) (err erro
return fmt.Errorf("connection closed")
}

if err = parseError(responseJSON); err != nil {
if err := parseError(responseJSON); err != nil {
return err
}

err = json.Unmarshal(responseJSON, response)
if err != nil {
if err := json.Unmarshal(responseJSON, response); err != nil {
api.logDebugf("Failed to parse response for request %d: %s", reqID, err.Error())
return err
}

return nil

}
}

Expand Down
Loading
Loading