/
session.go
207 lines (169 loc) · 6.38 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// Copyright (c) 2017-2019 Carnegie Mellon University. All rights reserved.
// Use of this source code is governed by BSD 3-clause license.
package resolver
import (
"context"
"errors"
"time"
graphql "github.com/graph-gophers/graphql-go"
dbhandler "go.edusense.io/storage/dbhandler"
models "go.edusense.io/storage/models"
)
// SessionResolver queries database and resolves query-agnostic Session model.
type SessionResolver struct {
Session *models.Session
FrameQuery bool
Driver dbhandler.DatabaseDriver
}
// SessionArgs defines parameters for session queries.
type SessionArgs struct {
SessionID *string
Keyword *string
}
// Sessions returns list of session resolvers from underlying database.
func (q QueryResolver) Sessions(ctx context.Context, args SessionArgs) ([]*SessionResolver, error) {
// if session id is specified, grab the session
if args.SessionID != nil {
session, err := q.Driver.GetSession(*args.SessionID)
if err != nil {
return []*SessionResolver{}, err
}
resolvers := []*SessionResolver{&SessionResolver{Driver: q.Driver, FrameQuery: true, Session: session}}
return resolvers, nil
}
keyword := ""
if args.Keyword != nil {
keyword = *args.Keyword
}
filter := &models.SessionFilter{
TimestampStart: time.Unix(0, 0),
TimestampEnd: time.Now(),
Keyword: keyword,
}
sessions, err := q.Driver.FindSession(filter)
if err != nil {
return []*SessionResolver{}, err
}
resolvers := make([]*SessionResolver, len(sessions))
for i := range sessions {
resolvers[i] = &SessionResolver{Driver: q.Driver, FrameQuery: false, Session: &sessions[i]}
}
return resolvers, nil
}
// ID extracts Session ID from given Session resolver.
func (s *SessionResolver) ID(ctx context.Context) (graphql.ID, error) {
return graphql.ID(s.Session.ID), nil
}
// Keyword extracts keyword from given Session resolver.
func (s *SessionResolver) Keyword(ctx context.Context) (string, error) {
return s.Session.Keyword, nil
}
func (s *SessionResolver) Version(ctx context.Context) (string, error) {
return s.Session.Version, nil
}
// Schemas extracts schemas from given Session resolver.
// TODO(DohyunKimOfficial): Currently returning empty list. After plumbing
// schemas to query and storage infrastructure, we can add schema resolving
// logic here.
func (s *SessionResolver) Schemas(ctx context.Context) ([]string, error) {
return []string{}, nil
}
// CreatedAt extracts when this session is created at from given Session
// resolver.
func (s *SessionResolver) CreatedAt(ctx context.Context) (*TimeResolver, error) {
return &TimeResolver{Time: s.Session.Timestamp}, nil
}
// VideoFrames extracts list of video frame resolvers from given Session
// resolver.
func (s *SessionResolver) VideoFrames(ctx context.Context, args FrameArgs) ([]*VideoFrameResolver, error) {
if !s.FrameQuery {
return []*VideoFrameResolver{}, errors.New("cannot query frames while querying sessions")
}
numberFilters := []models.FrameNumberFilter{}
if args.FrameNumber != nil && args.FrameNumber.Filters != nil {
numberFilters = make([]models.FrameNumberFilter, len(*args.FrameNumber.Filters))
for i, f := range *args.FrameNumber.Filters {
parsedFilter, _ := parseFrameNumberFilter(&f)
numberFilters[i] = parsedFilter
}
}
timestampFilters := []models.TimestampFilter{}
if args.Timestamp != nil && args.Timestamp.Filters != nil {
timestampFilters = make([]models.TimestampFilter, len(*args.Timestamp.Filters))
for i, f := range *args.Timestamp.Filters {
parsedFilter, err := parseTimestampFilter(&f)
timestampFilters[i] = parsedFilter
if err != nil {
return []*VideoFrameResolver{}, err
}
}
}
frames, err := s.Driver.GetQueriableVideoFrameByFilter(s.Session.ID, args.Schema+"-video", args.Channel, numberFilters, timestampFilters)
if err != nil {
return []*VideoFrameResolver{}, err
}
resolvers := make([]*VideoFrameResolver, len(frames))
for i, f := range frames {
resolvers[i] = &VideoFrameResolver{Frame: f}
}
return resolvers, nil
}
// AudioFrames extracts list of audio frame resolvers from given Session
// resolver.
func (s *SessionResolver) AudioFrames(ctx context.Context, args FrameArgs) ([]*AudioFrameResolver, error) {
if !s.FrameQuery {
return []*AudioFrameResolver{}, errors.New("cannot query frames while querying sessions")
}
numberFilters := []models.FrameNumberFilter{}
if args.FrameNumber != nil && args.FrameNumber.Filters != nil {
numberFilters = make([]models.FrameNumberFilter, len(*args.FrameNumber.Filters))
for i, f := range *args.FrameNumber.Filters {
numberFilters[i], _ = parseFrameNumberFilter(&f)
}
}
timestampFilters := []models.TimestampFilter{}
if args.Timestamp != nil && args.Timestamp.Filters != nil {
timestampFilters = make([]models.TimestampFilter, len(*args.Timestamp.Filters))
for i, f := range *args.Timestamp.Filters {
parsedFilter, err := parseTimestampFilter(&f)
timestampFilters[i] = parsedFilter
if err != nil {
return []*AudioFrameResolver{}, err
}
}
}
frames, err := s.Driver.GetQueriableAudioFrameByFilter(s.Session.ID, args.Schema+"-audio", args.Channel, numberFilters, timestampFilters)
if err != nil {
return []*AudioFrameResolver{}, nil
}
resolvers := make([]*AudioFrameResolver, len(frames))
for i, f := range frames {
resolvers[i] = &AudioFrameResolver{Frame: f}
}
return resolvers, nil
}
func parseTimestampFilter(f *TimestampQueryFilter) (models.TimestampFilter, error) {
switch f.Format {
case "RFC3339":
if f.Timestamp.RFC3339 == nil {
return models.TimestampFilter{}, errors.New("RFC3339 timestamp not found")
}
t, err := time.Parse(time.RFC3339, *f.Timestamp.RFC3339)
if err == nil {
return models.TimestampFilter{Operator: f.Op, Timestamp: t}, nil
}
return models.TimestampFilter{}, err
case "unixTimestamp":
if f.Timestamp.UnixSeconds == nil {
return models.TimestampFilter{}, errors.New("unix timestamp not found")
} else if f.Timestamp.UnixNanoseconds == nil {
return models.TimestampFilter{Operator: f.Op, Timestamp: time.Unix(int64(*f.Timestamp.UnixSeconds), 0)}, nil
}
return models.TimestampFilter{Operator: f.Op, Timestamp: time.Unix(int64(*f.Timestamp.UnixNanoseconds), 0)}, nil
default:
return models.TimestampFilter{}, errors.New("timestamp resolution error")
}
}
func parseFrameNumberFilter(f *FrameNumberQueryFilter) (models.FrameNumberFilter, error) {
return models.FrameNumberFilter{Operator: f.Op, FrameNumber: uint32(f.Number)}, nil
}