axiodb 20.3.2 → 20.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,203 +0,0 @@
1
- package commands
2
-
3
- import (
4
- "fmt"
5
-
6
- "github.com/nexoral/axiodb-cli/pkg/protocol"
7
- )
8
-
9
- func InsertDocument(client *protocol.Client, dbName, collectionName string, data interface{}) (*protocol.Response, error) {
10
- resp, err := client.Send("INSERT_DOCUMENT", map[string]interface{}{
11
- "dbName": dbName,
12
- "collectionName": collectionName,
13
- "data": data,
14
- })
15
- if err != nil {
16
- return nil, fmt.Errorf("insert document: %w", err)
17
- }
18
- if resp.StatusCode >= 400 {
19
- return nil, fmt.Errorf("insert document failed: %s", resp.Error)
20
- }
21
- return resp, nil
22
- }
23
-
24
- func InsertManyDocuments(client *protocol.Client, dbName, collectionName string, documents interface{}) (*protocol.Response, error) {
25
- resp, err := client.Send("INSERT_MANY_DOCUMENTS", map[string]interface{}{
26
- "dbName": dbName,
27
- "collectionName": collectionName,
28
- "documents": documents,
29
- })
30
- if err != nil {
31
- return nil, fmt.Errorf("insert many documents: %w", err)
32
- }
33
- if resp.StatusCode >= 400 {
34
- return nil, fmt.Errorf("insert many documents failed: %s", resp.Error)
35
- }
36
- return resp, nil
37
- }
38
-
39
- type QueryOptions struct {
40
- Query interface{}
41
- Limit int
42
- Skip int
43
- Sort interface{}
44
- FindOne bool
45
- Hint string
46
- }
47
-
48
- func QueryDocuments(client *protocol.Client, dbName, collectionName string, opts QueryOptions) (*protocol.Response, error) {
49
- params := map[string]interface{}{
50
- "dbName": dbName,
51
- "collectionName": collectionName,
52
- }
53
- if opts.Query != nil {
54
- params["query"] = opts.Query
55
- }
56
- if opts.Limit > 0 {
57
- params["limit"] = opts.Limit
58
- }
59
- if opts.Skip > 0 {
60
- params["skip"] = opts.Skip
61
- }
62
- if opts.Sort != nil {
63
- params["sort"] = opts.Sort
64
- }
65
- if opts.FindOne {
66
- params["findOne"] = true
67
- }
68
- if opts.Hint != "" {
69
- params["hint"] = opts.Hint
70
- }
71
-
72
- resp, err := client.Send("QUERY_DOCUMENTS", params)
73
- if err != nil {
74
- return nil, fmt.Errorf("query documents: %w", err)
75
- }
76
- if resp.StatusCode >= 400 {
77
- return nil, fmt.Errorf("query documents failed: %s", resp.Error)
78
- }
79
- return resp, nil
80
- }
81
-
82
- func QueryByID(client *protocol.Client, dbName, collectionName, id string) (*protocol.Response, error) {
83
- resp, err := client.Send("QUERY_BY_ID", map[string]interface{}{
84
- "dbName": dbName,
85
- "collectionName": collectionName,
86
- "id": id,
87
- })
88
- if err != nil {
89
- return nil, fmt.Errorf("query by id: %w", err)
90
- }
91
- if resp.StatusCode >= 400 {
92
- return nil, fmt.Errorf("query by id failed: %s", resp.Error)
93
- }
94
- return resp, nil
95
- }
96
-
97
- func FindDocumentsByIDs(client *protocol.Client, dbName, collectionName string, ids interface{}) (*protocol.Response, error) {
98
- resp, err := client.Send("FIND_BY_IDS", map[string]interface{}{
99
- "dbName": dbName,
100
- "collectionName": collectionName,
101
- "ids": ids,
102
- })
103
- if err != nil {
104
- return nil, fmt.Errorf("find documents by ids: %w", err)
105
- }
106
- if resp.StatusCode >= 400 {
107
- return nil, fmt.Errorf("find documents by ids failed: %s", resp.Error)
108
- }
109
- return resp, nil
110
- }
111
-
112
- func UpdateDocumentByID(client *protocol.Client, dbName, collectionName, id string, updateData interface{}) (*protocol.Response, error) {
113
- resp, err := client.Send("UPDATE_DOCUMENT_BY_ID", map[string]interface{}{
114
- "dbName": dbName,
115
- "collectionName": collectionName,
116
- "id": id,
117
- "updateData": updateData,
118
- })
119
- if err != nil {
120
- return nil, fmt.Errorf("update document: %w", err)
121
- }
122
- if resp.StatusCode >= 400 {
123
- return nil, fmt.Errorf("update document failed: %s", resp.Error)
124
- }
125
- return resp, nil
126
- }
127
-
128
- func UpdateDocumentsByQuery(client *protocol.Client, dbName, collectionName string, query, updateData interface{}, updateOne bool) (*protocol.Response, error) {
129
- resp, err := client.Send("UPDATE_DOCUMENTS_BY_QUERY", map[string]interface{}{
130
- "dbName": dbName,
131
- "collectionName": collectionName,
132
- "query": query,
133
- "updateData": updateData,
134
- "updateOne": updateOne,
135
- })
136
- if err != nil {
137
- return nil, fmt.Errorf("update documents by query: %w", err)
138
- }
139
- if resp.StatusCode >= 400 {
140
- return nil, fmt.Errorf("update documents by query failed: %s", resp.Error)
141
- }
142
- return resp, nil
143
- }
144
-
145
- func DeleteDocumentByID(client *protocol.Client, dbName, collectionName, id string) (*protocol.Response, error) {
146
- resp, err := client.Send("DELETE_DOCUMENT_BY_ID", map[string]interface{}{
147
- "dbName": dbName,
148
- "collectionName": collectionName,
149
- "id": id,
150
- })
151
- if err != nil {
152
- return nil, fmt.Errorf("delete document: %w", err)
153
- }
154
- if resp.StatusCode >= 400 {
155
- return nil, fmt.Errorf("delete document failed: %s", resp.Error)
156
- }
157
- return resp, nil
158
- }
159
-
160
- func DeleteDocumentsByQuery(client *protocol.Client, dbName, collectionName string, query interface{}, deleteOne bool) (*protocol.Response, error) {
161
- resp, err := client.Send("DELETE_DOCUMENTS_BY_QUERY", map[string]interface{}{
162
- "dbName": dbName,
163
- "collectionName": collectionName,
164
- "query": query,
165
- "deleteOne": deleteOne,
166
- })
167
- if err != nil {
168
- return nil, fmt.Errorf("delete documents by query: %w", err)
169
- }
170
- if resp.StatusCode >= 400 {
171
- return nil, fmt.Errorf("delete documents by query failed: %s", resp.Error)
172
- }
173
- return resp, nil
174
- }
175
-
176
- func Aggregate(client *protocol.Client, dbName, collectionName string, pipeline interface{}) (*protocol.Response, error) {
177
- resp, err := client.Send("AGGREGATE", map[string]interface{}{
178
- "dbName": dbName,
179
- "collectionName": collectionName,
180
- "pipeline": pipeline,
181
- })
182
- if err != nil {
183
- return nil, fmt.Errorf("aggregate: %w", err)
184
- }
185
- if resp.StatusCode >= 400 {
186
- return nil, fmt.Errorf("aggregate failed: %s", resp.Error)
187
- }
188
- return resp, nil
189
- }
190
-
191
- func TotalDocuments(client *protocol.Client, dbName, collectionName string) (*protocol.Response, error) {
192
- resp, err := client.Send("TOTAL_DOCUMENTS", map[string]interface{}{
193
- "dbName": dbName,
194
- "collectionName": collectionName,
195
- })
196
- if err != nil {
197
- return nil, fmt.Errorf("total documents: %w", err)
198
- }
199
- if resp.StatusCode >= 400 {
200
- return nil, fmt.Errorf("total documents failed: %s", resp.Error)
201
- }
202
- return resp, nil
203
- }
@@ -1,18 +0,0 @@
1
- package commands
2
-
3
- import (
4
- "fmt"
5
-
6
- "github.com/nexoral/axiodb-cli/pkg/protocol"
7
- )
8
-
9
- func Health(client *protocol.Client) (*protocol.Response, error) {
10
- resp, err := client.Send("HEALTH", nil)
11
- if err != nil {
12
- return nil, fmt.Errorf("get health: %w", err)
13
- }
14
- if resp.StatusCode >= 400 {
15
- return nil, fmt.Errorf("get health failed: %s", resp.Error)
16
- }
17
- return resp, nil
18
- }
@@ -1,51 +0,0 @@
1
- package commands
2
-
3
- import (
4
- "fmt"
5
-
6
- "github.com/nexoral/axiodb-cli/pkg/protocol"
7
- )
8
-
9
- func CreateIndex(client *protocol.Client, dbName, collectionName string, fieldNames []string) (*protocol.Response, error) {
10
- resp, err := client.Send("CREATE_INDEX", map[string]interface{}{
11
- "dbName": dbName,
12
- "collectionName": collectionName,
13
- "fieldNames": fieldNames,
14
- })
15
- if err != nil {
16
- return nil, fmt.Errorf("create index: %w", err)
17
- }
18
- if resp.StatusCode >= 400 {
19
- return nil, fmt.Errorf("create index failed: %s", resp.Error)
20
- }
21
- return resp, nil
22
- }
23
-
24
- func DropIndex(client *protocol.Client, dbName, collectionName, indexName string) (*protocol.Response, error) {
25
- resp, err := client.Send("DROP_INDEX", map[string]interface{}{
26
- "dbName": dbName,
27
- "collectionName": collectionName,
28
- "indexName": indexName,
29
- })
30
- if err != nil {
31
- return nil, fmt.Errorf("drop index: %w", err)
32
- }
33
- if resp.StatusCode >= 400 {
34
- return nil, fmt.Errorf("drop index failed: %s", resp.Error)
35
- }
36
- return resp, nil
37
- }
38
-
39
- func ListIndexes(client *protocol.Client, dbName, collectionName string) (*protocol.Response, error) {
40
- resp, err := client.Send("LIST_INDEXES", map[string]interface{}{
41
- "dbName": dbName,
42
- "collectionName": collectionName,
43
- })
44
- if err != nil {
45
- return nil, fmt.Errorf("list indexes: %w", err)
46
- }
47
- if resp.StatusCode >= 400 {
48
- return nil, fmt.Errorf("list indexes failed: %s", resp.Error)
49
- }
50
- return resp, nil
51
- }
@@ -1,84 +0,0 @@
1
- package commands
2
-
3
- import (
4
- "fmt"
5
-
6
- "github.com/nexoral/axiodb-cli/pkg/protocol"
7
- )
8
-
9
- type TransactionStep struct {
10
- Operation string `json:"operation"`
11
- Data interface{} `json:"data,omitempty"`
12
- Documents interface{} `json:"documents,omitempty"`
13
- Query interface{} `json:"query,omitempty"`
14
- UpdateData interface{} `json:"updateData,omitempty"`
15
- ID string `json:"id,omitempty"`
16
- IDs []string `json:"ids,omitempty"`
17
- SavepointName string `json:"savepointName,omitempty"`
18
- UpdateOne bool `json:"updateOne,omitempty"`
19
- DeleteOne bool `json:"deleteOne,omitempty"`
20
- }
21
-
22
- func BeginTransaction(client *protocol.Client, dbName, collectionName string) (*protocol.Response, error) {
23
- return client.Send("BEGIN_TRANSACTION", map[string]interface{}{"dbName": dbName, "collectionName": collectionName})
24
- }
25
-
26
- func CommitTransaction(client *protocol.Client, transactionID string) (*protocol.Response, error) {
27
- return client.Send("COMMIT_TRANSACTION", map[string]interface{}{"transactionId": transactionID})
28
- }
29
-
30
- func RollbackTransaction(client *protocol.Client, transactionID string) (*protocol.Response, error) {
31
- return client.Send("ROLLBACK_TRANSACTION", map[string]interface{}{"transactionId": transactionID})
32
- }
33
-
34
- func Savepoint(client *protocol.Client, transactionID, savepointName string) (*protocol.Response, error) {
35
- return client.Send("SAVEPOINT", map[string]interface{}{"transactionId": transactionID, "savepointName": savepointName})
36
- }
37
-
38
- func RollbackToSavepoint(client *protocol.Client, transactionID, savepointName string) (*protocol.Response, error) {
39
- return client.Send("ROLLBACK_TO_SAVEPOINT", map[string]interface{}{"transactionId": transactionID, "savepointName": savepointName})
40
- }
41
-
42
- func ReleaseSavepoint(client *protocol.Client, transactionID, savepointName string) (*protocol.Response, error) {
43
- return client.Send("RELEASE_SAVEPOINT", map[string]interface{}{"transactionId": transactionID, "savepointName": savepointName})
44
- }
45
-
46
- func RunTransaction(client *protocol.Client, dbName, collectionName string, steps []TransactionStep) (*protocol.Response, error) {
47
- begin, err := BeginTransaction(client, dbName, collectionName)
48
- if err != nil || begin.StatusCode >= 400 {
49
- if err != nil { return nil, fmt.Errorf("begin transaction: %w", err) }
50
- return nil, fmt.Errorf("begin transaction failed: %s", begin.Error)
51
- }
52
- transactionID, ok := begin.Data.(map[string]interface{})["transactionId"].(string)
53
- if !ok || transactionID == "" {
54
- return nil, fmt.Errorf("begin transaction returned no transaction ID")
55
- }
56
- base := map[string]interface{}{"dbName": dbName, "collectionName": collectionName, "transactionId": transactionID}
57
- for _, step := range steps {
58
- params := map[string]interface{}{}
59
- for key, value := range base { params[key] = value }
60
- switch step.Operation {
61
- case "insert": params["data"] = step.Data
62
- case "insert-many": params["documents"] = step.Documents
63
- case "query": params["query"] = step.Query
64
- case "find-by-ids": params["ids"] = step.IDs
65
- case "update-by-id": params["id"], params["updateData"] = step.ID, step.UpdateData
66
- case "update-by-query": params["query"], params["updateData"], params["updateOne"] = step.Query, step.UpdateData, step.UpdateOne
67
- case "delete-by-id": params["id"] = step.ID
68
- case "delete-by-query": params["query"], params["deleteOne"] = step.Query, step.DeleteOne
69
- case "savepoint", "rollback-to-savepoint", "release-savepoint": params["savepointName"] = step.SavepointName
70
- default: return nil, fmt.Errorf("unsupported transaction operation: %s", step.Operation)
71
- }
72
- command := map[string]string{"insert":"INSERT_DOCUMENT", "insert-many":"INSERT_MANY_DOCUMENTS", "query":"QUERY_DOCUMENTS", "find-by-ids":"FIND_BY_IDS", "update-by-id":"UPDATE_DOCUMENT_BY_ID", "update-by-query":"UPDATE_DOCUMENTS_BY_QUERY", "delete-by-id":"DELETE_DOCUMENT_BY_ID", "delete-by-query":"DELETE_DOCUMENTS_BY_QUERY", "savepoint":"SAVEPOINT", "rollback-to-savepoint":"ROLLBACK_TO_SAVEPOINT", "release-savepoint":"RELEASE_SAVEPOINT"}[step.Operation]
73
- response, sendErr := client.Send(command, params)
74
- if sendErr != nil || response.StatusCode >= 400 {
75
- _, _ = RollbackTransaction(client, transactionID)
76
- if sendErr != nil { return nil, fmt.Errorf("transaction %s: %w", step.Operation, sendErr) }
77
- return nil, fmt.Errorf("transaction %s failed: %s", step.Operation, response.Error)
78
- }
79
- }
80
- commit, err := CommitTransaction(client, transactionID)
81
- if err != nil { return nil, fmt.Errorf("commit transaction: %w", err) }
82
- if commit.StatusCode >= 400 { return nil, fmt.Errorf("commit transaction failed: %s", commit.Error) }
83
- return commit, nil
84
- }
@@ -1,236 +0,0 @@
1
- package httpclient
2
-
3
- import (
4
- "bytes"
5
- "encoding/json"
6
- "fmt"
7
- "io"
8
- "mime/multipart"
9
- "net/http"
10
- "net/http/cookiejar"
11
- "net/url"
12
- "os"
13
- "path/filepath"
14
- "strings"
15
- "time"
16
- )
17
-
18
- type HTTPClient struct {
19
- baseURL string
20
- httpClient *http.Client
21
- }
22
-
23
- func (c *HTTPClient) doJSON(method, path string, payload interface{}) (map[string]interface{}, error) {
24
- var body io.Reader
25
- if payload != nil {
26
- encoded, err := json.Marshal(payload)
27
- if err != nil {
28
- return nil, fmt.Errorf("encode request: %w", err)
29
- }
30
- body = bytes.NewReader(encoded)
31
- }
32
- req, err := http.NewRequest(method, c.baseURL+path, body)
33
- if err != nil {
34
- return nil, fmt.Errorf("create request: %w", err)
35
- }
36
- if payload != nil {
37
- req.Header.Set("Content-Type", "application/json")
38
- }
39
- resp, err := c.httpClient.Do(req)
40
- if err != nil {
41
- return nil, fmt.Errorf("request failed: %w", err)
42
- }
43
- defer resp.Body.Close()
44
- var result map[string]interface{}
45
- if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
46
- return nil, fmt.Errorf("parse response: %w", err)
47
- }
48
- if resp.StatusCode >= 400 {
49
- message, _ := result["message"].(string)
50
- if message == "" {
51
- message = resp.Status
52
- }
53
- return nil, fmt.Errorf("request failed: %s", message)
54
- }
55
- return result, nil
56
- }
57
-
58
- func (c *HTTPClient) ListUsers() (map[string]interface{}, error) {
59
- return c.doJSON(http.MethodGet, "/api/auth/users/", nil)
60
- }
61
-
62
- func (c *HTTPClient) CreateUser(username, password, role string) (map[string]interface{}, error) {
63
- return c.doJSON(http.MethodPost, "/api/auth/users/", map[string]string{"username": username, "password": password, "role": role})
64
- }
65
-
66
- func (c *HTTPClient) UpdateUserRole(username, role string) (map[string]interface{}, error) {
67
- return c.doJSON(http.MethodPatch, "/api/auth/users/"+url.PathEscape(username)+"/role", map[string]string{"role": role})
68
- }
69
-
70
- func (c *HTTPClient) ResetUserPassword(username, password string) (map[string]interface{}, error) {
71
- return c.doJSON(http.MethodPatch, "/api/auth/users/"+url.PathEscape(username)+"/reset-password", map[string]string{"newPassword": password})
72
- }
73
-
74
- func (c *HTTPClient) DeleteUser(username string) (map[string]interface{}, error) {
75
- return c.doJSON(http.MethodDelete, "/api/auth/users/"+url.PathEscape(username), nil)
76
- }
77
-
78
- func (c *HTTPClient) ListRoles() (map[string]interface{}, error) {
79
- return c.doJSON(http.MethodGet, "/api/auth/roles/", nil)
80
- }
81
-
82
- func (c *HTTPClient) CreateRole(roleName string, permissions []string) (map[string]interface{}, error) {
83
- return c.doJSON(http.MethodPost, "/api/auth/roles/", map[string]interface{}{"roleName": roleName, "permissions": permissions})
84
- }
85
-
86
- func (c *HTTPClient) DeleteRole(roleName string) (map[string]interface{}, error) {
87
- return c.doJSON(http.MethodDelete, "/api/auth/roles/"+url.PathEscape(roleName), nil)
88
- }
89
-
90
- func (c *HTTPClient) ListPermissions() (map[string]interface{}, error) {
91
- return c.doJSON(http.MethodGet, "/api/auth/roles/permissions", nil)
92
- }
93
-
94
- func (c *HTTPClient) ChangeOwnPassword(currentPassword, newPassword string) (map[string]interface{}, error) {
95
- return c.doJSON(http.MethodPatch, "/api/auth/change-password", map[string]string{"currentPassword": currentPassword, "newPassword": newPassword})
96
- }
97
-
98
- func New(host string, port int, timeout time.Duration) *HTTPClient {
99
- jar, _ := cookiejar.New(nil)
100
- return &HTTPClient{
101
- baseURL: fmt.Sprintf("http://%s:%d", host, port),
102
- httpClient: &http.Client{
103
- Timeout: timeout,
104
- Jar: jar,
105
- },
106
- }
107
- }
108
-
109
- func (c *HTTPClient) Login(username, password string) error {
110
- body, _ := json.Marshal(map[string]string{
111
- "username": username,
112
- "password": password,
113
- })
114
-
115
- resp, err := c.httpClient.Post(c.baseURL+"/api/auth/login", "application/json", bytes.NewReader(body))
116
- if err != nil {
117
- return fmt.Errorf("login request failed: %w", err)
118
- }
119
- defer resp.Body.Close()
120
-
121
- if resp.StatusCode == http.StatusOK {
122
- return nil
123
- }
124
-
125
- var errResp struct {
126
- Message string `json:"message"`
127
- }
128
- json.NewDecoder(resp.Body).Decode(&errResp)
129
- msg := errResp.Message
130
- if msg == "" {
131
- msg = resp.Status
132
- }
133
- return fmt.Errorf("login failed: %s", msg)
134
- }
135
-
136
- func (c *HTTPClient) Logout() error {
137
- resp, err := c.httpClient.Post(c.baseURL+"/api/auth/logout", "application/json", nil)
138
- if err != nil {
139
- return err
140
- }
141
- defer resp.Body.Close()
142
- return nil
143
- }
144
-
145
- func (c *HTTPClient) Export(dbName string) (string, int64, error) {
146
- url := fmt.Sprintf("%s/api/db/export-database/?dbName=%s", c.baseURL, dbName)
147
- resp, err := c.httpClient.Get(url)
148
- if err != nil {
149
- return "", 0, fmt.Errorf("export request failed: %w", err)
150
- }
151
- defer resp.Body.Close()
152
-
153
- if resp.StatusCode != http.StatusOK {
154
- var errResp struct {
155
- Message string `json:"message"`
156
- }
157
- json.NewDecoder(resp.Body).Decode(&errResp)
158
- msg := errResp.Message
159
- if msg == "" {
160
- msg = resp.Status
161
- }
162
- return "", 0, fmt.Errorf("export failed: %s", msg)
163
- }
164
-
165
- filename := dbName + ".tar.gz"
166
- if cd := resp.Header.Get("Content-Disposition"); cd != "" {
167
- if idx := strings.Index(cd, "filename="); idx >= 0 {
168
- name := cd[idx+9:]
169
- name = strings.Trim(name, "\"")
170
- if name != "" {
171
- filename = filepath.Base(name)
172
- }
173
- }
174
- }
175
-
176
- out, err := os.Create(filename)
177
- if err != nil {
178
- return "", 0, fmt.Errorf("create file: %w", err)
179
- }
180
- defer out.Close()
181
-
182
- written, err := io.Copy(out, resp.Body)
183
- if err != nil {
184
- os.Remove(filename)
185
- return "", 0, fmt.Errorf("write file: %w", err)
186
- }
187
-
188
- return filename, written, nil
189
- }
190
-
191
- func (c *HTTPClient) Import(filePath string) (string, error) {
192
- file, err := os.Open(filePath)
193
- if err != nil {
194
- return "", fmt.Errorf("open file: %w", err)
195
- }
196
- defer file.Close()
197
-
198
- var body bytes.Buffer
199
- writer := multipart.NewWriter(&body)
200
- part, err := writer.CreateFormFile("file", filepath.Base(filePath))
201
- if err != nil {
202
- return "", fmt.Errorf("create form file: %w", err)
203
- }
204
- if _, err := io.Copy(part, file); err != nil {
205
- return "", fmt.Errorf("write form data: %w", err)
206
- }
207
- writer.Close()
208
-
209
- resp, err := c.httpClient.Post(
210
- c.baseURL+"/api/db/import-database/",
211
- writer.FormDataContentType(),
212
- &body,
213
- )
214
- if err != nil {
215
- return "", fmt.Errorf("import request failed: %w", err)
216
- }
217
- defer resp.Body.Close()
218
-
219
- var result struct {
220
- Message string `json:"message"`
221
- Database string `json:"database"`
222
- }
223
- if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
224
- return "", fmt.Errorf("parse response: %w", err)
225
- }
226
-
227
- if resp.StatusCode != http.StatusOK {
228
- msg := result.Message
229
- if msg == "" {
230
- msg = fmt.Sprintf("HTTP %d", resp.StatusCode)
231
- }
232
- return "", fmt.Errorf("import failed: %s", msg)
233
- }
234
-
235
- return result.Database, nil
236
- }
@@ -1,46 +0,0 @@
1
- package protocol
2
-
3
- import "fmt"
4
-
5
- type AuthResult struct {
6
- Username string `json:"username"`
7
- Role string `json:"role"`
8
- MustChangePassword bool `json:"mustChangePassword"`
9
- }
10
-
11
- func Authenticate(client *Client, username, password string) (*AuthResult, error) {
12
- resp, err := client.Send("AUTHENTICATE", map[string]interface{}{
13
- "username": username,
14
- "password": password,
15
- })
16
- if err != nil {
17
- return nil, fmt.Errorf("authenticate: %w", err)
18
- }
19
-
20
- switch resp.StatusCode {
21
- case 200:
22
- data, ok := resp.Data.(map[string]interface{})
23
- if !ok {
24
- return nil, fmt.Errorf("unexpected auth response format")
25
- }
26
- result := &AuthResult{}
27
- if v, ok := data["username"].(string); ok {
28
- result.Username = v
29
- }
30
- if v, ok := data["role"].(string); ok {
31
- result.Role = v
32
- }
33
- if v, ok := data["mustChangePassword"].(bool); ok {
34
- result.MustChangePassword = v
35
- }
36
- return result, nil
37
- case 401:
38
- return nil, fmt.Errorf("authentication failed: invalid credentials")
39
- case 403:
40
- return nil, fmt.Errorf("authentication failed: password change required")
41
- case 429:
42
- return nil, fmt.Errorf("authentication failed: too many attempts, try again later")
43
- default:
44
- return nil, fmt.Errorf("authentication failed (status %d): %s", resp.StatusCode, resp.Error)
45
- }
46
- }