Merge branch 'dev' into player-refactoring-phase-1

This commit is contained in:
Alex Kaminskii 2022-11-29 15:51:20 +01:00
commit 1524733f65
37 changed files with 297 additions and 238 deletions

View file

@ -7,7 +7,7 @@ on:
paths: paths:
- sourcemap-reader/** - sourcemap-reader/**
name: Build and Deploy Chalice name: Build and Deploy sourcemap-reader
jobs: jobs:
deploy: deploy:

View file

@ -242,7 +242,7 @@ class JiraManager:
def get_issue_types(self): def get_issue_types(self):
try: try:
types = self._jira.issue_types() types = self._jira.project(self._config['JIRA_PROJECT_ID']).issueTypes
except JIRAError as e: except JIRAError as e:
self.retries -= 1 self.retries -= 1
if (e.status_code // 100) == 4 and self.retries > 0: if (e.status_code // 100) == 4 and self.retries > 0:

View file

@ -73,6 +73,8 @@ func main() {
log.Printf("Error while caching: %v", err) log.Printf("Error while caching: %v", err)
case <-tick: case <-tick:
cacher.UpdateTimeouts() cacher.UpdateTimeouts()
case msg := <-msgConsumer.Rebalanced():
log.Println(msg)
default: default:
if !cacher.CanCache() { if !cacher.CanCache() {
continue continue

View file

@ -163,6 +163,8 @@ func main() {
os.Exit(0) os.Exit(0)
case <-commitTick: case <-commitTick:
commitDBUpdates() commitDBUpdates()
case msg := <-consumer.Rebalanced():
log.Println(msg)
default: default:
// Handle new message from queue // Handle new message from queue
if err := consumer.ConsumeNext(); err != nil { if err := consumer.ConsumeNext(); err != nil {

View file

@ -98,6 +98,8 @@ func main() {
if err := consumer.CommitBack(intervals.EVENTS_BACK_COMMIT_GAP); err != nil { if err := consumer.CommitBack(intervals.EVENTS_BACK_COMMIT_GAP); err != nil {
log.Printf("can't commit messages with offset: %s", err) log.Printf("can't commit messages with offset: %s", err)
} }
case msg := <-consumer.Rebalanced():
log.Println(msg)
default: default:
if err := consumer.ConsumeNext(); err != nil { if err := consumer.ConsumeNext(); err != nil {
log.Fatalf("Error on consuming: %v", err) log.Fatalf("Error on consuming: %v", err)

View file

@ -82,6 +82,8 @@ func main() {
}) })
producer.Flush(cfg.ProducerTimeout) producer.Flush(cfg.ProducerTimeout)
consumer.Commit() consumer.Commit()
case msg := <-consumer.Rebalanced():
log.Println(msg)
default: default:
if err := consumer.ConsumeNext(); err != nil { if err := consumer.ConsumeNext(); err != nil {
log.Fatalf("Error on consuming: %v", err) log.Fatalf("Error on consuming: %v", err)

View file

@ -14,14 +14,11 @@ import (
"openreplay/backend/internal/storage" "openreplay/backend/internal/storage"
"openreplay/backend/pkg/messages" "openreplay/backend/pkg/messages"
"openreplay/backend/pkg/monitoring" "openreplay/backend/pkg/monitoring"
"openreplay/backend/pkg/pprof"
"openreplay/backend/pkg/queue" "openreplay/backend/pkg/queue"
"openreplay/backend/pkg/url/assets" "openreplay/backend/pkg/url/assets"
) )
func main() { func main() {
pprof.StartProfilingServer()
metrics := monitoring.New("sink") metrics := monitoring.New("sink")
log.SetFlags(log.LstdFlags | log.LUTC | log.Llongfile) log.SetFlags(log.LstdFlags | log.LUTC | log.Llongfile)
@ -147,6 +144,15 @@ func main() {
case <-tickInfo: case <-tickInfo:
counter.Print() counter.Print()
log.Printf("writer: %s", writer.Info()) log.Printf("writer: %s", writer.Info())
case <-consumer.Rebalanced():
s := time.Now()
// Commit now to avoid duplicate reads
if err := consumer.Commit(); err != nil {
log.Printf("can't commit messages: %s", err)
}
// Sync all files
writer.Sync()
log.Printf("manual sync finished, dur: %d", time.Now().Sub(s).Milliseconds())
default: default:
err := consumer.ConsumeNext() err := consumer.ConsumeNext()
if err != nil { if err != nil {

View file

@ -73,6 +73,8 @@ func main() {
os.Exit(0) os.Exit(0)
case <-counterTick: case <-counterTick:
go counter.Print() go counter.Print()
case msg := <-consumer.Rebalanced():
log.Println(msg)
default: default:
err := consumer.ConsumeNext() err := consumer.ConsumeNext()
if err != nil { if err != nil {

View file

@ -8,6 +8,7 @@ require (
github.com/Masterminds/semver v1.5.0 github.com/Masterminds/semver v1.5.0
github.com/aws/aws-sdk-go v1.44.98 github.com/aws/aws-sdk-go v1.44.98
github.com/btcsuite/btcutil v1.0.2 github.com/btcsuite/btcutil v1.0.2
github.com/confluentinc/confluent-kafka-go v1.8.2
github.com/elastic/go-elasticsearch/v7 v7.13.1 github.com/elastic/go-elasticsearch/v7 v7.13.1
github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis v6.15.9+incompatible
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -26,9 +27,8 @@ require (
go.opentelemetry.io/otel/exporters/prometheus v0.30.0 go.opentelemetry.io/otel/exporters/prometheus v0.30.0
go.opentelemetry.io/otel/metric v0.30.0 go.opentelemetry.io/otel/metric v0.30.0
go.opentelemetry.io/otel/sdk/metric v0.30.0 go.opentelemetry.io/otel/sdk/metric v0.30.0
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 golang.org/x/net v0.0.0-20220906165146-f3363e06e74c
google.golang.org/api v0.81.0 google.golang.org/api v0.81.0
gopkg.in/confluentinc/confluent-kafka-go.v1 v1.8.2
) )
require ( require (
@ -38,7 +38,6 @@ require (
cloud.google.com/go/storage v1.14.0 // indirect cloud.google.com/go/storage v1.14.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/confluentinc/confluent-kafka-go v1.9.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@ -53,7 +52,6 @@ require (
github.com/jackc/puddle v1.2.2-0.20220404125616-4e959849469a // indirect github.com/jackc/puddle v1.2.2-0.20220404125616-4e959849469a // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.15.7 // indirect github.com/klauspost/compress v1.15.7 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/paulmach/orb v0.7.1 // indirect github.com/paulmach/orb v0.7.1 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect
@ -69,7 +67,7 @@ require (
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/text v0.4.0 // indirect golang.org/x/text v0.4.0 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect

View file

@ -115,12 +115,11 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/confluentinc/confluent-kafka-go v1.9.0 h1:d1k62oAuQVxgdMdiDQnpkABbtIWTBwXHpDcyGQUw5QQ= github.com/confluentinc/confluent-kafka-go v1.8.2 h1:PBdbvYpyOdFLehj8j+9ba7FL4c4Moxn79gy9cYKxG5E=
github.com/confluentinc/confluent-kafka-go v1.9.0/go.mod h1:WDFs+KlhHITEoCzEfHSNgj5aP7vjajyYbZpvTEGs1sE= github.com/confluentinc/confluent-kafka-go v1.8.2/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -328,14 +327,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
@ -400,8 +397,6 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@ -566,8 +561,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y=
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo=
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -679,8 +675,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -941,8 +937,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/confluentinc/confluent-kafka-go.v1 v1.8.2 h1:QAgN6OC0o7dwvyz+HML6GYm+0Pk54O91+oxGqJ/5z8I=
gopkg.in/confluentinc/confluent-kafka-go.v1 v1.8.2/go.mod h1:ZdI3yfYmdNSLQPNCpO1y00EHyWaHG5EnQEyL/ntAegY=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

View file

@ -97,17 +97,21 @@ func (w *SessionWriter) Info() string {
return fmt.Sprintf("%d sessions", w.meta.Count()) return fmt.Sprintf("%d sessions", w.meta.Count())
} }
func (w *SessionWriter) Sync() {
w.sessions.Range(func(sid, lockObj any) bool {
if err := w.sync(sid.(uint64)); err != nil {
log.Printf("can't sync file descriptor: %s", err)
}
return true
})
}
func (w *SessionWriter) synchronizer() { func (w *SessionWriter) synchronizer() {
tick := time.Tick(w.syncTimeout) tick := time.Tick(w.syncTimeout)
for { for {
select { select {
case <-tick: case <-tick:
w.sessions.Range(func(sid, lockObj any) bool { w.Sync()
if err := w.sync(sid.(uint64)); err != nil {
log.Printf("can't sync file descriptor: %s", err)
}
return true
})
case <-w.done: case <-w.done:
w.sessions.Range(func(sid, lockObj any) bool { w.sessions.Range(func(sid, lockObj any) bool {
if err := w.Close(sid.(uint64)); err != nil { if err := w.Close(sid.(uint64)); err != nil {

View file

@ -6,6 +6,7 @@ type Consumer interface {
CommitBack(gap int64) error CommitBack(gap int64) error
Commit() error Commit() error
Close() Close()
Rebalanced() <-chan interface{}
} }
// Producer sends batches of session data to queue (redis or kafka) // Producer sends batches of session data to queue (redis or kafka)

View file

@ -27,6 +27,7 @@ type Consumer struct {
idsPending streamPendingIDsMap idsPending streamPendingIDsMap
lastTs int64 lastTs int64
autoCommit bool autoCommit bool
event chan interface{}
} }
func NewConsumer(group string, streams []string, messageIterator messages.MessageIterator) *Consumer { func NewConsumer(group string, streams []string, messageIterator messages.MessageIterator) *Consumer {
@ -57,11 +58,16 @@ func NewConsumer(group string, streams []string, messageIterator messages.Messag
group: group, group: group,
autoCommit: true, autoCommit: true,
idsPending: idsPending, idsPending: idsPending,
event: make(chan interface{}, 4),
} }
} }
const READ_COUNT = 10 const READ_COUNT = 10
func (c *Consumer) Rebalanced() <-chan interface{} {
return c.event
}
func (c *Consumer) ConsumeNext() error { func (c *Consumer) ConsumeNext() error {
// MBTODO: read in go routine, send messages to channel // MBTODO: read in go routine, send messages to channel
res, err := c.redis.XReadGroup(&_redis.XReadGroupArgs{ res, err := c.redis.XReadGroup(&_redis.XReadGroupArgs{

View file

@ -2,24 +2,24 @@ package kafka
import ( import (
"log" "log"
"openreplay/backend/pkg/messages"
"os" "os"
"time" "time"
"github.com/pkg/errors"
"gopkg.in/confluentinc/confluent-kafka-go.v1/kafka"
"openreplay/backend/pkg/env" "openreplay/backend/pkg/env"
"openreplay/backend/pkg/messages"
"github.com/confluentinc/confluent-kafka-go/kafka"
"github.com/pkg/errors"
) )
type Message = kafka.Message type Message = kafka.Message
type Consumer struct { type Consumer struct {
c *kafka.Consumer c *kafka.Consumer
messageIterator messages.MessageIterator messageIterator messages.MessageIterator
commitTicker *time.Ticker commitTicker *time.Ticker
pollTimeout uint pollTimeout uint
events chan interface{}
lastReceivedPrtTs map[int32]int64 lastReceivedPrtTs map[int32]int64
} }
@ -48,7 +48,7 @@ func NewConsumer(
kafkaConfig.SetKey("ssl.certificate.location", os.Getenv("KAFKA_SSL_CERT")) kafkaConfig.SetKey("ssl.certificate.location", os.Getenv("KAFKA_SSL_CERT"))
} }
// Apply Kerberos configuration // Apply Kerberos configuration
if env.Bool("KAFKA_USE_KERBEROS") { if env.Bool("KAFKA_USE_KERBEROS") {
kafkaConfig.SetKey("security.protocol", "sasl_plaintext") kafkaConfig.SetKey("security.protocol", "sasl_plaintext")
kafkaConfig.SetKey("sasl.mechanisms", "GSSAPI") kafkaConfig.SetKey("sasl.mechanisms", "GSSAPI")
@ -61,6 +61,21 @@ func NewConsumer(
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
var commitTicker *time.Ticker
if autoCommit {
commitTicker = time.NewTicker(2 * time.Minute)
}
consumer := &Consumer{
c: c,
messageIterator: messageIterator,
commitTicker: commitTicker,
pollTimeout: 200,
events: make(chan interface{}, 4),
lastReceivedPrtTs: make(map[int32]int64, 16),
}
subREx := "^(" subREx := "^("
for i, t := range topics { for i, t := range topics {
if i != 0 { if i != 0 {
@ -69,22 +84,27 @@ func NewConsumer(
subREx += t subREx += t
} }
subREx += ")$" subREx += ")$"
if err := c.Subscribe(subREx, nil); err != nil { if err := c.Subscribe(subREx, consumer.reBalanceCallback); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
var commitTicker *time.Ticker return consumer
if autoCommit { }
commitTicker = time.NewTicker(2 * time.Minute)
}
return &Consumer{ func (consumer *Consumer) reBalanceCallback(_ *kafka.Consumer, e kafka.Event) error {
c: c, switch evt := e.(type) {
messageIterator: messageIterator, case kafka.RevokedPartitions:
commitTicker: commitTicker, // receive before re-balancing partitions; stop consuming messages and commit current state
pollTimeout: 200, consumer.events <- evt.String()
lastReceivedPrtTs: make(map[int32]int64), case kafka.AssignedPartitions:
// receive after re-balancing partitions; continue consuming messages
//consumer.events <- evt.String()
} }
return nil
}
func (consumer *Consumer) Rebalanced() <-chan interface{} {
return consumer.events
} }
func (consumer *Consumer) Commit() error { func (consumer *Consumer) Commit() error {

View file

@ -1,16 +1,15 @@
package kafka package kafka
import ( import (
"log"
"fmt" "fmt"
"log"
"gopkg.in/confluentinc/confluent-kafka-go.v1/kafka" "github.com/confluentinc/confluent-kafka-go/kafka"
) )
func logPartitions(s string, prts []kafka.TopicPartition) { func logPartitions(s string, prts []kafka.TopicPartition) {
for _, p := range prts { for _, p := range prts {
s = fmt.Sprintf("%v | %v", s, p.Partition) s = fmt.Sprintf("%v | %v", s, p.Partition)
} }
log.Println(s) log.Println(s)
} }

View file

@ -5,7 +5,7 @@ import (
"log" "log"
"os" "os"
"gopkg.in/confluentinc/confluent-kafka-go.v1/kafka" "github.com/confluentinc/confluent-kafka-go/kafka"
"openreplay/backend/pkg/env" "openreplay/backend/pkg/env"
) )

View file

@ -23,4 +23,4 @@ MINIO_SECRET_KEY = ''
# APP and TRACKER VERSIONS # APP and TRACKER VERSIONS
VERSION = '1.9.0' VERSION = '1.9.0'
TRACKER_VERSION = '4.1.7' TRACKER_VERSION = '4.1.9'

View file

@ -46,7 +46,7 @@ function AuditView(props) {
]} ]}
defaultValue={order} defaultValue={order}
plain plain
onChange={({ value }) => auditStore.updateKey('order', value)} onChange={({ value }) => auditStore.updateKey('order', value.value)}
/> />
</div> </div>
<AuditSearchField onChange={(value) => auditStore.updateKey('searchQuery', value) }/> <AuditSearchField onChange={(value) => auditStore.updateKey('searchQuery', value) }/>

View file

@ -2,11 +2,10 @@ import React, { useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setAutoplayValues } from 'Duck/sessions'; import { setAutoplayValues } from 'Duck/sessions';
import { session as sessionRoute } from 'App/routes'; import { session as sessionRoute } from 'App/routes';
import { Link, Icon, Toggler, Tooltip } from 'UI'; import { Link, Icon, Tooltip } from 'UI';;
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
import cn from 'classnames'; import cn from 'classnames';
import { fetchAutoplaySessions } from 'Duck/search'; import { fetchAutoplaySessions } from 'Duck/search';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
const PER_PAGE = 10; const PER_PAGE = 10;
@ -14,12 +13,10 @@ const PER_PAGE = 10;
interface Props extends RouteComponentProps { interface Props extends RouteComponentProps {
previousId: string; previousId: string;
nextId: string; nextId: string;
autoplay: boolean;
defaultList: any; defaultList: any;
currentPage: number; currentPage: number;
total: number; total: number;
setAutoplayValues?: () => void; setAutoplayValues?: () => void;
toggleAutoplay?: () => void;
latestRequestTime: any; latestRequestTime: any;
sessionIds: any; sessionIds: any;
fetchAutoplaySessions?: (page: number) => Promise<void>; fetchAutoplaySessions?: (page: number) => Promise<void>;
@ -37,8 +34,6 @@ function Autoplay(props: Props) {
params: { sessionId }, params: { sessionId },
}, },
} = props; } = props;
const { player, store } = React.useContext(PlayerContext)
const { autoplay } = store.get()
const disabled = sessionIds.length === 0; const disabled = sessionIds.length === 0;
@ -57,14 +52,6 @@ function Autoplay(props: Props) {
return ( return (
<div className="flex items-center"> <div className="flex items-center">
<div
onClick={() => player.toggleAutoplay()}
className="cursor-pointer flex items-center mr-2 hover:bg-gray-light-shade rounded-md p-2"
>
<Toggler name="sessionsLive" onChange={() => player.toggleAutoplay()} checked={autoplay} />
<span className="ml-2 whitespace-nowrap">Auto-Play</span>
</div>
<Tooltip <Tooltip
placement="bottom" placement="bottom"
title={<div className="whitespace-nowrap">Play Previous Session</div>} title={<div className="whitespace-nowrap">Play Previous Session</div>}
@ -114,4 +101,4 @@ export default connect(
latestRequestTime: state.getIn(['search', 'latestRequestTime']), latestRequestTime: state.getIn(['search', 'latestRequestTime']),
}), }),
{ setAutoplayValues, fetchAutoplaySessions } { setAutoplayValues, fetchAutoplaySessions }
)(withRouter(observer(Autoplay))) )(withRouter(Autoplay))

View file

@ -18,7 +18,6 @@ const SelectedValue = ({ icon, text }) => {
class IssueForm extends React.PureComponent { class IssueForm extends React.PureComponent {
componentDidMount() { componentDidMount() {
const { projects, issueTypes } = this.props; const { projects, issueTypes } = this.props;
this.props.init({ this.props.init({
projectId: projects[0] ? projects[0].id : '', projectId: projects[0] ? projects[0].id : '',
issueType: issueTypes[0] ? issueTypes[0].id : '', issueType: issueTypes[0] ? issueTypes[0].id : '',
@ -27,8 +26,8 @@ class IssueForm extends React.PureComponent {
componentWillReceiveProps(newProps) { componentWillReceiveProps(newProps) {
const { instance } = this.props; const { instance } = this.props;
if (instance.projectId && newProps.instance.projectId != instance.projectId) { if (newProps.instance.projectId && newProps.instance.projectId != instance.projectId) {
this.props.fetchMeta(instance.projectId).then(() => { this.props.fetchMeta(newProps.instance.projectId).then(() => {
this.props.edit({ issueType: '', assignee: '', projectId: newProps.instance.projectId }); this.props.edit({ issueType: '', assignee: '', projectId: newProps.instance.projectId });
}); });
} }
@ -87,7 +86,7 @@ class IssueForm extends React.PureComponent {
<Select <Select
name="projectId" name="projectId"
options={projectOptions} options={projectOptions}
// value={instance.projectId} defaultValue={instance.projectId}
fluid fluid
onChange={this.writeOption} onChange={this.writeOption}
placeholder="Project" placeholder="Project"
@ -100,7 +99,7 @@ class IssueForm extends React.PureComponent {
name="issueType" name="issueType"
labeled labeled
options={issueTypeOptions} options={issueTypeOptions}
value={instance.issueType} defaultValue={instance.issueType}
fluid fluid
onChange={this.writeOption} onChange={this.writeOption}
placeholder="Select issue type" placeholder="Select issue type"

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Icon, Popover } from 'UI'; import { Icon, Popover, Button } from 'UI';
import IssuesModal from './IssuesModal'; import IssuesModal from './IssuesModal';
import { fetchProjects, fetchMeta } from 'Duck/assignments'; import { fetchProjects, fetchMeta } from 'Duck/assignments';
import stl from './issues.module.css'; import stl from './issues.module.css';
@ -67,30 +67,27 @@ class Issues extends React.Component {
const provider = issuesIntegration.provider; const provider = issuesIntegration.provider;
return ( return (
<div className="relative h-full w-full p-3"> <Popover
<div className={stl.buttonWrapper}> onOpen={this.handleOpen}
<Popover render={({ close }) => (
onOpen={this.handleOpen} <div>
render={({ close }) => ( <IssuesModal provider={provider} sessionId={sessionId} closeHandler={close} />
<div> </div>
<IssuesModal )}
provider={provider} >
sessionId={sessionId} <div className="relative">
closeHandler={close} <Button icon={`integrations/${provider === 'jira' ? 'jira' : 'github'}`} variant="text">
/> Create Issue
</div> </Button>
)}
>
<div
className="flex items-center"
disabled={!isModalDisplayed && (metaLoading || fetchIssuesLoading || projectsLoading)}
>
<Icon name={`integrations/${provider === 'jira' ? 'jira' : 'github'}`} size="16" />
<span className="ml-2">Create Issue</span>
</div>
</Popover>
</div> </div>
</div> {/* <div
className="flex items-center cursor-pointer"
disabled={!isModalDisplayed && (metaLoading || fetchIssuesLoading || projectsLoading)}
>
<Icon name={`integrations/${provider === 'jira' ? 'jira' : 'github'}`} size="16" />
<span className="ml-2 whitespace-nowrap">Create Issue</span>
</div> */}
</Popover>
); );
} }
} }

