-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrandy.go
140 lines (111 loc) · 3.07 KB
/
randy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"time"
"hash"
"crypto/md5"
"crypto/sha256"
"crypto/sha512"
)
// Randy represents runtime structure.
type Randy struct {
HashAlgo string
Hostname string
Port string
RunCounter int
CurrentCounter int
}
var randy *Randy
var hashes = map[string]bool {
"md5": true,
"sha256": true,
"sha512": true,
"raw": true,
}
func main() {
initRandy()
log.Print(fmt.Sprintf("Randy initialized, running on port %s", randy.Port))
http.HandleFunc("/", randyHandler)
log.Fatal(http.ListenAndServe(":"+randy.Port, nil))
}
func randyHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, randy.ToString())
}
// ToString returns current Randy structure as a final ID string.
func (randy *Randy) ToString() string {
uid := fmt.Sprintf("%d:%d:%d:%s:%s", randy.Timestamp(), randy.RunCounter, randy.Increment(), randy.Hostname, randy.Port)
hash := randy.CreateHash()
// If hash type is "raw" - just return generated uid.
// You should never use "raw" in production as it will expose your hostnames!
if hash == nil {
return uid
}
hash.Write([]byte(uid))
return fmt.Sprintf("%x", hash.Sum(nil))
}
// Increment increments internal Randy counter.
func (randy *Randy) Increment() int {
randy.CurrentCounter++
return randy.CurrentCounter
}
// Timestamp returns current datetime in unix format in nanoseconds.
func (randy *Randy) Timestamp() int64 {
return time.Now().UnixNano()
}
// CreateHash creates object that will be used to hash ids
func (randy *Randy) CreateHash() hash.Hash {
switch randy.HashAlgo {
case "raw":
return nil
case "md5":
return md5.New()
case "sha256":
return sha256.New()
case "sha512":
return sha512.New()
}
return nil
}
func initRandy() {
portFlag := flag.String("port", "8080", "port on which Randy will listen")
hashFlag := flag.String("hash", "raw", "function to hash ids")
flag.Parse()
if !hashes[*hashFlag] {
log.Panic(fmt.Sprintf("\"%s\" is not a valid hash function", *hashFlag))
}
runCounter := loadRunCounter(*portFlag)
hostname, err := os.Hostname()
if err != nil {
log.Panic(err)
}
randy = &Randy{
HashAlgo: *hashFlag,
Hostname: hostname,
Port: *portFlag,
RunCounter: runCounter,
CurrentCounter: 0,
}
}
// Randy stores counters of process initialization in counter files.
func loadRunCounter(port string) int {
filename := "counter/" + port + ".cnt"
var currentCounter int
count, err := ioutil.ReadFile(filename)
if err != nil {
currentCounter = -1
} else {
currentCounter, _ = strconv.Atoi(string(count))
}
currentCounter = currentCounter + 1
err = ioutil.WriteFile(filename, []byte(strconv.Itoa(currentCounter)), 0600)
if err != nil {
log.Panic(err)
}
return currentCounter
}