Skip to content

Commit

Permalink
feat: implement /api/dashboard API endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Jan 22, 2019
1 parent bf7a30f commit 8dc37e1
Show file tree
Hide file tree
Showing 12 changed files with 1,004 additions and 575 deletions.
535 changes: 97 additions & 438 deletions api/api.pb.go

Large diffs are not rendered by default.

9 changes: 2 additions & 7 deletions api/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "google/api/annotations.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
//import "google/protobuf/timestamp.proto";
import "pkg/crew/crew.proto";
import "pkg/dashboard/dashboard.proto";
import "pkg/soundcloud/soundcloud.proto";

option go_package = "ultre.me/calcbiz/api";
Expand Down Expand Up @@ -33,7 +34,7 @@ service Server {
}; }

rpc Ping(Void) returns (Pong) { option (google.api.http) = { get: "/api/ping" }; };
rpc Dashboard(Void) returns (DashboardOutput) { option (google.api.http) = {get: "/api/dashboard"}; }
rpc Dashboard(Void) returns (calcbiz.dashboard.Entries) { option (google.api.http) = {get: "/api/dashboard"}; }
rpc Crew(Void) returns (calcbiz.crew.Crew) { option (google.api.http) = {get: "/api/crew"}; }
rpc Numberinfo(NumberinfoInput) returns (NumberinfoOutput) { option (google.api.http) = {get: "/api/numberinfo/{number}"}; }
rpc Recettator(RecettatorInput) returns (RecettatorOutput) { option (google.api.http) = {get: "/api/recettator"}; }
Expand Down Expand Up @@ -71,12 +72,6 @@ message KryptosOutput { string to = 1; }
message TpyoEnocdeIpunt { string form = 1; }
message TpyoEnocdeOuptut { string to = 1; }

// dashboard messages

message DahsboardRandomOutput { /* TODO */ }
message DahsboardOutput { /* TODO */ }
message DashboardOutput { /* TODO */ }