View file

@ -67,7 +67,7 @@ function ReadNote(props: Props) {
<Icon name="close" size={18} /> <Icon name="close" size={18} />
</div> </div>
</div> </div>
<div className="text-xl py-3 overflow-y-scroll capitalize-first" style={{ maxHeight: 400 }}> <div className="text-xl py-3 overflow-y-auto capitalize-first" style={{ maxHeight: 400 }}>
{props.note.message} {props.note.message}
</div> </div>
<div className="w-full"> <div className="w-full">

View file

@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react';
import cn from 'classnames'; import cn from 'classnames';
import { connect } from 'react-redux' import { connect } from 'react-redux';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
import { Button, Link } from 'UI' import { Button, Link, Icon } from 'UI';
import { session as sessionRoute, withSiteId } from 'App/routes' import { session as sessionRoute, withSiteId } from 'App/routes';
import stl from './AutoplayTimer.module.css'; import stl from './AutoplayTimer.module.css';
import clsOv from './overlay.module.css'; import clsOv from './overlay.module.css';
@ -13,49 +13,55 @@ interface IProps extends RouteComponentProps {
} }
function AutoplayTimer({ nextId, siteId, history }: IProps) { function AutoplayTimer({ nextId, siteId, history }: IProps) {
let timer: NodeJS.Timer let timer: NodeJS.Timer;
const [cancelled, setCancelled] = useState(false); const [cancelled, setCancelled] = useState(false);
const [counter, setCounter] = useState(5); const [counter, setCounter] = useState(5);
useEffect(() => { useEffect(() => {
if(counter > 0) { if (counter > 0) {
timer = setTimeout(() => { timer = setTimeout(() => {
setCounter(counter - 1) setCounter(counter - 1);
}, 1000) }, 1000);
} }
if (counter === 0) { if (counter === 0) {
history.push(withSiteId(sessionRoute(nextId), siteId)) history.push(withSiteId(sessionRoute(nextId), siteId));
} }
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [counter]) }, [counter]);
const cancel = () => { const cancel = () => {
clearTimeout(timer) clearTimeout(timer);
setCancelled(true) setCancelled(true);
} };
if (cancelled) if (cancelled) return null;
return null
return ( return (
<div className={ cn(clsOv.overlay, stl.overlayBg) } > <div className={cn(clsOv.overlay, stl.overlayBg)}>
<div className="border p-6 shadow-lg bg-white rounded"> <div className="border p-6 shadow-lg bg-white rounded">
<div className="py-4">Next recording will be played in {counter}s</div> <div className="py-4">Next recording will be played in {counter}s</div>
<div className="flex items-center"> <div className="flex items-center">
<Button primary="outline" onClick={cancel}>Cancel</Button> <Button primary="outline" onClick={cancel}>
Cancel
</Button>
<div className="px-3" /> <div className="px-3" />
<Link to={ sessionRoute(nextId) } disabled={!nextId}> <Link to={sessionRoute(nextId)} disabled={!nextId}>
<Button variant="primary">Play Now</Button> <Button variant="primary">Play Now</Button>
</Link> </Link>
</div> </div>
<div className="mt-2 flex items-center color-gray-dark">
Turn on/off auto-replay in <Icon name="ellipsis-v" className="mx-1" /> More options
</div>
</div> </div>
</div> </div>
) );
} }
export default withRouter(connect(state => ({ export default withRouter(
siteId: state.getIn([ 'site', 'siteId' ]), connect((state: any) => ({
nextId: parseInt(state.getIn([ 'sessions', 'nextId' ])), siteId: state.getIn(['site', 'siteId']),
}))(AutoplayTimer)) nextId: parseInt(state.getIn(['sessions', 'nextId'])),
}))(AutoplayTimer)
);

View file

@ -11,6 +11,7 @@ import { useModal } from 'App/components/Modal';
import BugReportModal from './BugReport/BugReportModal'; import BugReportModal from './BugReport/BugReportModal';
import { PlayerContext } from 'App/components/Session/playerContext'; import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import AutoplayToggle from 'Shared/AutoplayToggle';
function SubHeader(props) { function SubHeader(props) {
const { player, store } = React.useContext(PlayerContext) const { player, store } = React.useContext(PlayerContext)
@ -74,39 +75,31 @@ function SubHeader(props) {
className="ml-auto text-sm flex items-center color-gray-medium gap-2" className="ml-auto text-sm flex items-center color-gray-medium gap-2"
style={{ width: 'max-content' }} style={{ width: 'max-content' }}
> >
<Button icon="file-pdf" variant="text" onClick={showReportModal}>Create Bug Report</Button> <Button icon="file-pdf" variant="text" onClick={showReportModal}>
Create Bug Report
</Button>
<NotePopup /> <NotePopup />
<Issues sessionId={props.sessionId} />
<SharePopup
entity="sessions"
id={props.sessionId}
showCopyLink={true}
trigger={
<div className="relative">
<Button icon="share-alt" variant="text" className="relative">
Share
</Button>
</div>
}
/>
<ItemMenu <ItemMenu
items={[ items={[
{
key: 1,
component: <AutoplayToggle />,
},
{ {
key: 2, key: 2,
component: props.jiraConfig && props.jiraConfig.token && (
<Issues sessionId={props.sessionId} />
),
},
{
key: 3,
component: (
<SharePopup
entity="sessions"
id={props.sessionId}
showCopyLink={true}
trigger={
<div className="flex items-center h-full w-full">
<Icon
className="mr-2"
disabled={props.disabled}
name="share-alt"
size="16"
/>
<span>Share</span>
</div>
}
/>
),
},
{
key: 4,
component: <Bookmark noMargin sessionId={props.sessionId} />, component: <Bookmark noMargin sessionId={props.sessionId} />,
}, },
]} ]}
@ -121,4 +114,4 @@ function SubHeader(props) {
); );
} }
export default observer(SubHeader); export default observer(SubHeader);

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Icon } from 'UI'; import { Icon, Button } from 'UI';
import styles from './menu.module.css'; import styles from './menu.module.css';
import cn from 'classnames'; import cn from 'classnames';
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
@ -32,8 +32,8 @@ export default class ItemMenu extends React.PureComponent<Props> {
}; };
closeMenu = () => { closeMenu = () => {
this.setState({ displayed: false }) this.setState({ displayed: false });
} };
render() { render() {
const { items } = this.props; const { items } = this.props;
@ -42,36 +42,22 @@ export default class ItemMenu extends React.PureComponent<Props> {
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<OutsideClickDetectingDiv onClickOutside={this.closeMenu}> <OutsideClickDetectingDiv onClickOutside={this.closeMenu}>
<div <Button variant="text" icon="ellipsis-v" onClick={this.toggleMenu}>
onClick={this.toggleMenu} More
className={cn( </Button>
'flex items-center cursor-pointer select-none', <div className={cn(styles.menu, styles.menuDim)} data-displayed={displayed}>
'rounded p-2', displayed ? 'bg-gray-light' : 'hover:bg-gray-light-shade' {items.map((item) =>
)} item.component ? (
> <div
<div key={item.key}
className={cn('rounded-full flex items-center justify-center', { role="menuitem"
'bg-gray-light': displayed, className="hover:bg-gray-light-shade cursor-pointer flex items-center w-full"
})} >
role="button" {item.component}
> </div>
<Icon name="ellipsis-v" size="16" /> ) : null
)}
</div> </div>
<span className={'mr-1 text-disabled-text'}>More</span>
</div>
<div className={cn(styles.menu, styles.menuDim)} data-displayed={displayed}>
{items.map((item) =>
item.component ? (
<div
key={item.key}
role="menuitem"
className="hover:bg-gray-light-shade cursor-pointer flex items-center w-full"
>
{item.component}
</div>
) : null
)}
</div>
</OutsideClickDetectingDiv> </OutsideClickDetectingDiv>
</div> </div>
); );

View file

@ -6,6 +6,7 @@ import stl from './signup.module.css'
import { signup } from 'Duck/user'; import { signup } from 'Duck/user';
import { connect } from 'react-redux' import { connect } from 'react-redux'
import Select from 'Shared/Select' import Select from 'Shared/Select'
import { SITE_ID_STORAGE_KEY } from 'App/constants/storageKeys';
const LOGIN_ROUTE = login() const LOGIN_ROUTE = login()
const recaptchaRef = React.createRef() const recaptchaRef = React.createRef()
@ -40,10 +41,10 @@ export default class SignupForm extends React.Component {
} }
return null; return null;
} }
handleSubmit = (token) => { handleSubmit = (token) => {
const { tenantId, fullname, password, email, projectName, organizationName, auth } = this.state; const { tenantId, fullname, password, email, projectName, organizationName, auth } = this.state;
localStorage.removeItem(SITE_ID_STORAGE_KEY)
this.props.signup({ tenantId, fullname, password, email, projectName, organizationName, auth, 'g-recaptcha-response': token }) this.props.signup({ tenantId, fullname, password, email, projectName, organizationName, auth, 'g-recaptcha-response': token })
this.setState({ reload: true }) this.setState({ reload: true })
} }

