2022-12-13 22:25:28 +11:00

309 lines
6.0 KiB
Go

package api
import (
"GoSungrow/iSolarCloud/api/GoStruct"
"GoSungrow/iSolarCloud/api/GoStruct/output"
"github.com/MickMake/GoUnify/Only"
"github.com/MickMake/GoUnify/cmdPath"
"io"
"path/filepath"
"time"
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
)
type Web struct {
ServerUrl EndPointUrl
Body []byte
Error error
cacheDir string
cacheTimeout time.Duration
retry int
client http.Client
httpRequest *http.Request
httpResponse *http.Response
}
func (w *Web) SetUrl(u string) error {
w.ServerUrl = SetUrl(u)
return w.Error
}
func (w *Web) AppendUrl(endpoint string) EndPointUrl {
return w.ServerUrl.AppendPath(endpoint)
}
func (w *Web) Get(endpoint EndPoint) EndPoint {
for range Only.Once {
w.Error = w.ServerUrl.IsValid()
if w.Error != nil {
w.Error = errors.New("Sungrow API EndPoint not yet implemented")
fmt.Println(w.Error)
break
}
isCached := false
if w.WebCacheCheck(endpoint) {
isCached = true
}
if isCached {
w.Body, w.Error = w.WebCacheRead(endpoint)
if w.Error != nil {
break
}
} else {
w.Body, w.Error = w.getApi(endpoint)
if w.Error != nil {
break
}
}
if len(w.Body) == 0 {
w.Error = errors.New("empty http response")
break
}
endpoint = endpoint.SetResponse(w.Body)
if endpoint.GetError() != nil {
w.Error = endpoint.GetError()
break
}
w.Error = endpoint.IsResponseValid()
if w.Error != nil {
_ = w.WebCacheRemove(endpoint)
// fmt.Printf("ERROR: Body is:\n%s\n", w.Body)
break
}
if isCached {
// Do nothing.
} else {
w.Error = w.WebCacheWrite(endpoint, w.Body)
if w.Error != nil {
break
}
}
}
if w.Error != nil {
endpoint = endpoint.SetError("%s", w.Error)
}
return endpoint
}
func (w *Web) getApi(endpoint EndPoint) ([]byte, error) {
for range Only.Once {
request := endpoint.RequestRef()
w.Error = GoStruct.VerifyOptionsRequired(request)
if w.Error != nil {
break
}
w.Error = endpoint.IsRequestValid()
if w.Error != nil {
break
}
u := endpoint.GetUrl()
w.Error = u.IsValid()
if w.Error != nil {
break
}
postUrl := w.ServerUrl.AppendPath(u.String()).String()
var j []byte
j, w.Error = json.Marshal(request)
if w.Error != nil {
break
}
w.httpResponse, w.Error = http.Post(postUrl, "application/json", bytes.NewBuffer(j))
if w.Error != nil {
break
}
if w.httpResponse.StatusCode == 401 {
w.Error = errors.New(w.httpResponse.Status)
break
}
//goland:noinspection GoUnhandledErrorResult,GoDeferInLoop
defer w.httpResponse.Body.Close()
if w.Error != nil {
break
}
if w.httpResponse.StatusCode != 200 {
w.Error = errors.New(fmt.Sprintf("API httpResponse is %s", w.httpResponse.Status))
break
}
w.Body, w.Error = io.ReadAll(w.httpResponse.Body)
if w.Error != nil {
break
}
}
return w.Body, w.Error
}
func (w *Web) SetCacheDir(basedir string) error {
for range Only.Once {
w.cacheDir = filepath.Join(basedir)
p := cmdPath.NewPath(basedir)
if p.DirExists() {
break
}
w.Error = p.MkdirAll()
if w.Error != nil {
break
}
// _, w.Error = os.Stat(w.cacheDir)
// if w.Error != nil {
// if os.IsNotExist(w.Error) {
// w.Error = nil
// }
// break
// }
//
// w.Error = os.MkdirAll(w.cacheDir, 0700)
// if w.Error != nil {
// break
// }
}
return w.Error
}
func (w *Web) GetCacheDir() string {
return w.cacheDir
}
func (w *Web) SetCacheTimeout(duration time.Duration) {
w.cacheTimeout = duration
}
func (w *Web) GetCacheTimeout() time.Duration {
return w.cacheTimeout
}
// WebCacheCheck Retrieves cache data from a local file.
func (w *Web) WebCacheCheck(endpoint EndPoint) bool {
var ok bool
for range Only.Once {
// fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
//
// var f os.FileInfo
// f, w.Error = os.Stat(fn)
// if w.Error != nil {
// if os.IsNotExist(w.Error) {
// w.Error = nil
// }
// break
// }
//
// if f.IsDir() {
// w.Error = errors.New("file is a directory")
// break
// }
p := cmdPath.NewPath(w.cacheDir, endpoint.CacheFilename())
if p.DirExists() {
w.Error = errors.New("file is a directory")
ok = false
break
}
if !p.FileExists() {
ok = false
break
}
duration := w.GetCacheTimeout()
then := p.ModTime()
then = then.Add(duration)
now := time.Now()
if then.Before(now) {
ok = false
break
}
ok = true
}
return ok
}
// WebCacheRead Retrieves cache data from a local file.
func (w *Web) WebCacheRead(endpoint EndPoint) ([]byte, error) {
fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
return output.PlainFileRead(fn)
}
// WebCacheRemove Removes a cache file.
func (w *Web) WebCacheRemove(endpoint EndPoint) error {
fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
return output.FileRemove(fn)
}
// WebCacheWrite Saves cache data to a file path.
func (w *Web) WebCacheWrite(endpoint EndPoint, data []byte) error {
fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
return output.PlainFileWrite(fn, data, output.DefaultFileMode)
}
// PointCacheCheck Retrieves cache data from a local file.
func (w *Web) PointCacheCheck(data DataMap) bool {
var ok bool
for range Only.Once {
p := cmdPath.NewPath(w.cacheDir, "Points.json")
if p.DirExists() {
w.Error = errors.New("file is a directory")
ok = false
break
}
if p.FileExists() {
ok = true
break
}
duration := w.GetCacheTimeout()
then := p.ModTime()
then = then.Add(duration)
now := time.Now()
if then.Before(now) {
break
}
ok = true
}
return ok
}
// PointCacheRead Retrieves cache data from a local file.
func (w *Web) PointCacheRead(endpoint EndPoint) ([]byte, error) {
fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
return output.PlainFileRead(fn)
}
// PointCacheWrite Saves cache data to a file path.
func (w *Web) PointCacheWrite(endpoint EndPoint, data []byte) error {
fn := filepath.Join(w.cacheDir, endpoint.CacheFilename())
return output.PlainFileWrite(fn, data, output.DefaultFileMode)
}