Skip to content
Open

i #3

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Build and Upload Artifacts
on:
push:
branches: [ main ]

jobs:
build-and-upload:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2

- name: Build Server
run: |
go build serve.go
echo "Server built successfully!"
ls

- name: Build Client
run: |
cd client
go build fcdn.go

- name: Upload Artifacts
uses: actions/upload-artifact@v2
with:
name: server-and-client
path: |
./server
./client/fcdn
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# FCDN
Download the same file from 2 server for increase speed and low bandwidth usage

Try Now:
Step 1: Download the fcdn client first
https://github.com/pawitpr/fcdn-client

Step2: We have already setup the server for you (https://cdn1-osyp.onrender.com/) (https://cdn0.onrender.com/)
and this is a test command:
```bash
fcdn.exe -a rootfs.xz https://cdn1-osyp.onrender.com/cdn/ubuntu-rootfs-arm64.tar.xz https://cdn0.onrender.com/cdn/ubuntu-rootfs-arm64.tar.xz
```

# Demo Video
https://github.com/pawitpr/fcdn/assets/123424956/7c80fda9-787a-4ee3-baa2-1924d96b2d83

Binary file added cdn/2023-05-17 09-31-49.mp4
Binary file not shown.
95 changes: 95 additions & 0 deletions client/fcdn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package main

import (
"flag"
"fmt"
"io"
"net/http"
"os"
"sync"
"time"
)

func download(url string, wg *sync.WaitGroup, dest string) {
defer wg.Done()

startTime := time.Now()

// Create a new HTTP GET request
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Error downloading %s: %s\n", url, err)
return
}
defer resp.Body.Close()

// Create a new file to save the downloaded data
file, err := os.Create(dest)
if err != nil {
fmt.Printf("Error creating file: %s\n", err)
return
}
defer file.Close()

// Copy the response body to the file while measuring speed
_, err = io.Copy(file, io.TeeReader(resp.Body, &SpeedMeasurer{}))
if err != nil {
fmt.Printf("Error saving file: %s\n", err)
return
}

elapsedTime := time.Since(startTime)
downloadSpeed := float64(resp.ContentLength) / elapsedTime.Seconds() / 1024 / 1024 // Speed in MB/s

fmt.Printf("Downloaded %s\n", url)
fmt.Printf("Elapsed Time: %s\n", elapsedTime)
fmt.Printf("Download Speed: %.2f MB/s\n", downloadSpeed)
}

type SpeedMeasurer struct {
totalBytes int64
lastTime time.Time
}

func (sm *SpeedMeasurer) Write(p []byte) (n int, err error) {
n = len(p)
sm.totalBytes += int64(n)

if sm.lastTime.IsZero() {
sm.lastTime = time.Now()
} else {
elapsedTime := time.Since(sm.lastTime)
if elapsedTime.Seconds() >= 1 {
downloadSpeed := float64(sm.totalBytes) / elapsedTime.Seconds() / 1024 / 1024 // Speed in MB/s
fmt.Printf("Current Download Speed: %.2f MB/s\n", downloadSpeed)
sm.totalBytes = 0
sm.lastTime = time.Now()
}
}

return
}

func main() {
// Parse command-line arguments
var fileName string
flag.StringVar(&fileName, "a", "file.txt", "Destination file name")
flag.Parse()

// Get the server URLs from command-line arguments
urls := flag.Args()
if len(urls) == 0 {
fmt.Println("Please provide server URLs")
return
}

var wg sync.WaitGroup
wg.Add(len(urls))

for _, url := range urls {
go download(url, &wg, fileName)
}

wg.Wait()
fmt.Println("All downloads completed")
}
3 changes: 3 additions & 0 deletions client/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module example.com/m

go 1.20
7 changes: 7 additions & 0 deletions client/key
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDTR0qHiT5bRaqJd1wuchb6owbjxHGIMfOT/SLlYG07lQAAAJjWZ3Ol1mdz
pQAAAAtzc2gtZWQyNTUxOQAAACDTR0qHiT5bRaqJd1wuchb6owbjxHGIMfOT/SLlYG07lQ
AAAED4vE/GvgmPUCeRRtgWzubzAXq+Ody24dnw6JH/3PrwoNNHSoeJPltFqol3XC5yFvqj
BuPEcYgx85P9IuVgbTuVAAAAFXBhd2l0c2FoYXJlQGdtYWlsLmNvbQ==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions client/key.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINNHSoeJPltFqol3XC5yFvqjBuPEcYgx85P9IuVgbTuV pawitsahare@gmail.com
27 changes: 27 additions & 0 deletions serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Serve is a very simple static file server in go
Usage:
-p="8100": port to serve on
-d=".": the directory of static files to host
Navigating to http://localhost:8100 will display the index.html or directory
listing file.
*/
package main

import (
"flag"
"log"
"net/http"
)

func main() {
port := flag.String("p", "8100", "port to serve on")
directory := flag.String("d", ".", "the directory of static file to host")
flag.Parse()

http.Handle("/", http.FileServer(http.Dir(*directory)))

log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
//