package main
import (
"coin/exam07/blockchain"
"fmt"
"html/template"
"log"
"net/http"
)
const port string = ":4000"
type homeData struct {
// public/private는 template까지 영향을 준다.
PageTitle string
Blocks []*blockchain.Block
}
func home(rw http.ResponseWriter, r *http.Request) {
// template.Must() err가 있다면 처리해준다. 에러가 없으면 Template pointer를 반환한다.
tmpl := template.Must(template.ParseFiles("templates/home.html"))
// 블록체인을 블러와 저장한다.
data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
tmpl.Execute(rw, data)
}
func main() {
http.HandleFunc("/", home)
fmt.Printf("Listening on http://localhost%s\n", port)
// 에러가 있을때만 실행
log.Fatal(http.ListenAndServe(port, nil))
}
package blockchain
import (
"crypto/sha256"
"fmt"
"sync"
)
// main.go에서 가져다 쓰기위해 임시로 대문자로 변경
type Block struct {
Data string
Hash string
PrevHash string
}
type blockchain struct {
blocks []*Block
}
var b *blockchain
var once sync.Once
func (b *Block) calculateHash() {
hash := sha256.Sum256([]byte(b.Data + b.PrevHash))
b.Hash = fmt.Sprintf("%x", hash)
}
func getLastHash() string {
totalBlocks := len(GetBlockchain().blocks)
if totalBlocks == 0 {
return ""
}
return GetBlockchain().blocks[totalBlocks-1].Hash
}
func createBlock(data string) *Block {
newBlock := Block{data, "", getLastHash()}
newBlock.calculateHash()
return &newBlock
}
// export 함수
func (b *blockchain) AddBlock(data string) {
b.blocks = append(b.blocks, createBlock(data))
}
func GetBlockchain() *blockchain {
if b == nil {
once.Do(func() {
b = &blockchain{}
b.AddBlock("Genesis Block")
})
}
return b
}
// 사용자에게 field를 드러내주는 function(singleton의 철학)
func (b *blockchain) AllBlocks() []*Block {
return b.blocks
// return GetBlockchain().blocks
}
package main
import (
"coin/exam08/blockchain"
"fmt"
"html/template"
"log"
"net/http"
)
const port string = ":4000"
type homeData struct {
// public/private는 template까지 영향을 준다.
PageTitle string
Blocks []*blockchain.Block
}
func home(rw http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("templates/home.gohtml"))
data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
tmpl.Execute(rw, data)
}
func main() {
http.HandleFunc("/", home)
fmt.Printf("Listening on http://localhost%s\n", port)
// 에러가 있을때만 실행
log.Fatal(http.ListenAndServe(port, nil))
}
package blockchain
import (
"crypto/sha256"
"fmt"
"sync"
)
// main.go에서 가져다 쓰기위해 임시로 대문자로 변경
type Block struct {
Data string
Hash string
PrevHash string
}
type blockchain struct {
blocks []*Block
}
var b *blockchain
var once sync.Once
func (b *Block) calculateHash() {
hash := sha256.Sum256([]byte(b.Data + b.PrevHash))
b.Hash = fmt.Sprintf("%x", hash)
}
func getLastHash() string {
totalBlocks := len(GetBlockchain().blocks)
if totalBlocks == 0 {
return ""
}
return GetBlockchain().blocks[totalBlocks-1].Hash
}
func createBlock(data string) *Block {
newBlock := Block{data, "", getLastHash()}
newBlock.calculateHash()
return &newBlock
}
// export 함수
func (b *blockchain) AddBlock(data string) {
b.blocks = append(b.blocks, createBlock(data))
}
func GetBlockchain() *blockchain {
if b == nil {
once.Do(func() {
b = &blockchain{}
b.AddBlock("Genesis Block")
})
}
return b
}
// 사용자에게 field를 드러내주는 function(singleton의 철학)
func (b *blockchain) AllBlocks() []*Block {
return b.blocks
// return GetBlockchain().blocks
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css">
<title>Coin</title>
</head>
<body>
<header>
<h1>{{.PageTitle}}</h1>
</header>
<main>
{{range .Blocks}}
{{/* .Data는 실제 Blocks 안에 있는 Data를 의미한다. */}}
{{/* 가져올 값들은 모두 대문자로 시작해야하고 struct에 있는 field명과 같아야한다. */}}
<section>
<ul>
<li>{{.Data}}</li>
<li>{{.Hash}}</li>
<li>{{.PrevHash}}</li>
</ul>
<section>
{{end}}
</main>
</body>
</html>
package main
import (
"coin/exam09/blockchain"
"fmt"
"html/template"
"log"
"net/http"
)
const (
port string = ":4000"
templateDir string = "templates/"
)
var templates *template.Template
type homeData struct {
// public/private는 template까지 영향을 준다.
PageTitle string
Blocks []*blockchain.Block
}
func home(rw http.ResponseWriter, r *http.Request) {
data := homeData{"Home", blockchain.GetBlockchain().AllBlocks()}
templates.ExecuteTemplate(rw, "home", data)
}
func main() {
// tamplates를 업데이트한다.(templates는 pages/*.gohtml을 가지고 있게되고)
templates = template.Must(template.ParseGlob(templateDir + "pages/*.gohtml"))
// 해당 라인이 실행되면 templates variable은 template Object가 된다.
// (templates는 partials/*.gohtml도 함께 가지고 있게 된다.)
templates = template.Must(templates.ParseGlob(templateDir + "partials/*.gohtml"))
http.HandleFunc("/", home)
fmt.Printf("Listening on http://localhost%s\n", port)
// 에러가 있을때만 실행
log.Fatal(http.ListenAndServe(port, nil))
}
{{define "add"}}
<!DOCTYPE html>
<html lang="en">
{{template "head"}}
<body>
{{template "header"}}
<main>
<form>
<input type="text" placeholder="Data for your block" required />
</form>
</main>
{{template "footer"}}
</body>
</html>
{{end}}
{{define "home"}}
<!DOCTYPE html>
<html lang="en">
{{template "head"}}
<body>
{{template "header"}}
<main>
{{range .Blocks}}
{{template "Block"}}
{{end}}
</main>
{{template "footer"}}
</body>
</html>
{{end}}
{{define "Block"}}
<div>
<ul>
<li>{{.Data}}</li>
<li>{{.Hash}}</li>
{{if .PreHash}}
<li>{{.PreHash}}</li>
{{end}}
</ul>
</div>
<hr />
{{end}}
{{define "footer"}}
<footer>© 2022</footer>
{{end}}
{{define "head"}}
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css">
<title>Coin</title>
</head>
{{end}}
{{define "header"}}
<header>
<nav>
<a href="/"><h1>FDongFDong 코인</h1></a>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/add">Add</a>
</li>
</ul>
</nav>
<h1>{{.PageTitle}}</h1>
</header>
{{end}}