Skip to content

Commit b5f7786

Browse files
RAJ6MAURYArmaurya
andauthored
[refactor]: separating Code for better readability (#5)
* combined all struct into one file * Configs will be fetch from this files only * http route handlers * adding routes to all the urls * refactoring * removing init and adding a func name and calling it in main func directly * fallback condition added --------- Co-authored-by: rmaurya <[email protected]>
1 parent 0cb761a commit b5f7786

File tree

7 files changed

+559
-514
lines changed

7 files changed

+559
-514
lines changed

common/config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package common
2+
3+
import "os"
4+
5+
// Get port from environment variable or use default
6+
func GetPort() string {
7+
port := os.Getenv("PORT")
8+
if port == "" {
9+
port = "8080"
10+
}
11+
return port
12+
}

common/type.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package common
2+
3+
import "time"
4+
5+
// ReleaseAsset represents a single asset in a release
6+
type ReleaseAsset struct {
7+
Name string `json:"name"`
8+
DownloadCount int `json:"download_count"`
9+
}
10+
11+
// Release represents a GitHub release
12+
type Release struct {
13+
ID int `json:"id"`
14+
TagName string `json:"tag_name"`
15+
CreatedAt time.Time `json:"created_at"`
16+
Assets []ReleaseAsset `json:"assets"`
17+
}
18+
19+
// ReleaseDownloadStats represents download statistics for a single release
20+
type ReleaseDownloadStats struct {
21+
TagName string `json:"tag_name"`
22+
CreatedAt time.Time `json:"created_at"`
23+
TotalDownloads int `json:"total_downloads"`
24+
Assets []AssetStats `json:"assets"`
25+
}
26+
27+
// AssetStats represents download statistics for a single asset
28+
type AssetStats struct {
29+
Name string `json:"name"`
30+
DownloadCount int `json:"download_count"`
31+
}
32+
33+
// DownloadStats represents download statistics for all releases
34+
type DownloadStats struct {
35+
RepoName string `json:"repo_name"`
36+
TotalDownloads int `json:"total_downloads"`
37+
Releases []ReleaseDownloadStats `json:"releases"`
38+
}
39+
40+
type Config struct {
41+
GithubToken string
42+
}
43+
44+
type Contributor struct {
45+
Login string `json:"login"`
46+
}
47+
48+
type OrganizationStats struct {
49+
OrgName string `json:"org_name"`
50+
TotalRepos int `json:"total_repos"`
51+
TotalContributors int `json:"total_contributors"`
52+
}
53+
54+
type StarHistory struct {
55+
RepoName string `json:"repo_name"`
56+
History []StarPoint `json:"history"`
57+
}
58+
59+
// StarPoint represents stars at a specific point in time
60+
type StarPoint struct {
61+
Date time.Time `json:"date"`
62+
Stars int `json:"stars"`
63+
}
64+
65+
// MultiRepoStarHistory represents star history for multiple repositories
66+
type MultiRepoStarHistory struct {
67+
Repositories []StarHistory `json:"repositories"`
68+
}

handlers/api.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package handlers
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
9+
cu "github.com/sonichigo/hg/common"
10+
)
11+
12+
func HandleRepoStats(w http.ResponseWriter, r *http.Request) {
13+
if r.Method != http.MethodGet {
14+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
15+
return
16+
}
17+
18+
repoURL := r.URL.Query().Get("repo")
19+
if repoURL == "" {
20+
http.Error(w, "Repository URL is required", http.StatusBadRequest)
21+
return
22+
}
23+
24+
owner, repo, err := extractRepoInfo(repoURL)
25+
if err != nil {
26+
http.Error(w, fmt.Sprintf("Invalid repository URL: %v", err), http.StatusBadRequest)
27+
return
28+
}
29+
30+
// Make token optional
31+
var config *cu.Config
32+
authHeader := r.Header.Get("Authorization")
33+
if authHeader != "" {
34+
token := strings.TrimPrefix(authHeader, "Bearer ")
35+
token = strings.TrimSpace(token)
36+
config = &cu.Config{GithubToken: token}
37+
}
38+
39+
releases, err := getAllReleases(owner, repo, config)
40+
if err != nil {
41+
http.Error(w, err.Error(), http.StatusInternalServerError)
42+
return
43+
}
44+
45+
stats := calculateDownloadStats(releases)
46+
stats.RepoName = fmt.Sprintf("%s/%s", owner, repo)
47+
48+
w.Header().Set("Content-Type", "application/json")
49+
json.NewEncoder(w).Encode(stats)
50+
}
51+
func HandleStarHistory(w http.ResponseWriter, r *http.Request) {
52+
if r.Method != http.MethodGet {
53+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
54+
return
55+
}
56+
57+
// Get repositories from query parameter
58+
repos := r.URL.Query()["repo"]
59+
if len(repos) == 0 {
60+
http.Error(w, "At least one repository URL is required", http.StatusBadRequest)
61+
return
62+
}
63+
64+
// Make token optional
65+
var config *cu.Config
66+
authHeader := r.Header.Get("Authorization")
67+
if authHeader != "" {
68+
token := strings.TrimPrefix(authHeader, "Bearer ")
69+
token = strings.TrimSpace(token)
70+
config = &cu.Config{GithubToken: token}
71+
}
72+
73+
// Fetch star history for all repositories
74+
result := cu.MultiRepoStarHistory{
75+
Repositories: make([]cu.StarHistory, 0, len(repos)),
76+
}
77+
78+
for _, repoURL := range repos {
79+
owner, repo, err := extractRepoInfo(repoURL)
80+
if err != nil {
81+
http.Error(w, fmt.Sprintf("Invalid repository URL: %v", err), http.StatusBadRequest)
82+
return
83+
}
84+
85+
history, err := getStarHistory(owner, repo, config)
86+
if err != nil {
87+
http.Error(w, err.Error(), http.StatusInternalServerError)
88+
return
89+
}
90+
91+
result.Repositories = append(result.Repositories, *history)
92+
}
93+
94+
w.Header().Set("Content-Type", "application/json")
95+
json.NewEncoder(w).Encode(result)
96+
}
97+
func HandleOrgContributors(w http.ResponseWriter, r *http.Request) {
98+
if r.Method != http.MethodGet {
99+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
100+
return
101+
}
102+
103+
org := r.URL.Query().Get("org")
104+
if org == "" {
105+
http.Error(w, "Organization name is required", http.StatusBadRequest)
106+
return
107+
}
108+
109+
// Make token optional
110+
var config *cu.Config
111+
authHeader := r.Header.Get("Authorization")
112+
if authHeader != "" {
113+
token := strings.TrimPrefix(authHeader, "Bearer ")
114+
token = strings.TrimSpace(token)
115+
config = &cu.Config{GithubToken: token}
116+
}
117+
118+
stats, err := getOrgContributors(org, config)
119+
if err != nil {
120+
http.Error(w, err.Error(), http.StatusInternalServerError)
121+
return
122+
}
123+
124+
w.Header().Set("Content-Type", "application/json")
125+
json.NewEncoder(w).Encode(stats)
126+
}

handlers/static.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package handlers
2+
3+
import "net/http"
4+
5+
func ServerIndex(w http.ResponseWriter, r *http.Request) {
6+
if r.URL.Path == "/" {
7+
http.ServeFile(w, r, "./web/index.html")
8+
return
9+
}
10+
http.NotFound(w, r)
11+
}
12+
func ServerOrgPage(w http.ResponseWriter, r *http.Request) {
13+
if r.URL.Path == "/orgs" {
14+
http.ServeFile(w, r, "./web/org.html")
15+
return
16+
}
17+
}
18+
func ServerStartPage(w http.ResponseWriter, r *http.Request) {
19+
if r.URL.Path == "/starhistory" {
20+
http.ServeFile(w, r, "./web/stars.html")
21+
return
22+
}
23+
}

0 commit comments

Comments
 (0)