Skip to content

Commit

Permalink
[refactor]: separating Code for better readability (#5)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
RAJ6MAURYA and rmaurya authored Dec 30, 2024
1 parent 0cb761a commit b5f7786
Show file tree
Hide file tree
Showing 7 changed files with 559 additions and 514 deletions.
12 changes: 12 additions & 0 deletions common/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package common

import "os"

// Get port from environment variable or use default
func GetPort() string {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
return port
}
68 changes: 68 additions & 0 deletions common/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package common

import "time"

// ReleaseAsset represents a single asset in a release
type ReleaseAsset struct {
Name string `json:"name"`
DownloadCount int `json:"download_count"`
}

// Release represents a GitHub release
type Release struct {
ID int `json:"id"`
TagName string `json:"tag_name"`
CreatedAt time.Time `json:"created_at"`
Assets []ReleaseAsset `json:"assets"`
}

// ReleaseDownloadStats represents download statistics for a single release
type ReleaseDownloadStats struct {
TagName string `json:"tag_name"`
CreatedAt time.Time `json:"created_at"`
TotalDownloads int `json:"total_downloads"`
Assets []AssetStats `json:"assets"`
}

// AssetStats represents download statistics for a single asset
type AssetStats struct {
Name string `json:"name"`
DownloadCount int `json:"download_count"`
}

// DownloadStats represents download statistics for all releases
type DownloadStats struct {
RepoName string `json:"repo_name"`
TotalDownloads int `json:"total_downloads"`
Releases []ReleaseDownloadStats `json:"releases"`
}

type Config struct {
GithubToken string
}

type Contributor struct {
Login string `json:"login"`
}

type OrganizationStats struct {
OrgName string `json:"org_name"`
TotalRepos int `json:"total_repos"`
TotalContributors int `json:"total_contributors"`
}

type StarHistory struct {
RepoName string `json:"repo_name"`
History []StarPoint `json:"history"`
}

// StarPoint represents stars at a specific point in time
type StarPoint struct {
Date time.Time `json:"date"`
Stars int `json:"stars"`
}

// MultiRepoStarHistory represents star history for multiple repositories
type MultiRepoStarHistory struct {
Repositories []StarHistory `json:"repositories"`
}
126 changes: 126 additions & 0 deletions handlers/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package handlers

import (
"encoding/json"
"fmt"
"net/http"
"strings"

cu "github.com/sonichigo/hg/common"
)

func HandleRepoStats(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

repoURL := r.URL.Query().Get("repo")
if repoURL == "" {
http.Error(w, "Repository URL is required", http.StatusBadRequest)
return
}

owner, repo, err := extractRepoInfo(repoURL)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid repository URL: %v", err), http.StatusBadRequest)
return
}

// Make token optional
var config *cu.Config
authHeader := r.Header.Get("Authorization")
if authHeader != "" {
token := strings.TrimPrefix(authHeader, "Bearer ")
token = strings.TrimSpace(token)
config = &cu.Config{GithubToken: token}
}

releases, err := getAllReleases(owner, repo, config)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

stats := calculateDownloadStats(releases)
stats.RepoName = fmt.Sprintf("%s/%s", owner, repo)

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stats)
}
func HandleStarHistory(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

// Get repositories from query parameter
repos := r.URL.Query()["repo"]
if len(repos) == 0 {
http.Error(w, "At least one repository URL is required", http.StatusBadRequest)
return
}

// Make token optional
var config *cu.Config
authHeader := r.Header.Get("Authorization")
if authHeader != "" {
token := strings.TrimPrefix(authHeader, "Bearer ")
token = strings.TrimSpace(token)
config = &cu.Config{GithubToken: token}
}

// Fetch star history for all repositories
result := cu.MultiRepoStarHistory{
Repositories: make([]cu.StarHistory, 0, len(repos)),
}

for _, repoURL := range repos {
owner, repo, err := extractRepoInfo(repoURL)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid repository URL: %v", err), http.StatusBadRequest)
return
}

history, err := getStarHistory(owner, repo, config)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

result.Repositories = append(result.Repositories, *history)
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
func HandleOrgContributors(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

org := r.URL.Query().Get("org")
if org == "" {
http.Error(w, "Organization name is required", http.StatusBadRequest)
return
}

// Make token optional
var config *cu.Config
authHeader := r.Header.Get("Authorization")
if authHeader != "" {
token := strings.TrimPrefix(authHeader, "Bearer ")
token = strings.TrimSpace(token)
config = &cu.Config{GithubToken: token}
}

stats, err := getOrgContributors(org, config)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stats)
}
23 changes: 23 additions & 0 deletions handlers/static.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package handlers

import "net/http"

func ServerIndex(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "./web/index.html")
return
}
http.NotFound(w, r)
}
func ServerOrgPage(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/orgs" {
http.ServeFile(w, r, "./web/org.html")
return
}
}
func ServerStartPage(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/starhistory" {
http.ServeFile(w, r, "./web/stars.html")
return
}
}
Loading

0 comments on commit b5f7786

Please sign in to comment.