// numberinfo messages
message NumberinfoInput { float number = 1; }
message NumberinfoOutput { map<string, string> facts = 1; }
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/gogo/protobuf v1.2.0
github.com/golang/protobuf v1.2.0
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/handlers v1.4.0
github.com/gorilla/mux v1.6.2
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190104160321-4832df01553a
Expand All @@ -21,7 +22,7 @@ require (
github.com/sirupsen/logrus v1.3.0 // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
github.com/tdewolff/minify v2.3.6+incompatible
github.com/tdewolff/minify v2.3.6+incompatible // indirect
github.com/tdewolff/minify/v2 v2.3.8
github.com/tdewolff/parse v2.3.4+incompatible // indirect
github.com/tpyolang/tpyo-cli v1.0.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import (
"ultre.me/calcbiz/views"
)

// FIXME: handle context cancel (when client aborts a request)

// VERSION represents the version of the Camembert au lait crew's website
const VERSION = "2.1.0"

Expand Down
124 changes: 90 additions & 34 deletions pkg/dashboard/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,101 +4,157 @@ import (
"fmt"
"math/rand"

"go.uber.org/zap"
"ultre.me/calcbiz/pkg/soundcloud"
"ultre.me/calcbiz/pkg/spreadshirt"
)

type CALCDashboard struct {
soundcloud *soundcloud.Soundcloud
func (e *Entries) append(entries ...*Entry) {
for _, entry := range entries {
e.Entries = append(e.Entries, entry)
}
}

const (
typeHack = "hack"
typeTrack = "track"
typeMerch = "merch"
)
func NewManualEntry(title, URL, imageURL, description string, kind Entry_Kind) *Entry {
return &Entry{
Title: title,
URL: URL,
Description: description,
ImageURL: imageURL,
Kind: kind,
}
}

func New() *CALCDashboard {
return &CALCDashboard{}
func (e *Entries) shuffle() {
for i := range e.Entries {
j := rand.Intn(i + 1)
e.Entries[i], e.Entries[j] = e.Entries[j], e.Entries[i]
}
}

func (d *CALCDashboard) SetSoundCloud(soundcloud *soundcloud.Soundcloud) {
d.soundcloud = soundcloud
type Options struct {
Soundcloud *soundcloud.Soundcloud
}

func (d *CALCDashboard) hackEntries(limit int) (Entries, error) {
entries := Entries{}
entries.append(NewManualEntry(typeHack, "Moi j'aime", "hackz/moijaime", "", "Générateur de phrase de moi j'aime"))
entries.append(NewManualEntry(typeHack, "3615cryptage", "hackz/3615cryptage", "", "Messages codés de James Bond"))
type Dashboard struct{ opts *Options }

func New(opts *Options) *Dashboard { return &Dashboard{opts: opts} }

func newEntries() *Entries {
return &Entries{Entries: make([]*Entry, 0)}
}

func (d *Dashboard) hackEntries(limit int) (*Entries, error) {
entries := newEntries()
entries.append(NewManualEntry("Moi j'aime", "hackz/moijaime", "", "Générateur de phrase de moi j'aime", Entry_Hack))
entries.append(NewManualEntry("3615cryptage", "hackz/3615cryptage", "", "Messages codés de James Bond", Entry_Hack))

entries.shuffle()
if len(entries) < limit {
limit = len(entries)
if len(entries.Entries) < limit {
limit = len(entries.Entries)
}
return entries[:limit], nil
entries.Entries = entries.Entries[:limit]
return entries, nil
}

func (d *CALCDashboard) trackEntries(limit int) (Entries, error) {
entries := Entries{}
func (d *Dashboard) trackEntries(limit int) (*Entries, error) {
entries := newEntries()

tracks, err := d.soundcloud.Tracks()
tracks, err := d.opts.Soundcloud.GetTracks()
if err != nil {
return entries, err
}
if len(tracks) < limit {
limit = len(tracks)
if len(tracks.Tracks) < limit {
limit = len(tracks.Tracks)
}

// shuffle tracks
for i := range tracks {
for i := range tracks.Tracks {
j := rand.Intn(i + 1)
tracks[i], tracks[j] = tracks[j], tracks[i]
tracks.Tracks[i], tracks.Tracks[j] = tracks.Tracks[j], tracks.Tracks[i]
}

for _, track := range tracks[:limit] {
entries.append(NewManualEntry(typeTrack, track.Title, fmt.Sprintf("track/%d", track.Id), track.ArtworkUrl, track.Description))
for _, track := range tracks.Tracks[:limit] {
entries.append(NewManualEntry(
track.Title,
fmt.Sprintf("track/%d", track.ID),
track.ArtworkUrl,
track.Description,
Entry_Track,
))
}

entries.shuffle()
return entries, nil
}

func (d *CALCDashboard) merchEntries(limit int) (Entries, error) {
func (d *Dashboard) merchEntries(limit int) (Entries, error) {
entries := Entries{}

products := spreadshirt.GetAllProducts(250, 250)
if len(products) < limit {
limit = len(products)
}
for _, product := range products[:limit] {
entries.append(NewManualEntry(typeMerch, product.Title, product.URL, product.ImageURL, ""))
entries.append(NewManualEntry(
product.Title,
product.URL,
product.ImageURL,
"",
Entry_Merch,
))
}

entries.shuffle()
return entries, nil
}

func (d *CALCDashboard) Random() (Entries, error) {
entries := Entries{}
func (d *Dashboard) Random() (*Entries, error) {
entries := newEntries()

globalLimit := 16

// FIXME: parallelize slow calls

//
// hacks
//
hacks, err := d.hackEntries(3)
if err != nil {
return nil, err
}
entries = append(entries, hacks...)
entries.append(hacks.Entries...)
zap.L().Debug("fetched hack entries", zap.Int("len", len(hacks.Entries)))

//
// tracks (soundcloud)
//
// FIXME: add timeout
tracks, err := d.trackEntries(11)
if err != nil {
return nil, err
}
entries = append(entries, tracks...)
zap.L().Debug("fetched tracks entries", zap.Int("len", len(tracks.Entries)))
entries.append(tracks.Entries...)

//
// merch
//
// FIXME: add timeout
merchs, err := d.merchEntries(2)
if err != nil {
return nil, err
}
entries = append(entries, merchs...)
zap.L().Debug("fetched merch entries", zap.Int("len", len(merchs.Entries)))
entries.append(merchs.Entries...)

// shuffle the compilation
entries.shuffle()

// ensure we have exactly `globalLimit` entries
for len(entries.Entries) < globalLimit {
entries.Entries = append(entries.Entries, entries.Entries...)
}
entries.Entries = entries.Entries[:globalLimit]
return entries, nil
}
Loading

0 comments on commit 8dc37e1

Please sign in to comment.