Feature: Data history manager engine subsystem (#693)

* Adds lovely initial concept for historical data doer

* Adds ability to save tasks. Adds config. Adds startStop to engine

* Has a database microservice without use of globals! Further infrastructure design. Adds readme

* Commentary to help design

* Adds migrations for database

* readme and adds database models

* Some modelling that doesn't work end of day

* Completes datahistoryjob sql.Begins datahistoryjobresult

* Adds datahistoryjob functions to retreive job results. Adapts subsystem

* Adds process for upserting jobs and job results to the database

* Broken end of day weird sqlboiler crap

* Fixes issue with SQL generation.

* RPC generation and addition of basic upsert command

* Renames types

* Adds rpc functions

* quick commit before context swithc. Exchanges aren't being populated

* Begin the tests!

* complete sql tests. stop failed jobs. CLI command creation

* Defines rpc commands

* Fleshes out RPC implementation

* Expands testing

* Expands testing, removes double remove

* Adds coverage of data history subsystem, expands errors and nil checks

* Minor logic improvement

* streamlines datahistory test setup

* End of day minor linting

* Lint, convert simplify, rpc expansion, type expansion, readme expansion

* Documentation update

* Renames for consistency

* Completes RPC server commands

* Fixes tests

* Speeds up testing by reducing unnecessary actions. Adds maxjobspercycle config

* Comments for everything

* Adds missing result string. checks interval supported. default start end cli

* Fixes ID problem. Improves binance trade fetch. job ranges are processed

* adds dbservice coverage. adds rpcserver coverage

* docs regen, uses dbcon interface, reverts binance, fixes races, toggle manager

* Speed up tests, remove bad global usage, fix uuid check

* Adds verbose. Updates docs. Fixes postgres

* Minor changes to logging and start stop

* Fixes postgres db tests, fixes postgres column typo

* Fixes old string typo,removes constraint,error parsing for nonreaders

* prevents dhm running when table doesn't exist. Adds prereq documentation

* Adds parallel, rmlines, err fix, comment fix, minor param fixes

* doc regen, common time range check and test updating

* Fixes job validation issues. Updates candle range checker.

* Ensures test cannot fail due to time.Now() shenanigans

* Fixes oopsie, adds documentation and a warn

* Fixes another time test, adjusts copy

* Drastically speeds up data history manager tests via function overrides

* Fixes summary bug and better logs

* Fixes local time test, fixes websocket tests

* removes defaults and comment,updates error messages,sets cli command args

* Fixes FTX trade processing

* Fixes issue where jobs got stuck if data wasn't returned but retrieval was successful

* Improves test speed. Simplifies trade verification SQL. Adds command help

* Fixes the oopsies

* Fixes use of query within transaction. Fixes trade err

* oopsie, not needed

* Adds missing data status. Properly ends job even when data is missing

* errors are more verbose and so have more words to describe them

* Doc regen for new status

* tiny test tinkering

* str := string("Removes .String()").String()

* Merge fixups

* Fixes a data race discovered during github actions

* Allows websocket test to pass consistently

* Fixes merge issue preventing datahistorymanager from starting via config

* Niterinos cmd defaults and explanations

* fixes default oopsie

* Fixes lack of nil protection

* Additional oopsie

* More detailed error for validating job exchange
This commit is contained in:
Scott
2021-07-01 16:21:48 +10:00
committed by GitHub
parent c109cfb6b4
commit 197ef2df21
133 changed files with 17770 additions and 1367 deletions

View File

@@ -63,6 +63,7 @@ var (
errCurrencyNotEnabled = errors.New("currency not enabled")
errCurrencyPairInvalid = errors.New("currency provided is not found in the available pairs list")
errNoTrades = errors.New("no trades returned from supplied params")
errNilRequestData = errors.New("nil request data received, cannot continue")
)
// RPCServer struct
@@ -873,8 +874,9 @@ func (s *RPCServer) GetOrders(_ context.Context, r *gctrpc.GetOrdersRequest) (*g
return nil, err
}
}
if !start.IsZero() && !end.IsZero() && start.After(end) {
return nil, errInvalidTimes
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
request := &order.GetOrdersRequest{
@@ -1513,17 +1515,20 @@ func (s *RPCServer) WithdrawalEventsByExchange(_ context.Context, r *gctrpc.With
// WithdrawalEventsByDate returns previous withdrawal request details by exchange
func (s *RPCServer) WithdrawalEventsByDate(_ context.Context, r *gctrpc.WithdrawalEventsByDateRequest) (*gctrpc.WithdrawalEventsByExchangeResponse, error) {
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
var UTCEndTime time.Time
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
var ret []*withdraw.Response
ret, err = s.WithdrawManager.WithdrawEventByDate(r.Exchange, UTCStartTime, UTCEndTime, int(r.Limit))
ret, err = s.WithdrawManager.WithdrawEventByDate(r.Exchange, start, end, int(r.Limit))
if err != nil {
return nil, err
}
@@ -1894,16 +1899,19 @@ func (s *RPCServer) GetExchangeTickerStream(r *gctrpc.GetExchangeTickerStreamReq
// GetAuditEvent returns matching audit events from database
func (s *RPCServer) GetAuditEvent(_ context.Context, r *gctrpc.GetAuditEventRequest) (*gctrpc.GetAuditEventResponse, error) {
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.StartDate)
start, err := time.Parse(common.SimpleTimeFormat, r.StartDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
end, err := time.Parse(common.SimpleTimeFormat, r.EndDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
UTCEndTime, err := time.Parse(common.SimpleTimeFormat, r.EndDate)
if err != nil {
return nil, err
}
events, err := audit.GetEvent(UTCStartTime, UTCEndTime, r.OrderBy, int(r.Limit))
events, err := audit.GetEvent(start, end, r.OrderBy, int(r.Limit))
if err != nil {
return nil, err
}
@@ -1939,19 +1947,18 @@ func (s *RPCServer) GetAuditEvent(_ context.Context, r *gctrpc.GetAuditEventRequ
// GetHistoricCandles returns historical candles for a given exchange
func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricCandlesRequest) (*gctrpc.GetHistoricCandlesResponse, error) {
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
var UTCEndTime time.Time
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, err
}
if UTCStartTime.After(UTCEndTime) || UTCStartTime.Equal(UTCEndTime) {
return nil, errInvalidTimes
}
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
@@ -1988,8 +1995,8 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
pair,
a,
interval,
UTCStartTime,
UTCEndTime)
start,
end)
if err != nil {
return nil, err
}
@@ -1997,14 +2004,14 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
if r.ExRequest {
klineItem, err = exch.GetHistoricCandlesExtended(pair,
a,
UTCStartTime,
UTCEndTime,
start,
end,
interval)
} else {
klineItem, err = exch.GetHistoricCandles(pair,
a,
UTCStartTime,
UTCEndTime,
start,
end,
interval)
}
}
@@ -2015,7 +2022,7 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
if r.FillMissingWithTrades {
var tradeDataKline *kline.Item
tradeDataKline, err = fillMissingCandlesWithStoredTrades(UTCStartTime, UTCEndTime, &klineItem)
tradeDataKline, err = fillMissingCandlesWithStoredTrades(start, end, &klineItem)
if err != nil {
return nil, err
}
@@ -2680,17 +2687,20 @@ func (s *RPCServer) GetSavedTrades(_ context.Context, r *gctrpc.GetSavedTradesRe
return nil, err
}
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
var trades []trade.Data
trades, err = trade.GetTradesInRange(r.Exchange, r.AssetType, r.Pair.Base, r.Pair.Quote, UTCStartTime, UTCEndTime)
trades, err = trade.GetTradesInRange(r.Exchange, r.AssetType, r.Pair.Base, r.Pair.Quote, start, end)
if err != nil {
return nil, err
}
@@ -2720,12 +2730,15 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
if r.End == "" || r.Start == "" || r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" || r.TimeInterval == 0 {
return nil, errInvalidArguments
}
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
var UTCEndTime time.Time
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
@@ -2747,7 +2760,7 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
}
var trades []trade.Data
trades, err = trade.GetTradesInRange(r.Exchange, r.AssetType, r.Pair.Base, r.Pair.Quote, UTCStartTime, UTCEndTime)
trades, err = trade.GetTradesInRange(r.Exchange, r.AssetType, r.Pair.Base, r.Pair.Quote, start, end)
if err != nil {
return nil, err
}
@@ -2814,12 +2827,15 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
return nil, err
}
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
@@ -2828,8 +2844,8 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
p,
a,
kline.Interval(r.Interval),
UTCStartTime,
UTCEndTime,
start,
end,
)
if err != nil {
return nil, err
@@ -2845,7 +2861,7 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
candleTimes = append(candleTimes, klineItem.Candles[i].Time)
}
var ranges []timeperiods.TimeRange
ranges, err = timeperiods.FindTimeRangesContainingData(UTCStartTime, UTCEndTime, klineItem.Interval.Duration(), candleTimes)
ranges, err = timeperiods.FindTimeRangesContainingData(start, end, klineItem.Interval.Duration(), candleTimes)
if err != nil {
return nil, err
}
@@ -2870,8 +2886,8 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
resp.Status = fmt.Sprintf("Found %v candles. Missing %v candles in requested timeframe starting %v ending %v",
foundCount,
len(resp.MissingPeriods),
UTCStartTime.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone),
UTCEndTime.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone))
start.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone),
end.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone))
}
return resp, nil
@@ -2898,22 +2914,24 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
if err != nil {
return nil, err
}
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
UTCStartTime = UTCStartTime.Truncate(time.Hour)
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return nil, err
}
UTCEndTime = UTCEndTime.Truncate(time.Hour)
start = start.Truncate(time.Hour)
end = end.Truncate(time.Hour)
intervalMap := make(map[time.Time]bool)
iterationTime := UTCStartTime
for iterationTime.Before(UTCEndTime) {
iterationTime := start
for iterationTime.Before(end) {
intervalMap[iterationTime] = false
iterationTime = iterationTime.Add(time.Hour)
}
@@ -2924,8 +2942,8 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
r.AssetType,
r.Pair.Base,
r.Pair.Quote,
UTCStartTime,
UTCEndTime,
start,
end,
)
if err != nil {
return nil, err
@@ -2941,7 +2959,7 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
tradeTimes = append(tradeTimes, trades[i].Timestamp)
}
var ranges []timeperiods.TimeRange
ranges, err = timeperiods.FindTimeRangesContainingData(UTCStartTime, UTCEndTime, time.Hour, tradeTimes)
ranges, err = timeperiods.FindTimeRangesContainingData(start, end, time.Hour, tradeTimes)
if err != nil {
return nil, err
}
@@ -2966,8 +2984,8 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
resp.Status = fmt.Sprintf("Found %v periods. Missing %v periods between %v and %v",
foundCount,
len(resp.MissingPeriods),
UTCStartTime.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone),
UTCEndTime.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone))
start.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone),
end.In(time.UTC).Format(common.SimpleTimeFormatWithTimezone))
}
return resp, nil
@@ -3009,13 +3027,15 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
return err
}
var trades []trade.Data
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
start, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return err
return fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
UTCEndTime, err = time.Parse(common.SimpleTimeFormat, r.End)
end, err := time.Parse(common.SimpleTimeFormat, r.End)
if err != nil {
return fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return err
}
@@ -3025,7 +3045,7 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
Pair: r.Pair,
}
for iterateStartTime := UTCStartTime; iterateStartTime.Before(UTCEndTime); iterateStartTime = iterateStartTime.Add(time.Hour) {
for iterateStartTime := start; iterateStartTime.Before(end); iterateStartTime = iterateStartTime.Add(time.Hour) {
iterateEndTime := iterateStartTime.Add(time.Hour)
trades, err = exch.GetHistoricTrades(cp, a, iterateStartTime, iterateEndTime)
if err != nil {
@@ -3041,7 +3061,7 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
}
for i := range trades {
tradeTS := trades[i].Timestamp.In(time.UTC)
if tradeTS.After(UTCEndTime) {
if tradeTS.After(end) {
break
}
grpcTrades.Trades = append(grpcTrades.Trades, &gctrpc.SavedTrades{
@@ -3282,3 +3302,270 @@ func parseSingleEvents(ret *withdraw.Response) *gctrpc.WithdrawalEventsByExchang
Event: []*gctrpc.WithdrawalEventResponse{tempEvent},
}
}
// UpsertDataHistoryJob adds or updates a data history job for the data history manager
// It will upsert the entry in the database and allow for the processing of the job
func (s *RPCServer) UpsertDataHistoryJob(_ context.Context, r *gctrpc.UpsertDataHistoryJobRequest) (*gctrpc.UpsertDataHistoryJobResponse, error) {
if r == nil {
return nil, errNilRequestData
}
a, err := asset.New(r.Asset)
if err != nil {
return nil, err
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
e := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, e, a, p)
if err != nil {
return nil, err
}
start, err := time.Parse(common.SimpleTimeFormat, r.StartDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
end, err := time.Parse(common.SimpleTimeFormat, r.EndDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start, end)
if err != nil {
return nil, err
}
job := DataHistoryJob{
Nickname: r.Nickname,
Exchange: r.Exchange,
Asset: a,
Pair: p,
StartDate: start,
EndDate: end,
Interval: kline.Interval(r.Interval),
RunBatchLimit: r.BatchSize,
RequestSizeLimit: r.RequestSizeLimit,
DataType: dataHistoryDataType(r.DataType),
Status: dataHistoryStatusActive,
MaxRetryAttempts: r.MaxRetryAttempts,
}
err = s.dataHistoryManager.UpsertJob(&job, r.InsertOnly)
if err != nil {
return nil, err
}
result, err := s.dataHistoryManager.GetByNickname(r.Nickname, false)
if err != nil {
return nil, fmt.Errorf("%s %w", r.Nickname, err)
}
return &gctrpc.UpsertDataHistoryJobResponse{
JobId: result.ID.String(),
Message: "successfully upserted job: " + result.Nickname,
}, nil
}
// GetDataHistoryJobDetails returns a data history job's details
// can request all data history results with r.FullDetails
func (s *RPCServer) GetDataHistoryJobDetails(_ context.Context, r *gctrpc.GetDataHistoryJobDetailsRequest) (*gctrpc.DataHistoryJob, error) {
if r == nil {
return nil, errNilRequestData
}
if r.Id == "" && r.Nickname == "" {
return nil, errNicknameIDUnset
}
if r.Nickname != "" && r.Id != "" {
return nil, errOnlyNicknameOrID
}
var (
result *DataHistoryJob
err error
jobResults []*gctrpc.DataHistoryJobResult
)
if r.Id != "" {
var id uuid.UUID
id, err = uuid.FromString(r.Id)
if err != nil {
return nil, fmt.Errorf("%s %w", r.Id, err)
}
result, err = s.dataHistoryManager.GetByID(id)
if err != nil {
return nil, fmt.Errorf("%s %w", r.Id, err)
}
} else {
result, err = s.dataHistoryManager.GetByNickname(r.Nickname, r.FullDetails)
if err != nil {
return nil, fmt.Errorf("%s %w", r.Nickname, err)
}
if r.FullDetails {
for _, v := range result.Results {
for i := range v {
jobResults = append(jobResults, &gctrpc.DataHistoryJobResult{
StartDate: v[i].IntervalStartDate.Format(common.SimpleTimeFormat),
EndDate: v[i].IntervalEndDate.Format(common.SimpleTimeFormat),
HasData: v[i].Status == dataHistoryStatusComplete,
Message: v[i].Result,
RunDate: v[i].Date.Format(common.SimpleTimeFormat),
})
}
}
}
}
return &gctrpc.DataHistoryJob{
Id: result.ID.String(),
Nickname: result.Nickname,
Exchange: result.Exchange,
Asset: result.Asset.String(),
Pair: &gctrpc.CurrencyPair{
Delimiter: result.Pair.Delimiter,
Base: result.Pair.Base.String(),
Quote: result.Pair.Quote.String(),
},
StartDate: result.StartDate.Format(common.SimpleTimeFormat),
EndDate: result.EndDate.Format(common.SimpleTimeFormat),
Interval: int64(result.Interval.Duration()),
RequestSizeLimit: result.RequestSizeLimit,
DataType: result.DataType.String(),
MaxRetryAttempts: result.MaxRetryAttempts,
BatchSize: result.RunBatchLimit,
JobResults: jobResults,
Status: result.Status.String(),
}, nil
}
// DeleteDataHistoryJob deletes a data history job from the database
func (s *RPCServer) DeleteDataHistoryJob(_ context.Context, r *gctrpc.GetDataHistoryJobDetailsRequest) (*gctrpc.GenericResponse, error) {
if r == nil {
return nil, errNilRequestData
}
if r.Nickname == "" && r.Id == "" {
return nil, errNicknameIDUnset
}
if r.Nickname != "" && r.Id != "" {
return nil, errOnlyNicknameOrID
}
status := "success"
err := s.dataHistoryManager.DeleteJob(r.Nickname, r.Id)
if err != nil {
log.Error(log.GRPCSys, err)
status = "failed"
}
return &gctrpc.GenericResponse{Status: status}, err
}
// GetActiveDataHistoryJobs returns any active data history job details
func (s *RPCServer) GetActiveDataHistoryJobs(_ context.Context, _ *gctrpc.GetInfoRequest) (*gctrpc.DataHistoryJobs, error) {
jobs, err := s.dataHistoryManager.GetActiveJobs()
if err != nil {
return nil, err
}
var response []*gctrpc.DataHistoryJob
for i := range jobs {
response = append(response, &gctrpc.DataHistoryJob{
Id: jobs[i].ID.String(),
Nickname: jobs[i].Nickname,
Exchange: jobs[i].Exchange,
Asset: jobs[i].Asset.String(),
Pair: &gctrpc.CurrencyPair{
Delimiter: jobs[i].Pair.Delimiter,
Base: jobs[i].Pair.Base.String(),
Quote: jobs[i].Pair.Quote.String(),
},
StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat),
EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat),
Interval: int64(jobs[i].Interval.Duration()),
RequestSizeLimit: jobs[i].RequestSizeLimit,
DataType: jobs[i].DataType.String(),
MaxRetryAttempts: jobs[i].MaxRetryAttempts,
BatchSize: jobs[i].RunBatchLimit,
Status: jobs[i].Status.String(),
})
}
return &gctrpc.DataHistoryJobs{Results: response}, nil
}
// GetDataHistoryJobsBetween returns all jobs created between supplied dates
func (s *RPCServer) GetDataHistoryJobsBetween(_ context.Context, r *gctrpc.GetDataHistoryJobsBetweenRequest) (*gctrpc.DataHistoryJobs, error) {
if r == nil {
return nil, errNilRequestData
}
start, err := time.Parse(common.SimpleTimeFormat, r.StartDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse start time %v", errInvalidTimes, err)
}
end, err := time.Parse(common.SimpleTimeFormat, r.EndDate)
if err != nil {
return nil, fmt.Errorf("%w cannot parse end time %v", errInvalidTimes, err)
}
err = common.StartEndTimeCheck(start.Local(), end)
if err != nil {
return nil, err
}
jobs, err := s.dataHistoryManager.GetAllJobStatusBetween(start, end)
if err != nil {
return nil, err
}
var respJobs []*gctrpc.DataHistoryJob
for i := range jobs {
respJobs = append(respJobs, &gctrpc.DataHistoryJob{
Id: jobs[i].ID.String(),
Nickname: jobs[i].Nickname,
Exchange: jobs[i].Exchange,
Asset: jobs[i].Asset.String(),
Pair: &gctrpc.CurrencyPair{
Delimiter: jobs[i].Pair.Delimiter,
Base: jobs[i].Pair.Base.String(),
Quote: jobs[i].Pair.Quote.String(),
},
StartDate: jobs[i].StartDate.Format(common.SimpleTimeFormat),
EndDate: jobs[i].EndDate.Format(common.SimpleTimeFormat),
Interval: int64(jobs[i].Interval.Duration()),
RequestSizeLimit: jobs[i].RequestSizeLimit,
DataType: jobs[i].DataType.String(),
MaxRetryAttempts: jobs[i].MaxRetryAttempts,
BatchSize: jobs[i].RunBatchLimit,
Status: jobs[i].Status.String(),
})
}
return &gctrpc.DataHistoryJobs{
Results: respJobs,
}, nil
}
// GetDataHistoryJobSummary provides a general look at how a data history job is going with the "resultSummaries" property
func (s *RPCServer) GetDataHistoryJobSummary(_ context.Context, r *gctrpc.GetDataHistoryJobDetailsRequest) (*gctrpc.DataHistoryJob, error) {
if r == nil {
return nil, errNilRequestData
}
if r.Nickname == "" {
return nil, fmt.Errorf("get job summary %w", errNicknameUnset)
}
job, err := s.dataHistoryManager.GenerateJobSummary(r.Nickname)
if err != nil {
return nil, err
}
return &gctrpc.DataHistoryJob{
Nickname: job.Nickname,
Exchange: job.Exchange,
Asset: job.Asset.String(),
Pair: &gctrpc.CurrencyPair{
Delimiter: job.Pair.Delimiter,
Base: job.Pair.Base.String(),
Quote: job.Pair.Quote.String(),
},
StartDate: job.StartDate.Format(common.SimpleTimeFormat),
EndDate: job.EndDate.Format(common.SimpleTimeFormat),
Interval: int64(job.Interval.Duration()),
DataType: job.DataType.String(),
Status: job.Status.String(),
ResultSummaries: job.ResultRanges,
}, nil
}