Skip to content

Commit

Permalink
Added Forks Timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
emanuelef committed Jul 12, 2024
1 parent 38d80bf commit 73ebf36
Show file tree
Hide file tree
Showing 6 changed files with 933 additions and 4 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.21.6

require (
github.com/Code-Hex/go-generics-cache v1.5.1
github.com/emanuelef/github-repo-activity-stats v0.2.29
github.com/emanuelef/github-repo-activity-stats v0.2.30
github.com/gofiber/contrib/otelfiber v1.0.10
github.com/gofiber/fiber/v2 v2.52.5
github.com/joho/godotenv v1.5.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emanuelef/github-repo-activity-stats v0.2.29 h1:zJNiNWnBv8gBMIxakzy9SimJpGYz9pOJUA6CvK5b2oY=
github.com/emanuelef/github-repo-activity-stats v0.2.29/go.mod h1:Z6q8Ahan1HhKCArQovdXyjZAhHswriqTFGJ14fu7MKA=
github.com/emanuelef/github-repo-activity-stats v0.2.30 h1:Q6/nV+CsV6XhCI648t6VNhbq7/3oygIuZiaWNmgSK7A=
github.com/emanuelef/github-repo-activity-stats v0.2.30/go.mod h1:Z6q8Ahan1HhKCArQovdXyjZAhHswriqTFGJ14fu7MKA=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down
110 changes: 110 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ type IssuesWithStatsResponse struct {
Issues []stats.IssuesPerDay `json:"issues"`
}

type ForksWithStatsResponse struct {
Forks []stats.ForksPerDay `json:"forks"`
}

func getEnv(key, fallback string) string {
value, exists := os.LookupEnv(key)
if !exists {
Expand Down Expand Up @@ -106,9 +110,11 @@ func main() {
cacheOverall := cache.New[string, *stats.RepoStats]()
cacheStars := cache.New[string, StarsWithStatsResponse]()
cacheIssues := cache.New[string, IssuesWithStatsResponse]()
cacheForks := cache.New[string, ForksWithStatsResponse]()

onGoingStars := make(map[string]bool)
onGoingIssues := make(map[string]bool)
onGoingForks := make(map[string]bool)

ghStatClients := make(map[string]*repostats.ClientGQL)

Expand Down Expand Up @@ -454,6 +460,110 @@ func main() {
return c.JSON(res)
})

app.Get("/allForks", func(c *fiber.Ctx) error {
param := c.Query("repo")
randomIndex := rand.Intn(len(maps.Keys(ghStatClients)))
clientKey := c.Query("client", maps.Keys(ghStatClients)[randomIndex])
forceRefetch := c.Query("forceRefetch", "false") == "true"

client, ok := ghStatClients[clientKey]
if !ok {
return c.Status(404).SendString("Resource not found")
}

repo, err := url.QueryUnescape(param)
if err != nil {
return err
}

// needed because c.Query cannot be used as a map key
repo = fmt.Sprintf("%s", repo)
repo = strings.ToLower(repo)

ip := c.Get("X-Forwarded-For")

// If X-Forwarded-For is empty, fallback to RemoteIP
if ip == "" {
ip = c.IP()
}

userAgent := c.Get("User-Agent")
log.Printf("Forks Request from IP: %s, Repo: %s User-Agent: %s\n", ip, repo, userAgent)

if strings.Contains(userAgent, "python-requests") {
return c.Status(404).SendString("Custom 404 Error: Resource not found")
}

span := trace.SpanFromContext(c.UserContext())
span.SetAttributes(attribute.String("github.repo", repo))
span.SetAttributes(attribute.String("caller.ip", ip))

if forceRefetch {
cacheForks.Delete(repo)
}

if res, hit := cacheForks.Get(repo); hit {
return c.JSON(res)
}

// if another request is already getting the data, skip and rely on SSE updates
if _, hit := onGoingForks[repo]; hit {
return c.SendStatus(fiber.StatusNoContent)
}

onGoingForks[repo] = true

updateChannel := make(chan int)
var allForks []stats.ForksPerDay

eg, ctx := errgroup.WithContext(ctx)

eg.Go(func() error {
allForks, err = client.GetAllForksHistory(ctx, repo, updateChannel)
if err != nil {
return err
}
return nil
})

for progress := range updateChannel {
// fmt.Printf("Progress: %d\n", progress)

wg := &sync.WaitGroup{}

for _, s := range currentSessions.Sessions {
wg.Add(1)
go func(cs *session.Session) {
defer wg.Done()
if cs.Repo == repo {
cs.StateChannel <- progress
}
}(s)
}
wg.Wait()
}

if err := eg.Wait(); err != nil {
delete(onGoingForks, repo)
return err
}

// defer close(updateChannel)

res := ForksWithStatsResponse{
Forks: allForks,
}

now := time.Now()
nextDay := now.UTC().Truncate(24 * time.Hour).Add(DAY_CACHED * 24 * time.Hour)
durationUntilEndOfDay := nextDay.Sub(now)

cacheForks.Set(repo, res, cache.WithExpiration(durationUntilEndOfDay))
delete(onGoingForks, repo)

return c.JSON(res)
})

app.Get("/limits", func(c *fiber.Ctx) error {
client, ok := ghStatClients["PAT"]
if !ok {
Expand Down
17 changes: 16 additions & 1 deletion website/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import MainPage from "./MainPage";
import TimeSeriesChart from "./TimeSeriesChart";
import CompareChart from "./CompareChart";
import IssuesTimeSeriesChart from "./IssuesTimeSeriesChart";
import ForksTimeSeriesChart from "./ForksTimeSeriesChart";
import CalendarChart from "./CalendarChart";
import InfoPage from "./InfoPage";

Expand All @@ -18,6 +19,7 @@ import QueryStatsRoundedIcon from "@mui/icons-material/QueryStatsRounded";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import SsidChartRoundedIcon from "@mui/icons-material/SsidChartRounded";
import BugReportRoundedIcon from "@mui/icons-material/BugReportRounded";
import AltRouteOutlinedIcon from "@mui/icons-material/AltRouteOutlined";

import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
Expand Down Expand Up @@ -81,7 +83,8 @@ function App() {
useLocation().pathname.includes("/table") ||
useLocation().pathname.includes("/calendar") ||
useLocation().pathname.includes("/info") ||
useLocation().pathname.includes("/issues")
useLocation().pathname.includes("/issues") ||
useLocation().pathname.includes("/forks")
)
}
>
Expand Down Expand Up @@ -109,6 +112,17 @@ function App() {
>
Issues
</MenuItem>
<MenuItem
component={<Link to="/forks" className="link" />}
icon={
<Tooltip title="Forks Timeline" placement="right">
<AltRouteOutlinedIcon />
</Tooltip>
}
active={useLocation().pathname.includes("/forks")}
>
Forks
</MenuItem>
<MenuItem
component={<Link to="/table" className="link" />}
icon={
Expand Down Expand Up @@ -158,6 +172,7 @@ function App() {
<Route path="/calendar" element={<CalendarChart />} />
<Route path="/info" element={<InfoPage />} />
<Route path="/issues" element={<IssuesTimeSeriesChart />} />
<Route path="/forks" element={<ForksTimeSeriesChart />} />
</Routes>
</section>
</div>
Expand Down
Loading

0 comments on commit 73ebf36

Please sign in to comment.