1st ver
commit
fdb5553bd7
|
@ -0,0 +1,2 @@
|
||||||
|
.idea
|
||||||
|
.vscode
|
|
@ -0,0 +1,2 @@
|
||||||
|
# go-client
|
||||||
|
Core Implementation for Go based Replay features
|
|
@ -0,0 +1,48 @@
|
||||||
|
package anticaptcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *api.Cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) HttpCli() *api.Cli {
|
||||||
|
return c.cli
|
||||||
|
}
|
||||||
|
|
||||||
|
type Req struct {
|
||||||
|
Site string `json:"site"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Img []byte `json:"img"`
|
||||||
|
To int `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Recaptchav2(site string, data string) (string, error) {
|
||||||
|
ret := ""
|
||||||
|
req := &Req{
|
||||||
|
Site: site,
|
||||||
|
Data: data,
|
||||||
|
Img: nil,
|
||||||
|
To: 300,
|
||||||
|
}
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/anticaptcha/recaptchav2", req, &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Image2text(site string, data []byte) (string, error) {
|
||||||
|
ret := ""
|
||||||
|
req := &Req{
|
||||||
|
Site: site,
|
||||||
|
Img: data,
|
||||||
|
To: 300,
|
||||||
|
}
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/anticaptcha/image2text", req, &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
ret := &Cli{cli: api.NewCli()}
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package chrome
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *api.Cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) HttpCli() *api.Cli {
|
||||||
|
return c.cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Start(to int) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/chrome/start?to=%d", to), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) StartHeadless() error {
|
||||||
|
err := c.cli.HttpJsonGet("/ipc/chrome/startHeadless", nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) Stop() error {
|
||||||
|
err := c.cli.HttpJsonGet("/ipc/chrome/stop", nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) New(url string) (string, error) {
|
||||||
|
ret := ""
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/chrome/new?url=%s", url), &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
func (c *Cli) Close(id string) error {
|
||||||
|
err := c.cli.HttpJsonGet("/ipc/chrome/close/"+id, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) Eval(id string, s string) (map[string]interface{}, error) {
|
||||||
|
ret := make(map[string]interface{})
|
||||||
|
bs, err := c.cli.HttpRawPost("/ipc/chrome/eval/"+id, []byte(s))
|
||||||
|
json.Unmarshal(bs, &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Wait(id string, s string, to int) (string, error) {
|
||||||
|
ret := ""
|
||||||
|
bs, err := c.cli.HttpRawPost(fmt.Sprintf("/ipc/chrome/wait/%s?to=%d", id, to), []byte(s))
|
||||||
|
json.Unmarshal(bs, &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Send(id string, m string, ps map[string]interface{}) (string, error) {
|
||||||
|
ret := ""
|
||||||
|
in := map[string]interface{}{
|
||||||
|
"method": m,
|
||||||
|
"params": ps,
|
||||||
|
}
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/chrome/eval/"+id, in, &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
ret := &Cli{cli: api.NewCli()}
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *http.Client
|
||||||
|
headers map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Addr() string {
|
||||||
|
ret := os.Getenv("REPLAY_ADDR")
|
||||||
|
if ret == "" {
|
||||||
|
ret = "https://localhost:8443"
|
||||||
|
} else if strings.HasPrefix(ret, ":") {
|
||||||
|
ret = "https://localhost" + ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
func (c *Cli) AddHeader(k string, v string) {
|
||||||
|
c.headers[k] = v
|
||||||
|
}
|
||||||
|
func (c *Cli) DelHeader(k string) {
|
||||||
|
delete(c.headers, k)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpDo(method string, strurl string, body []byte) (*http.Response, error) {
|
||||||
|
if !strings.HasPrefix(strurl, "http") {
|
||||||
|
addr := c.Addr()
|
||||||
|
if strings.HasSuffix(addr, "/") {
|
||||||
|
addr = addr[:len(addr)-1]
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(strurl, "") {
|
||||||
|
strurl = "/" + strurl
|
||||||
|
}
|
||||||
|
strurl = addr + strurl
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(method, strurl, bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.headers != nil {
|
||||||
|
for k, v := range c.headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if body != nil && len(body) > 0 {
|
||||||
|
req, err = http.NewRequest(method, strurl, io.NopCloser(bytes.NewReader(body)))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
req, err = http.NewRequest(method, strurl, nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("X-API-KEY", apikey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
return c.cli.Do(req)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpDoJson(method string, strurl string, i interface{}, o interface{}) (err error) {
|
||||||
|
bs, err := json.Marshal(i)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := c.HttpDo(method, strurl, bs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if o != nil {
|
||||||
|
err = json.NewDecoder(res.Body).Decode(o)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonGet(strurl string, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodGet, strurl, nil, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonDelete(strurl string, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodDelete, strurl, nil, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonHead(strurl string, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodHead, strurl, nil, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonPost(strurl string, i interface{}, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodPost, strurl, i, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonPut(strurl string, i interface{}, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodPut, strurl, i, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpJsonPatch(strurl string, i interface{}, o interface{}) error {
|
||||||
|
return c.HttpDoJson(http.MethodPatch, strurl, i, o)
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpRawGet(strurl string) ([]byte, error) {
|
||||||
|
res, err := c.HttpDo(http.MethodGet, strurl, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
bs, _ := io.ReadAll(res.Body)
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpRawDelete(strurl string) ([]byte, error) {
|
||||||
|
res, err := c.HttpDo(http.MethodDelete, strurl, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
bs, _ := io.ReadAll(res.Body)
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpRawPost(strurl string, i []byte) ([]byte, error) {
|
||||||
|
res, err := c.HttpDo(http.MethodPost, strurl, i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
bs, _ := io.ReadAll(res.Body)
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
func (c *Cli) HttpRawPut(strurl string, i []byte) ([]byte, error) {
|
||||||
|
res, err := c.HttpDo(http.MethodPut, strurl, i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
bs, _ := io.ReadAll(res.Body)
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
apikey = os.Getenv("REPLAY_APIKEY")
|
||||||
|
ret := &Cli{
|
||||||
|
cli: &http.Client{},
|
||||||
|
headers: make(map[string]string),
|
||||||
|
}
|
||||||
|
ret.AddHeader("X-API-KEY", apikey)
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package excel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CELLTYPE_STRING = "s"
|
||||||
|
CELLTYPE_INT = "i"
|
||||||
|
CELLTYPE_BOOL = "b"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *api.Cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) HttpCli() *api.Cli {
|
||||||
|
return c.cli
|
||||||
|
}
|
||||||
|
|
||||||
|
type Req struct {
|
||||||
|
File string `json:"file"`
|
||||||
|
Sheet string `json:"sheet"`
|
||||||
|
Cel string `json:"cel"`
|
||||||
|
Val string `json:"val"`
|
||||||
|
Celtype string `json:"celtype"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Read(fname string, sheet string) ([][]string, error) {
|
||||||
|
req := &Req{
|
||||||
|
File: fname,
|
||||||
|
Sheet: sheet,
|
||||||
|
}
|
||||||
|
res := make([][]string, 0)
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/excel/read", req, &res)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
func (c *Cli) Write(fname string, sheet string, cell string, val string, celtype string) error {
|
||||||
|
req := &Req{
|
||||||
|
File: fname,
|
||||||
|
Sheet: sheet,
|
||||||
|
Cel: cell,
|
||||||
|
Val: val,
|
||||||
|
Celtype: celtype,
|
||||||
|
}
|
||||||
|
res := ""
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/excel/write", req, &res)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) New(fname string, sheet string) (string, error) {
|
||||||
|
req := &Req{
|
||||||
|
File: fname,
|
||||||
|
Sheet: sheet,
|
||||||
|
}
|
||||||
|
res := ""
|
||||||
|
err := c.cli.HttpJsonPost("/ipc/excel/new", req, &res)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
ret := &Cli{cli: api.NewCli()}
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/types"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var apikey string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
apikey = os.Getenv("REPLAY_APIKEY")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Addr() string {
|
||||||
|
ret := os.Getenv("REPLAY_ADDR")
|
||||||
|
if ret == "" {
|
||||||
|
ret = "http://localhost:8080"
|
||||||
|
} else if strings.HasPrefix(ret, ":") {
|
||||||
|
ret = "http://localhost" + ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpDo(method string, strurl string, body []byte) (*http.Response, error) {
|
||||||
|
cli := http.Client{}
|
||||||
|
var err error
|
||||||
|
var req *http.Request
|
||||||
|
|
||||||
|
if body != nil && len(body) > 0 {
|
||||||
|
req, err = http.NewRequest(method, strurl, io.NopCloser(bytes.NewReader(body)))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
req, err = http.NewRequest(method, strurl, nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("X-API-KEY", apikey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
return cli.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpDoJson(i interface{}, method string, strurl string, body []byte) (err error) {
|
||||||
|
res, err := HttpDo(method, strurl, body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type roboDAO struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d roboDAO) GetAll() ([]*types.Robot, error) {
|
||||||
|
ret := make([]*types.Robot, 0)
|
||||||
|
err := HttpDoJson(&ret, http.MethodGet, Addr()+fmt.Sprintf("/api/v1/robots"), nil)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
func (d roboDAO) Enqueue(id uint) error {
|
||||||
|
_, err := HttpDo(http.MethodGet, Addr()+fmt.Sprintf("/api/v1/robots/op/enqueue/%d", id), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var RoboDAO roboDAO
|
||||||
|
|
||||||
|
type sqlDAO struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d sqlDAO) SQL(s string) (types.SQLResponse, error) {
|
||||||
|
ret := types.SQLResponse{}
|
||||||
|
req := types.SQLRequest{Sql: s}
|
||||||
|
bs, _ := json.Marshal(req)
|
||||||
|
err := HttpDoJson(&ret, http.MethodPost, Addr()+fmt.Sprintf("/api/v1/sql"), bs)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var SQLDAO sqlDAO
|
||||||
|
|
||||||
|
type appDAO struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d appDAO) GetAll() ([]*types.App, error) {
|
||||||
|
ret := make([]*types.App, 0)
|
||||||
|
err := HttpDoJson(&ret, http.MethodGet, Addr()+fmt.Sprintf("/api/v1/apps"), nil)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
func (d appDAO) Run(id interface{}) ([]*types.App, error) {
|
||||||
|
ret := make([]*types.App, 0)
|
||||||
|
err := HttpDoJson(&ret, http.MethodGet, Addr()+fmt.Sprintf("/api/v1/app/run/%v", id), nil)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var AppDAO appDAO
|
|
@ -0,0 +1,89 @@
|
||||||
|
package replay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/api"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/types"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *api.Cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) HttpCli() *api.Cli {
|
||||||
|
return c.cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) OpenApp(id uint) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/api/v1/app/run/%d", id), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ConfigGet(k string) (ret string, err error) {
|
||||||
|
err = c.cli.HttpJsonGet("/api/v1/config/byrepo/"+util.Repo()+"/"+k, &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ConfigGetAll() (ret []types.Config, err error) {
|
||||||
|
ret = make([]types.Config, 0)
|
||||||
|
err = c.cli.HttpJsonGet("/api/v1/config/byrepo/"+util.Repo(), &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) CronReload() error {
|
||||||
|
return c.cli.HttpJsonGet("/ipc/cron/reload", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) Exit() error {
|
||||||
|
err := c.cli.HttpJsonGet("/api/v1/exit", nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) MenuGetAllEnabled() (ret []types.Menu, err error) {
|
||||||
|
ret = make([]types.Menu, 0)
|
||||||
|
err = c.cli.HttpJsonGet("/api/v1/menu/enabled", nil)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) QueueAdd(job string, bs []byte) error {
|
||||||
|
return c.cli.HttpJsonGet("/api/v1/queue/add/"+job, bs)
|
||||||
|
}
|
||||||
|
func (c *Cli) QueueGetData(id string) (ret []byte, err error) {
|
||||||
|
ret, err = c.cli.HttpRawGet("/api/v1/queue/getrequest/" + id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (c *Cli) QueueGetMyData() ([]byte, error) {
|
||||||
|
return c.QueueGetData(os.Getenv("REPLAY_QUEUEID"))
|
||||||
|
}
|
||||||
|
func (c *Cli) QueueAbort() error {
|
||||||
|
return c.cli.HttpJsonGet("/api/v1/queue/abort", nil)
|
||||||
|
}
|
||||||
|
func (c *Cli) QueueEnqueue(id uint) error {
|
||||||
|
return c.cli.HttpJsonGet(fmt.Sprintf("/api/v1/robots/op/enqueue/%d", id), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ServiceStopAll() error {
|
||||||
|
return c.cli.HttpJsonGet("/api/v1/service/op/stopall", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SQLReturn struct {
|
||||||
|
Data []map[string]interface{} `json:"data"`
|
||||||
|
Err string `json:"err"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) SQL(s string) (*SQLReturn, error) {
|
||||||
|
in := &struct {
|
||||||
|
Sql string `json:"sql"`
|
||||||
|
}{s}
|
||||||
|
out := &SQLReturn{}
|
||||||
|
err := c.cli.HttpJsonPost("/api/v1/sql", in, &out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
ret := &Cli{cli: api.NewCli()}
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package wingui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cli struct {
|
||||||
|
cli *api.Cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) HttpCli() *api.Cli {
|
||||||
|
return c.cli
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ClipRead() (string, error) {
|
||||||
|
ret := ""
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/clip/read"), &ret)
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ClipWrite(site string) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/clip/write?str=%s", site), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) MouseClick() error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/mouse/click"), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) MouseMove(x, y int) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/mouse/move?x=%d&y=%d", x, y), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) MouseMoveRelative(x, y int) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/mouse/moverelative?x=%d&y=%d", x, y), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) MouseClickRelative(x, y int) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/mouse/clickatrelative?x=%d&y=%d", x, y), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) MouseClickAt(x, y int) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/mouse/clickat?x=%d&y=%d", x, y), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) ScreenClick(f string) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/click?f=%s", f), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) ScreenClickCenter(f string) error {
|
||||||
|
err := c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/clickcenter?f=%s", f), nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
func (c *Cli) ScreenFind(f string) (ret map[string]interface{}, err error) {
|
||||||
|
ret = make(map[string]interface{})
|
||||||
|
err = c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/find?f=%s", f), &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cli) ScreenWait(f string, m int) (ret map[string]interface{}, err error) {
|
||||||
|
ret = make(map[string]interface{})
|
||||||
|
err = c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/wait?f=%s&m=%d", f, m), &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (c *Cli) ScreenWaitClick(f string, m int) (ret map[string]interface{}, err error) {
|
||||||
|
ret = make(map[string]interface{})
|
||||||
|
err = c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/waitclick?f=%s&m=%d", f, m), &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (c *Cli) ScreenWaitClickCenter(f string, m int) (ret map[string]interface{}, err error) {
|
||||||
|
ret = make(map[string]interface{})
|
||||||
|
err = c.cli.HttpJsonGet(fmt.Sprintf("/ipc/wingui/screen/waitclickcenter?f=%s&m=%d", f, m), &ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli() *Cli {
|
||||||
|
ret := &Cli{cli: api.NewCli()}
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package constants
|
||||||
|
|
||||||
|
const (
|
||||||
|
FEATURE_ROBOT = "robot"
|
||||||
|
FEATURE_SERVICE = "service"
|
||||||
|
FEATURE_APP = "app"
|
||||||
|
FEATURE_RUNTIME = "runtime"
|
||||||
|
RUNNER_BIN = "bin"
|
||||||
|
RUNNER_PYTHON = "python"
|
||||||
|
RUNNER_SHELL = "shell"
|
||||||
|
ENV_ROOT = "ROOT"
|
||||||
|
ENV_IPC = "IPC"
|
||||||
|
ENV_ROOTPID = "ROOT_PID"
|
||||||
|
ENV_ADDR = "ADDR"
|
||||||
|
ENV_LISTEN_ADDR = "LISTENADDR"
|
||||||
|
ENV_DUMPENV = "DUMPENV"
|
||||||
|
ENV_IPC_TCP = "IPC_TCP"
|
||||||
|
ENV_LOG = "LOG"
|
||||||
|
ENV_DEBUG_PROTO = "DEBUG_PROTO"
|
||||||
|
ENV_PYTHON = "PYTHON"
|
||||||
|
ENV_HTTPBASE = "HTTPBASE"
|
||||||
|
ENV_STRAWID = "STRAWID"
|
||||||
|
|
||||||
|
IPC_CORE = "core"
|
||||||
|
IPC_SVC_CLIP = "clip"
|
||||||
|
IPC_STATIC = "static"
|
||||||
|
IPC_DB = "db"
|
||||||
|
IPC_NOTIFY = "notify"
|
||||||
|
|
||||||
|
IPC_CORE_reg = "reg"
|
||||||
|
IPC_CORE_regs = "regs"
|
||||||
|
IPC_CORE_unreg = "unreg"
|
||||||
|
IPC_CORE_db_ConfigGet = "db.ConfigGet"
|
||||||
|
IPC_CORE_db_MenuGet = "db.MenuGet"
|
||||||
|
IPC_CORE_db_QueueAdd = "db.QueueAdd"
|
||||||
|
|
||||||
|
BASE_URL = "BASE_URL"
|
||||||
|
ADDR = "ADDR"
|
||||||
|
PYTHON = "PYTHON"
|
||||||
|
SHELL = "SHELL"
|
||||||
|
ROOT = "ROOT"
|
||||||
|
LOGGING = "LOGGING"
|
||||||
|
RESTART = "RESTART"
|
||||||
|
CHECK_URL = "CHECK_URL"
|
||||||
|
ROBOT_ID = "ROBOT_ID"
|
||||||
|
OWNER = "OWNER"
|
||||||
|
SHOWCONSOLE = "SHOWCONSOLE"
|
||||||
|
UID = "UID"
|
||||||
|
VSCODE = "VSCODE"
|
||||||
|
SCRIPTS_ROOT = "SCRIPTS_ROOT"
|
||||||
|
REPOS_ROOT = "REPOS_ROOT"
|
||||||
|
STATIC_ROOT = "STATIC_ROOT"
|
||||||
|
AUTO_OPEN_CONSOLE = "AUTO_OPEN_CONSOLE"
|
||||||
|
NOTIFY_ON_OPEN = "NOTIFY_ON_OPEN"
|
||||||
|
USE_TRAY = "USE_TRAY"
|
||||||
|
TEMP = "TEMP"
|
||||||
|
WORKINGIR = "WORKINGIR"
|
||||||
|
ADDONS_DIR = "ADDONS_DIR"
|
||||||
|
CHANNEL = "CHANNEL"
|
||||||
|
|
||||||
|
API_VERCHECK = "/api/vercheck"
|
||||||
|
API_VERGET = "/api/verget"
|
||||||
|
|
||||||
|
EVT_TYPE_JOBSTART = "jobstart"
|
||||||
|
EVT_TYPE_JOBFINISH = "jobfinish"
|
||||||
|
EVT_TYPE_APPSTART = "appstart"
|
||||||
|
EVT_TYPE_APPFINISH = "appfinish"
|
||||||
|
|
||||||
|
ENV_REPLAY_INSTANCE_ALIAS = "REPLAY_INSTANCE_ALIAS"
|
||||||
|
ENV_ROOT_PID = "ROOT_PID"
|
||||||
|
ENV_REPLAY_ADDR = "REPLAY_ADDR"
|
||||||
|
ENV_REPLAY_DATADIR = "REPLAY_DATADIR"
|
||||||
|
ENV_REPLAY_REPO = "REPLAY_REPO"
|
||||||
|
ENV_REPLAY_APIKEY = "REPLAY_APIKEY"
|
||||||
|
ENV_REPLAY_ALIAS = "REPLAY_ALIAS"
|
||||||
|
ENV_REPLAY_VER = "REPLAY_VER"
|
||||||
|
ENV_REPLAY_QUEUEID = "REPLAY_QUEUEID"
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package errmgr
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
func Report(err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
module go.digitalcircle.com.br/open/replaycli-go
|
||||||
|
|
||||||
|
go 1.17
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Microsoft/go-winio v0.5.0
|
||||||
|
github.com/gorilla/websocket v1.4.2
|
||||||
|
github.com/mitchellh/go-ps v1.0.0
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,17 @@
|
||||||
|
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||||
|
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210921065528-437939a70204 h1:JJhkWtBuTQKyz2bd5WG9H8iUsJRU3En/KRfN8B2RnDs=
|
||||||
|
golang.org/x/sys v0.0.0-20210921065528-437939a70204/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
@ -0,0 +1,94 @@
|
||||||
|
package ipcmux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ENV_IPC = "IPC"
|
||||||
|
ENV_ROOTPID = "ROOT_PID"
|
||||||
|
)
|
||||||
|
|
||||||
|
var listenNet func(path string) (net.Listener, error)
|
||||||
|
|
||||||
|
var dialNet func(path string) (net.Conn, error)
|
||||||
|
|
||||||
|
func Dial(p string) (net.Conn, error) {
|
||||||
|
return dialNet(p)
|
||||||
|
}
|
||||||
|
func SetName(n string) {
|
||||||
|
os.Setenv(ENV_IPC, n)
|
||||||
|
}
|
||||||
|
func ResolveBinName() string {
|
||||||
|
|
||||||
|
bin := os.Getenv(ENV_IPC)
|
||||||
|
if bin == "" {
|
||||||
|
bin = os.Args[0]
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
bin = strings.Replace(bin, "\\", "/", -1)
|
||||||
|
}
|
||||||
|
parts := strings.Split(bin, "/")
|
||||||
|
bin = parts[len(parts)-1]
|
||||||
|
bin = strings.Replace(bin, ".exe", "", 1)
|
||||||
|
log.Printf("No IPC env var found, using %s to bind ipc", bin)
|
||||||
|
}
|
||||||
|
return bin
|
||||||
|
}
|
||||||
|
|
||||||
|
func Listen(p string) (net.Listener, error) {
|
||||||
|
log.Printf("IPC:: Will listen on: [%s]", p)
|
||||||
|
return listenNet(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient() *http.Client {
|
||||||
|
ret := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
DialContext: func(_ context.Context, _, b string) (net.Conn, error) {
|
||||||
|
ps := strings.Split(b, ":")
|
||||||
|
return dialNet(ps[0])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func Serve(mux *http.ServeMux) error {
|
||||||
|
go CheckRoot()
|
||||||
|
|
||||||
|
bin := ResolveBinName()
|
||||||
|
|
||||||
|
l, err := Listen(bin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
server := http.Server{
|
||||||
|
Handler: mux,
|
||||||
|
}
|
||||||
|
err = server.Serve(l)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServeNamed(n string, mux *http.ServeMux) error {
|
||||||
|
go CheckRoot()
|
||||||
|
|
||||||
|
l, err := Listen(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
server := http.Server{
|
||||||
|
Handler: mux,
|
||||||
|
}
|
||||||
|
err = server.Serve(l)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServeDefault() error {
|
||||||
|
return Serve(http.DefaultServeMux)
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package ipcmux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/go-ps"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
libpath "path"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
listenNet = func(path string) (net.Listener, error) {
|
||||||
|
ipc_root := os.Getenv("IPC_ROOT")
|
||||||
|
if ipc_root == "" {
|
||||||
|
ipc_root = os.TempDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
path = "replayme_" + path
|
||||||
|
path = libpath.Join(ipc_root, path)
|
||||||
|
err := os.Remove(path)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
log.Printf("Err removing old uds: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l, err := net.Listen("unix", path)
|
||||||
|
log.Printf("UnixSocket::%s=>%v", path, err)
|
||||||
|
return l, err
|
||||||
|
|
||||||
|
}
|
||||||
|
dialNet = func(path string) (net.Conn, error) {
|
||||||
|
ipc_root := os.Getenv("IPC_ROOT")
|
||||||
|
if ipc_root == "" {
|
||||||
|
ipc_root = os.TempDir()
|
||||||
|
}
|
||||||
|
path = "replayme_" + path
|
||||||
|
path = libpath.Join(ipc_root, path)
|
||||||
|
conn, err := net.Dial("unix", path)
|
||||||
|
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
PRCTL_SYSCALL = 157
|
||||||
|
PR_SET_PDEATHSIG = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func CheckRoot() {
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
rootpid := os.Getenv(ENV_ROOTPID)
|
||||||
|
rootpidi, err := strconv.Atoi(rootpid)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("No root process found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rootpidi == 0 || rootpidi == os.Getpid() {
|
||||||
|
log.Printf("%s is set to zero, no monitoring on root will take place", ENV_ROOTPID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
p, err := ps.FindProcess(rootpidi)
|
||||||
|
if p == nil || err != nil {
|
||||||
|
log.Printf("aborting")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package ipcmux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
listenNet = func(path string) (net.Listener, error) {
|
||||||
|
path = strings.Replace(path, "/", "\\", -1)
|
||||||
|
log.Printf("Listening to: " + path)
|
||||||
|
|
||||||
|
chcon := make(chan bool)
|
||||||
|
var conn net.Listener
|
||||||
|
var err error
|
||||||
|
go func() {
|
||||||
|
path = "\\\\.\\pipe\\" + path
|
||||||
|
conn, err = winio.ListenPipe(path, &winio.PipeConfig{
|
||||||
|
SecurityDescriptor: "",
|
||||||
|
MessageMode: false,
|
||||||
|
InputBufferSize: 0,
|
||||||
|
OutputBufferSize: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ipcmux::listenNet: %s", err.Error())
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
go func() {
|
||||||
|
to := time.Second * time.Duration(3)
|
||||||
|
fconn, err := winio.DialPipe(path, &to)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error on pipe warm up: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
fconn.Close()
|
||||||
|
}
|
||||||
|
log.Printf("Pipe warm up done")
|
||||||
|
}()
|
||||||
|
}()
|
||||||
|
chcon <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-chcon:
|
||||||
|
return conn, err
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
err = errors.New("Timeout exceeded for Listening: " + path)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
dialNet = func(path string) (net.Conn, error) {
|
||||||
|
path = strings.Replace(path, "/", "\\", -1)
|
||||||
|
path = "\\\\.\\pipe\\" + path
|
||||||
|
chcon := make(chan bool)
|
||||||
|
var conn net.Conn
|
||||||
|
var err error
|
||||||
|
//Log("Dialing to: " + path)
|
||||||
|
go func() {
|
||||||
|
to := time.Second * time.Duration(15)
|
||||||
|
conn, err = winio.DialPipe(path, &to)
|
||||||
|
//conn, err = npipe.Dial(path)
|
||||||
|
chcon <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-chcon:
|
||||||
|
return conn, err
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
err = errors.New("Timeout exceeded for conn: " + path)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckRoot() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
rootpid := os.Getenv(ENV_ROOTPID)
|
||||||
|
rootpidi, err := strconv.Atoi(rootpid)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("No root process found")
|
||||||
|
}
|
||||||
|
if rootpidi == 0 || rootpidi == os.Getpid() {
|
||||||
|
log.Printf("%s is set to zero, no monitoring on root will take place", ENV_ROOTPID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := os.FindProcess(rootpidi)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error finding process: %s", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if p == nil {
|
||||||
|
log.Printf("Process not found.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
_, err = p.Wait()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(err.Error())
|
||||||
|
}
|
||||||
|
log.Printf("Parent process %s is gone. Finishing here.", os.Getenv(ENV_ROOTPID))
|
||||||
|
os.Exit(0)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package pubsub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/ipcmux"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const XMSGTYPE = "X-MSGTYPE"
|
||||||
|
const XPUBSUBID = "X-PUBSUBID"
|
||||||
|
|
||||||
|
var PSID = ""
|
||||||
|
var dialer *websocket.Dialer
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dialer = &websocket.Dialer{}
|
||||||
|
hname, _ := os.Hostname()
|
||||||
|
pid := os.Getppid()
|
||||||
|
u, _ := user.Current()
|
||||||
|
PSID = fmt.Sprintf("psid_%s_%s_%d", hname, u.Username, pid)
|
||||||
|
|
||||||
|
dialer.NetDial = func(network, addr string) (net.Conn, error) {
|
||||||
|
ps := strings.Split(addr, ":")
|
||||||
|
c, err := ipcmux.Dial(ps[0])
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PSCli struct {
|
||||||
|
q string
|
||||||
|
con *websocket.Conn
|
||||||
|
ch chan []byte
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PSCli) GetConn() *websocket.Conn {
|
||||||
|
if p.con == nil {
|
||||||
|
|
||||||
|
var counter = 0
|
||||||
|
for counter < 100 {
|
||||||
|
con, _, err := dialer.Dial("ws://pubsub/?q="+p.q, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error connecting WS: %s", err.Error())
|
||||||
|
counter++
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.con = con
|
||||||
|
p.con.SetCloseHandler(func(code int, text string) error {
|
||||||
|
log.Printf("Connection closed: %d: %s", code, text)
|
||||||
|
p.con = nil
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return p.con
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PSCli) Send(i interface{}) error {
|
||||||
|
bs, err := json.Marshal(i)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = p.GetConn().WriteMessage(websocket.TextMessage, bs)
|
||||||
|
if err != nil {
|
||||||
|
p.con.Close()
|
||||||
|
p.con = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PSCli) Chan() chan []byte {
|
||||||
|
return p.ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PSCli) Read(i interface{}) error {
|
||||||
|
_, bs, err := p.GetConn().ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
if p.con != nil {
|
||||||
|
p.con.Close()
|
||||||
|
p.con = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(bs, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCli(q string) (*PSCli, error) {
|
||||||
|
ret := &PSCli{}
|
||||||
|
ret.q = q
|
||||||
|
return ret, nil
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package static
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/ipcmux"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var builtinMimeTypesLower = map[string]string{
|
||||||
|
".css": "text/css; charset=utf-8",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".htm": "text/html; charset=utf-8",
|
||||||
|
".html": "text/html; charset=utf-8",
|
||||||
|
".jpg": "image/jpeg",
|
||||||
|
".js": "application/javascript",
|
||||||
|
".wasm": "application/wasm",
|
||||||
|
".pdf": "application/pdf",
|
||||||
|
".png": "image/png",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".xml": "text/xml; charset=utf-8",
|
||||||
|
}
|
||||||
|
|
||||||
|
func Mime(ext string) string {
|
||||||
|
if v, ok := builtinMimeTypesLower[ext]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return mime.TypeByExtension(ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServeParse() {
|
||||||
|
addr := flag.String("ipc", "samplestatic", "IPC Addr")
|
||||||
|
root := flag.String("root", ".", "Root dir")
|
||||||
|
flag.Parse()
|
||||||
|
Serve(*addr, *root)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Serve(addr string, root string) {
|
||||||
|
|
||||||
|
ipcmux.SetName(addr)
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
path := strings.Split(r.URL.Path, "?")[0]
|
||||||
|
if path == "" {
|
||||||
|
path = "index.html"
|
||||||
|
}
|
||||||
|
ext := filepath.Ext(path)
|
||||||
|
|
||||||
|
bs, err := os.ReadFile(filepath.Join(root, path))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", Mime(ext))
|
||||||
|
|
||||||
|
w.Write(bs)
|
||||||
|
})
|
||||||
|
ipcmux.ServeDefault()
|
||||||
|
}
|
|
@ -0,0 +1,349 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//region AUTH
|
||||||
|
|
||||||
|
type SecUser struct {
|
||||||
|
Model
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Groups []*SecGroup `json:"groups" gorm:"many2many:sec_user_groups;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecGroup struct {
|
||||||
|
Model
|
||||||
|
Code string `json:"code"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
//Users []*SecUser `json:"users" gorm:"many2many:sec_user_groups;"`
|
||||||
|
Perms []*SecPerm `json:"perms" gorm:"many2many:sec_group_perms;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecPerm struct {
|
||||||
|
Model
|
||||||
|
Code string `json:"code"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
//Groups []*SecGroup `json:"groups" gorm:"many2many:group_perms;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
Model
|
||||||
|
Username string
|
||||||
|
SessionID string
|
||||||
|
Perms string
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion AUTH
|
||||||
|
|
||||||
|
type Feature struct {
|
||||||
|
Model
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Desc string `json:"desc" yaml:"desc"`
|
||||||
|
Repo uint `json:"repo"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Robot struct {
|
||||||
|
Feature
|
||||||
|
}
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Feature
|
||||||
|
IsNative *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Feature
|
||||||
|
Ipcid string `json:"ipcid"`
|
||||||
|
Env string `json:"env" yaml:"env"`
|
||||||
|
Enabled *bool `yaml:"enabled" json:"enabled"`
|
||||||
|
Image string `yaml:"image" json:"image"`
|
||||||
|
Delay int `yaml:"delay" json:"delay"`
|
||||||
|
Pid int `json:"pid" yaml:"-"`
|
||||||
|
Hostname string `json:"hostname" yaml:"hostname"`
|
||||||
|
Gui bool `json:"gui" yaml:"gui"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Runtime struct {
|
||||||
|
Feature
|
||||||
|
Path string `json:"path" yaml:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repo struct {
|
||||||
|
Model
|
||||||
|
Feature string `json:"feature" yaml:"feature"`
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Url string `json:"repo"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
Cred uint `json:"cred"`
|
||||||
|
LocalDir string `json:"local_dir"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReplayDescriptor struct {
|
||||||
|
Feature string `json:"feature" yaml:"feature"`
|
||||||
|
ReplayID string `json:"replay_id" yaml:"replay_id"`
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Desc string `json:"desc" yaml:"desc"`
|
||||||
|
Runner string `json:"runner" yaml:"runner"`
|
||||||
|
Main string `json:"main" yaml:"main"`
|
||||||
|
Args []string `json:"args" yaml:"args"`
|
||||||
|
Env map[string]string `json:"env" yaml:"env"`
|
||||||
|
InstallScript string `json:"install_script" yaml:"install_script"`
|
||||||
|
UninstallScript string `json:"uninstall_script" yaml:"uninstall_script"`
|
||||||
|
AbortScript string `json:"abort_script" yaml:"abort_script"`
|
||||||
|
Id string `json:"id" yaml:"-"`
|
||||||
|
LocalDir string `json:"local_dir" yaml:"-"`
|
||||||
|
RepoID uint `json:"repo_id" yaml:"-"`
|
||||||
|
QueueID uint `json:"queue_id" yaml:"-"`
|
||||||
|
Config map[string]string `json:"config" yaml:"config"`
|
||||||
|
Alias string `json:"alias" yaml:"alias"`
|
||||||
|
Autostart bool `json:"autostart" yaml:"autostart"`
|
||||||
|
Hostname string `json:"hostname" yaml:"hostname"`
|
||||||
|
Ipcid string `json:"ipcid"`
|
||||||
|
Gui bool `json:"gui" yaml:"gui"`
|
||||||
|
Link string `json:"link" yaml:"link"` //This prop allows redirect of repos
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyRequest struct {
|
||||||
|
Title string
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
ID uint `gorm:"primarykey" json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//type Model simpledb.SimplePersistent
|
||||||
|
|
||||||
|
type Menu struct {
|
||||||
|
Model
|
||||||
|
Name string `json:"name"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Tooltip string `json:"tooltip"`
|
||||||
|
Target string `json:"target"`
|
||||||
|
Index int `json:"index" gorm:"column:menuindex"`
|
||||||
|
Enabled *bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Model
|
||||||
|
K string `json:"k"`
|
||||||
|
V string `json:"v"`
|
||||||
|
T string `json:"t"`
|
||||||
|
Repo uint `json:"repo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Credentials struct {
|
||||||
|
Model
|
||||||
|
Name string `json:"name"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Sshkey string `json:"sshkey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Log struct {
|
||||||
|
Model
|
||||||
|
Log []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
Model
|
||||||
|
Name string `json:"name"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
File string `json:"file"`
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
Model
|
||||||
|
From string `json:"from"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
Enabled *bool `json:"enabled"`
|
||||||
|
Index string `json:"index"`
|
||||||
|
HeadersJson string `json:"headers_json"`
|
||||||
|
Permissions string `json:"permissions"`
|
||||||
|
PermArr []string `json:"-" gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Queue struct {
|
||||||
|
Model
|
||||||
|
Job uint `json:"job"`
|
||||||
|
Ready bool `json:"ready"`
|
||||||
|
Processed bool `json:"processed"`
|
||||||
|
ProcessedAt time.Time `json:"processed_at"`
|
||||||
|
Request []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
//type QueueData struct {
|
||||||
|
// Model
|
||||||
|
// Qid uint
|
||||||
|
// Request []byte
|
||||||
|
//}
|
||||||
|
|
||||||
|
type CryptoKey struct {
|
||||||
|
Model
|
||||||
|
Defkey bool
|
||||||
|
Name string
|
||||||
|
Pub []byte
|
||||||
|
Priv []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//type Version struct {
|
||||||
|
// Model
|
||||||
|
// Job string `json:"job"`
|
||||||
|
// Ver string `json:"ver"`
|
||||||
|
// Notes string `json:"notes"`
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//type VersionData struct {
|
||||||
|
// Model
|
||||||
|
// Vid uint `json:"vid"`
|
||||||
|
// Data []byte `json:"data"`
|
||||||
|
//}
|
||||||
|
|
||||||
|
type Cron struct {
|
||||||
|
Model
|
||||||
|
Cron string `json:"cron"`
|
||||||
|
JobCode uint `json:"job"`
|
||||||
|
Enabled *bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//type Resource struct {
|
||||||
|
// Model
|
||||||
|
// Name string `json:"name"`
|
||||||
|
// Mime string `json:"mime"`
|
||||||
|
// Len int `json:"len"`
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//type ResourceContent struct {
|
||||||
|
// Model
|
||||||
|
// Resid uint `json:"resid"`
|
||||||
|
// Content []byte `json:"content"`
|
||||||
|
//}
|
||||||
|
|
||||||
|
type License struct {
|
||||||
|
Model
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
RobotID string `json:"robot_id"`
|
||||||
|
MachineID string `json:"machine_id"`
|
||||||
|
UID string `json:"uid"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KV struct {
|
||||||
|
ID string `gorm:"primarykey" json:"id"`
|
||||||
|
V string `json:"v"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@API
|
||||||
|
*/
|
||||||
|
type VerCheckRequest struct {
|
||||||
|
Chan string `json:"chan"`
|
||||||
|
Os string `json:"os"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Data map[string]string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@API
|
||||||
|
*/
|
||||||
|
type VerCheckResponse struct {
|
||||||
|
Data map[string]string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@API
|
||||||
|
*/
|
||||||
|
type VerGetRequest struct {
|
||||||
|
Os string `json:"os"`
|
||||||
|
Chan string `json:"chan"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@API
|
||||||
|
*/
|
||||||
|
type VerGetResponse struct {
|
||||||
|
Data []byte `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SQLRequest struct {
|
||||||
|
Sql string `json:"sql"`
|
||||||
|
}
|
||||||
|
type SQLResponse struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
Err string `json:"err"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecUserChOwnPassRequest struct {
|
||||||
|
Oldpass string `json:"oldpass"`
|
||||||
|
Newpass string `json:"newpass"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginRequest struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecipeItem struct {
|
||||||
|
Url string `json:"url" yaml:"url"`
|
||||||
|
User string `json:"user" yaml:"user"`
|
||||||
|
Password string `json:"password" yaml:"password"`
|
||||||
|
Sshkey string `json:"sshkey" yaml:"sshkey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Recipe struct {
|
||||||
|
User string `json:"user" yaml:"user"`
|
||||||
|
Password string `json:"password" yaml:"password"`
|
||||||
|
Sshkey string `json:"sshkey" yaml:"sshkey"`
|
||||||
|
LicUser string `json:"licuser" yaml:"licuser"`
|
||||||
|
License string `json:"license" yaml:"license"`
|
||||||
|
Alias string `json:"alias" yaml:"alias"`
|
||||||
|
Items []RecipeItem `json:"items" yaml:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PubSubMsg struct {
|
||||||
|
Msg string
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PubSubMsgRunnerFinishData struct {
|
||||||
|
Err error
|
||||||
|
Desc *ReplayDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
type Series struct {
|
||||||
|
Serie string `json:"serie"`
|
||||||
|
When time.Time `json:"when"`
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
Sec int `json:"sec"`
|
||||||
|
Min int `json:"min"`
|
||||||
|
Hour int `json:"hour"`
|
||||||
|
Day int `json:"day"`
|
||||||
|
Month int `json:"month"`
|
||||||
|
Year int `json:"year"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Series) SetTime(t time.Time) {
|
||||||
|
s.When = t
|
||||||
|
s.Day = t.Day()
|
||||||
|
s.Hour = t.Hour()
|
||||||
|
s.Min = t.Minute()
|
||||||
|
s.Sec = t.Second()
|
||||||
|
s.Month = int(t.Month())
|
||||||
|
s.Year = t.Year()
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.digitalcircle.com.br/open/replaycli-go/constants"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var apikey string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
apikey = os.Getenv("REPLAY_APIKEY")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Addr() string {
|
||||||
|
ret := os.Getenv("REPLAY_ADDR")
|
||||||
|
if ret == "" {
|
||||||
|
ret = "http://localhost:8080"
|
||||||
|
} else if strings.HasPrefix(ret, ":") {
|
||||||
|
ret = "http://localhost" + ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func DataDir() string {
|
||||||
|
ret := os.Getenv(constants.ENV_REPLAY_DATADIR)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func Repo() string {
|
||||||
|
repo := os.Getenv("REPLAY_REPO")
|
||||||
|
if repo == "" {
|
||||||
|
path, _ := os.Getwd()
|
||||||
|
path = strings.Replace(path, "\\", "/", -1)
|
||||||
|
pathparts := strings.Split(path, "/")
|
||||||
|
repo = pathparts[len(pathparts)-1]
|
||||||
|
|
||||||
|
}
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//func HttpDo(method string, strurl string, body []byte) (*http.Response, error) {
|
||||||
|
// cli := http.Client{}
|
||||||
|
// var err error
|
||||||
|
// var req *http.Request
|
||||||
|
//
|
||||||
|
// if body != nil && len(body) > 0 {
|
||||||
|
// req, err = http.NewRequest(method, strurl, io.NopCloser(bytes.NewReader(body)))
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// req, err = http.NewRequest(method, strurl, nil)
|
||||||
|
// }
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// req.Header.Set("X-API-KEY", apikey)
|
||||||
|
// req.Header.Set("Content-Type", "application/json")
|
||||||
|
// return cli.Do(req)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func HttpDoJson(i interface{}, method string, strurl string, body []byte) (err error) {
|
||||||
|
// res, err := HttpDo(method, strurl, body)
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// err = json.NewDecoder(res.Body).Decode(i)
|
||||||
|
// return
|
||||||
|
//}
|
Loading…
Reference in New Issue