View file

@ -0,0 +1,29 @@
import React from 'react';
import { Controls as PlayerControls, connectPlayer } from 'Player';
import { Toggler } from 'UI';
interface Props {
toggleAutoplay: () => void;
autoplay: boolean;
}
function AutoplayToggle(props: Props) {
const { autoplay } = props;
return (
<div
onClick={props.toggleAutoplay}
className="cursor-pointer flex items-center mr-2 hover:bg-gray-light-shade rounded-md p-2"
>
<Toggler name="sessionsLive" onChange={props.toggleAutoplay} checked={autoplay} />
<span className="ml-2 whitespace-nowrap">Auto-Play</span>
</div>
);
}
export default connectPlayer(
(state: any) => ({
autoplay: state.autoplay,
}),
{
toggleAutoplay: PlayerControls.toggleAutoplay,
}
)(AutoplayToggle);

View file

@ -0,0 +1 @@
export { default } from './AutoplayToggle';

View file

@ -149,7 +149,7 @@ function ConsolePanel() {
)} )}
</CellMeasurer> </CellMeasurer>
</React.Fragment> </React.Fragment>
); )
} }
return ( return (

View file

@ -180,7 +180,6 @@ function NetworkPanel() {
const onTabClick = (activeTab: typeof TAP_KEYS[number]) => devTools.update(INDEX_KEY, { activeTab }) const onTabClick = (activeTab: typeof TAP_KEYS[number]) => devTools.update(INDEX_KEY, { activeTab })
const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => devTools.update(INDEX_KEY, { filter: value }) const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => devTools.update(INDEX_KEY, { filter: value })
// AutoScroll // AutoScroll
const countNow = fetchListNow.length + resourceListNow.length - intersectedCount const countNow = fetchListNow.length + resourceListNow.length - intersectedCount
const [ const [

View file

@ -38,7 +38,6 @@ function StackEventPanel() {
const onTabClick = (activeTab: typeof TAB_KEYS[number]) => devTools.update(INDEX_KEY, { activeTab }) const onTabClick = (activeTab: typeof TAB_KEYS[number]) => devTools.update(INDEX_KEY, { activeTab })
const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => devTools.update(INDEX_KEY, { filter: value }) const onFilterChange = ({ target: { value } }: React.ChangeEvent<HTMLInputElement>) => devTools.update(INDEX_KEY, { filter: value })
const tabs = useMemo(() => const tabs = useMemo(() =>
TABS.filter(({ key }) => key === ALL || list.some(({ source }) => key === source)), TABS.filter(({ key }) => key === ALL || list.some(({ source }) => key === source)),
[ list.length ], [ list.length ],

View file

@ -128,7 +128,7 @@ export default class SharePopup extends React.PureComponent {
</div> </div>
)} )}
> >
<div className="p-3 w-full">{trigger}</div> {trigger}
</Popover> </Popover>
); );
} }

View file

@ -59,7 +59,7 @@ const Popover = ({ children, render, placement, onOpen = () => {} }: Props) => {
{open && ( {open && (
<FloatingFocusManager <FloatingFocusManager
context={context} context={context}
modal={false} modal={true}
order={['reference', 'content']} order={['reference', 'content']}
returnFocus={false} returnFocus={false}
> >

View file

@ -3,4 +3,5 @@ export const TIMEZONE = "__$session-timezone$__"
export const DURATION_FILTER = "__$session-durationFilter$__" export const DURATION_FILTER = "__$session-durationFilter$__"
export const SESSION_FILTER = "__$session-filter$__" export const SESSION_FILTER = "__$session-filter$__"
export const GLOBAL_DESTINATION_PATH = "__$global-destinationPath$__" export const GLOBAL_DESTINATION_PATH = "__$global-destinationPath$__"
export const GLOBAL_HAS_NO_RECORDINGS = "__$global-hasNoRecordings$__" export const GLOBAL_HAS_NO_RECORDINGS = "__$global-hasNoRecordings$__"
export const SITE_ID_STORAGE_KEY = "__$user-siteId$__"

View file

@ -15,14 +15,12 @@ import {
createEdit, createEdit,
createRemove, createRemove,
createUpdate, createUpdate,
createSave,
saveType, saveType,
} from './funcTools/crud'; } from './funcTools/crud';
import { createRequestReducer } from './funcTools/request'; import { createRequestReducer } from './funcTools/request';
import { Map, List, fromJS } from "immutable"; import { Map, List, fromJS } from "immutable";
import { GLOBAL_HAS_NO_RECORDINGS } from 'App/constants/storageKeys'; import { GLOBAL_HAS_NO_RECORDINGS, SITE_ID_STORAGE_KEY } from 'App/constants/storageKeys';
const SITE_ID_STORAGE_KEY = "__$user-siteId$__";
const storedSiteId = localStorage.getItem(SITE_ID_STORAGE_KEY); const storedSiteId = localStorage.getItem(SITE_ID_STORAGE_KEY);
const name = 'project'; const name = 'project';

View file

@ -1,3 +1,3 @@
<svg viewBox="0 0 29 19" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 29 19" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.7" d="M11.6355 2.9045C10.8963 1.75328 9.80334 0.873101 8.521 0.396241C7.23867 -0.0806184 5.83621 -0.128393 4.5244 0.260101C3.21259 0.648595 2.06231 1.45237 1.24645 2.55061C0.430585 3.64885 -0.00678382 4.98223 7.95597e-05 6.35034C0.00076002 7.48328 0.305669 8.59524 0.882952 9.57006C1.46024 10.5449 2.28871 11.3468 3.28182 11.892C4.27493 12.4372 5.39624 12.7058 6.52859 12.6695C7.66095 12.6333 8.76279 12.2937 9.71903 11.6861C9.22188 13.1623 8.29591 14.7372 6.77033 16.316C6.47844 16.6179 6.31846 17.0234 6.32558 17.4433C6.3327 17.8632 6.50633 18.2631 6.80828 18.555C7.11022 18.8469 7.51575 19.0069 7.93566 18.9997C8.35556 18.9926 8.75543 18.819 9.04731 18.517C14.6867 12.6728 13.9542 6.31998 11.6355 2.91209V2.9045ZM26.8154 2.9045C26.0762 1.75328 24.9833 0.873101 23.7009 0.396241C22.4186 -0.0806184 21.0161 -0.128393 19.7043 0.260101C18.3925 0.648595 17.2422 1.45237 16.4264 2.55061C15.6105 3.64885 15.1731 4.98223 15.18 6.35034C15.1807 7.48328 15.4856 8.59524 16.0629 9.57006C16.6402 10.5449 17.4686 11.3468 18.4617 11.892C19.4549 12.4372 20.5762 12.7058 21.7085 12.6695C22.8409 12.6333 23.9427 12.2937 24.899 11.6861C24.4018 13.1623 23.4758 14.7372 21.9503 16.316C21.6584 16.6179 21.4984 17.0234 21.5055 17.4433C21.5126 17.8632 21.6863 18.2631 21.9882 18.555C22.2901 18.8469 22.6957 19.0069 23.1156 18.9997C23.5355 18.9926 23.9354 18.819 24.2272 18.517C29.8666 12.6728 29.1342 6.31998 26.8154 2.91209V2.9045Z" /> <path opacity="0.7" d="M11.6355 2.9045C10.8963 1.75328 9.80334 0.873101 8.521 0.396241C7.23867 -0.0806184 5.83621 -0.128393 4.5244 0.260101C3.21259 0.648595 2.06231 1.45237 1.24645 2.55061C0.430585 3.64885 -0.00678382 4.98223 7.95597e-05 6.35034C0.00076002 7.48328 0.305669 8.59524 0.882952 9.57006C1.46024 10.5449 2.28871 11.3468 3.28182 11.892C4.27493 12.4372 5.39624 12.7058 6.52859 12.6695C7.66095 12.6333 8.76279 12.2937 9.71903 11.6861C9.22188 13.1623 8.29591 14.7372 6.77033 16.316C6.47844 16.6179 6.31846 17.0234 6.32558 17.4433C6.3327 17.8632 6.50633 18.2631 6.80828 18.555C7.11022 18.8469 7.51575 19.0069 7.93566 18.9997C8.35556 18.9926 8.75543 18.819 9.04731 18.517C14.6867 12.6728 13.9542 6.31998 11.6355 2.91209V2.9045ZM26.8154 2.9045C26.0762 1.75328 24.9833 0.873101 23.7009 0.396241C22.4186 -0.0806184 21.0161 -0.128393 19.7043 0.260101C18.3925 0.648595 17.2422 1.45237 16.4264 2.55061C15.6105 3.64885 15.1731 4.98223 15.18 6.35034C15.1807 7.48328 15.4856 8.59524 16.0629 9.57006C16.6402 10.5449 17.4686 11.3468 18.4617 11.892C19.4549 12.4372 20.5762 12.7058 21.7085 12.6695C22.8409 12.6333 23.9427 12.2937 24.899 11.6861C24.4018 13.1623 23.4758 14.7372 21.9503 16.316C21.6584 16.6179 21.4984 17.0234 21.5055 17.4433C21.5126 17.8632 21.6863 18.2631 21.9882 18.555C22.2901 18.8469 22.6957 19.0069 23.1156 18.9997C23.5355 18.9926 23.9354 18.819 24.2272 18.517C29.8666 12.6728 29.1342 6.31998 26.8154 2.91209V2.9045Z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -19,9 +19,7 @@ version="v1.9.0"
usr=`whoami` usr=`whoami`
# Installing k3s # Installing k3s
[[ x$SKIP_K8S_INSTALL == "xtrue" ]] && { function install_k8s{
info "Skipping Kuberntes installation"
} || {
curl -sL https://get.k3s.io | sudo K3S_KUBECONFIG_MODE="644" INSTALL_K3S_VERSION='v1.22.8+k3s1' INSTALL_K3S_EXEC="--no-deploy=traefik" sh - curl -sL https://get.k3s.io | sudo K3S_KUBECONFIG_MODE="644" INSTALL_K3S_VERSION='v1.22.8+k3s1' INSTALL_K3S_EXEC="--no-deploy=traefik" sh -
[[ -d ~/.kube ]] || mkdir ~/.kube [[ -d ~/.kube ]] || mkdir ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
@ -29,42 +27,42 @@ usr=`whoami`
sudo chown -R $usr ~/.kube/config sudo chown -R $usr ~/.kube/config
} }
[[ x$SKIP_K8S_TOOLS == "xtrue" ]] && { function install_tools(){
info "Skipping Kuberntes installation"
} || {
## installing kubectl ## installing kubectl
which kubectl &> /dev/null || { which kubectl &> /dev/null || {
info "kubectl not installed. Installing it..." info "kubectl not installed. Installing it..."
sudo curl -SsL https://dl.k8s.io/release/v1.20.0/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl ; sudo chmod +x /usr/local/bin/kubectl sudo curl -SsL https://dl.k8s.io/release/v1.20.0/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl ; sudo chmod +x /usr/local/bin/kubectl
} }
## Installing GH package manager
which eget &> /dev/null || {
local version="1.3.0"
info "eget not installed. Installing it..."
curl -SsL https://github.com/zyedidia/eget/releases/download/v$version/eget-1.3.0-linux_amd64.tar.gz -o /tmp/eget.tar.gz
cd /tmp
tar -xf eget.tar.gz
sudo mv eget-$version-linux_amd64/eget /usr/local/bin/eget
sudo chmod +x /usr/local/bin/eget
cd -
}
## installing stern ## installing stern
which stern &> /dev/null || { which stern &> /dev/null || {
info "stern not installed. installing..." info "stern not installed. installing..."
sudo curl -SsL https://github.com/derdanne/stern/releases/download/2.1.16/stern_linux_amd64 -o /usr/local/bin/stern ; sudo chmod +x /usr/local/bin/stern sudo eget --to /usr/local/bin stern/stern
} }
## installing k9s ## installing k9s
which k9s &> /dev/null || { which k9s &> /dev/null || {
info "k9s not installed. Installing it..." info "k9s not installed. Installing it..."
sudo curl -SsL https://github.com/derailed/k9s/releases/download/v0.24.2/k9s_Linux_x86_64.tar.gz -o /tmp/k9s.tar.gz sudo eget --to /usr/local/bin derailed/k9s
cd /tmp
tar -xf k9s.tar.gz
sudo mv k9s /usr/local/bin/k9s
sudo chmod +x /usr/local/bin/k9s
cd -
} }
## installing helm ## installing helm
which helm &> /dev/null which helm &> /dev/null || {
if [[ $? -ne 0 ]]; then
info "helm not installed. Installing it..." info "helm not installed. Installing it..."
curl -ssl https://get.helm.sh/helm-v3.10.2-linux-amd64.tar.gz -o /tmp/helm.tar.gz sudo eget --to /usr/local/bin https://get.helm.sh/helm-v3.10.2-linux-amd64.tar.gz -f helm
tar -xf /tmp/helm.tar.gz }
chmod +x linux-amd64/helm
sudo cp linux-amd64/helm /usr/local/bin/helm
rm -rf linux-amd64/helm /tmp/helm.tar.gz
fi
} }
sleep 10 sleep 10
@ -79,10 +77,6 @@ randomPass() {
## Prepping the infra ## Prepping the infra
[[ -z $DOMAIN_NAME ]] && {
fatal 'DOMAIN_NAME variable is empty. Rerun the script `DOMAIN_NAME=openreplay.mycomp.org bash init.sh `'
}
# Mac os doesn't have gnu sed, which will cause compatibility issues. # Mac os doesn't have gnu sed, which will cause compatibility issues.
# This wrapper will help to check the sed, and use the correct version="v1.9.0" # This wrapper will help to check the sed, and use the correct version="v1.9.0"
# Ref: https://stackoverflow.com/questions/37639496/how-can-i-check-the-version="v1.9.0" # Ref: https://stackoverflow.com/questions/37639496/how-can-i-check-the-version="v1.9.0"
@ -102,21 +96,52 @@ function sed_i_wrapper(){
fi fi
} }
info "Creating dynamic passwords" function create_passwords() {
sed_i_wrapper -i "s/postgresqlPassword: \"changeMePassword\"/postgresqlPassword: \"$(randomPass)\"/g" vars.yaml [[ -z $DOMAIN_NAME ]] && {
sed_i_wrapper -i "s/accessKey: \"changeMeMinioAccessKey\"/accessKey: \"$(randomPass)\"/g" vars.yaml fatal 'DOMAIN_NAME variable is empty. Rerun the script `DOMAIN_NAME=openreplay.mycomp.org bash init.sh `'
sed_i_wrapper -i "s/secretKey: \"changeMeMinioPassword\"/secretKey: \"$(randomPass)\"/g" vars.yaml }
sed_i_wrapper -i "s/jwt_secret: \"SetARandomStringHere\"/jwt_secret: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/assistKey: \"SetARandomStringHere\"/assistKey: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/assistJWTSecret: \"SetARandomStringHere\"/assistJWTSecret: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/domainName: \"\"/domainName: \"${DOMAIN_NAME}\"/g" vars.yaml
info "Setting proper permission for shared folder" info "Creating dynamic passwords"
sudo mkdir -p /openreplay/storage/nfs sed_i_wrapper -i "s/postgresqlPassword: \"changeMePassword\"/postgresqlPassword: \"$(randomPass)\"/g" vars.yaml
sudo chown -R 1001:1001 /openreplay/storage/nfs sed_i_wrapper -i "s/accessKey: \"changeMeMinioAccessKey\"/accessKey: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/secretKey: \"changeMeMinioPassword\"/secretKey: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/jwt_secret: \"SetARandomStringHere\"/jwt_secret: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/assistKey: \"SetARandomStringHere\"/assistKey: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/assistJWTSecret: \"SetARandomStringHere\"/assistJWTSecret: \"$(randomPass)\"/g" vars.yaml
sed_i_wrapper -i "s/domainName: \"\"/domainName: \"${DOMAIN_NAME}\"/g" vars.yaml
}
function set_permissions() {
info "Setting proper permission for shared folder"
sudo mkdir -p /openreplay/storage/nfs
sudo chown -R 1001:1001 /openreplay/storage/nfs
}
## Installing OpenReplay ## Installing OpenReplay
info "installing databases" function install_openreplay() {
helm upgrade --install databases ./databases -n db --create-namespace --wait -f ./vars.yaml --atomic info "installing databases"
info "installing application" helm upgrade --install databases ./databases -n db --create-namespace --wait -f ./vars.yaml --atomic
helm upgrade --install openreplay ./openreplay -n app --create-namespace --wait -f ./vars.yaml --atomic info "installing application"
helm upgrade --install openreplay ./openreplay -n app --create-namespace --wait -f ./vars.yaml --atomic
}
function main(){
[[ x$SKIP_K8S_INSTALL == "x1" ]] && {
info "Skipping Kuberntes installation"
} || {
install_k8s
}
[[ x$SKIP_K8S_TOOLS == "x1" ]] && {
info "Skipping Kuberntes tools installation"
} || {
install_tools
}
create_passwords
set_permissions
[[ x$SKIP_OR_INSTALL == "x1" ]] && {
info "Skipping OpenReplay installation"
} || {
install_openreplay
}
}