Files
remark42/backend/app/store/remote/remote.go
T

135 lines
3.5 KiB
Go

package remote
import (
"bytes"
"encoding/json"
"net/http"
"time"
"github.com/pkg/errors"
"github.com/umputun/remark/backend/app/store"
)
// Client implements remote engine and delegates all calls to remote http server
type Client struct {
API string
Client http.Client
AuthUser string
AuthPasswd string
}
// Request encloses method name and all params
type Request struct {
Method string `json:"method"`
Params interface{} `json:"params"`
}
// Response encloses result and error received from remote server
type Response struct {
Result *json.RawMessage `json:"result,omitempty"`
Error string `json:"error,omitempty"`
}
// Create comment and return ID
func (r *Client) Create(comment store.Comment) (commentID string, err error) {
resp, err := r.call("create", comment)
if err != nil {
return "", err
}
err = json.Unmarshal(*resp.Result, &commentID)
return commentID, err
}
// Get comment by ID
func (r *Client) Get(locator store.Locator, commentID string) (comment store.Comment, err error) {
resp, err := r.call("get", locator, commentID)
if err != nil {
return store.Comment{}, err
}
err = json.Unmarshal(*resp.Result, &comment)
return comment, err
}
// Put updates comment, mutable parts only
func (r *Client) Put(locator store.Locator, comment store.Comment) error {
_, err := r.call("put", locator, comment)
return err
}
// Find comments for locator
func (r *Client) Find(locator store.Locator, sort string) (comments []store.Comment, err error) {
resp, err := r.call("find", locator, sort)
if err != nil {
return []store.Comment{}, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
}
// Last comments for given site, sorted by time
func (r *Client) Last(siteID string, limit int, since time.Time) (comments []store.Comment, err error) {
resp, err := r.call("last", siteID, limit, since)
if err != nil {
return []store.Comment{}, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
}
// User get comments by user, sorted by time
func (r *Client) User(siteID, userID string, limit, skip int) (comments []store.Comment, err error) {
resp, err := r.call("user", siteID, userID, limit, skip)
if err != nil {
return []store.Comment{}, err
}
err = json.Unmarshal(*resp.Result, &comments)
return comments, err
}
// UserCount gets comments count by user
func (r *Client) UserCount(siteID, userID string) (count int, err error) {
resp, err := r.call("user_count", siteID, userID)
if err != nil {
return 0, err
}
err = json.Unmarshal(*resp.Result, &count)
return count, err
}
func (r *Client) call(method string, args ...interface{}) (*Response, error) {
b, err := json.Marshal(Request{Method: method, Params: args})
if err != nil {
return nil, errors.Wrapf(err, "marshaling failed for %s", method)
}
req, err := http.NewRequest("POST", r.API, bytes.NewBuffer(b))
if err != nil {
return nil, errors.Wrapf(err, "failed to make request for %s", method)
}
req.SetBasicAuth(r.AuthUser, r.AuthPasswd)
resp, err := r.Client.Do(req)
if err != nil {
return nil, errors.Wrapf(err, "remote call failed for %s", method)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.Errorf("bad status %d for %s", resp.StatusCode, method)
}
cr := Response{}
if err = json.NewDecoder(resp.Body).Decode(&cr); err != nil {
return nil, errors.Wrapf(err, "failed to decode response for %s", method)
}
if cr.Error != "" {
return nil, errors.New(cr.Error)
}
return &cr, nil
}