Commit 6a5c6931ebe949e22aada7d63497bcff1ac6c402
1 parent
2c237577d3
Exists in
master
added database map to server
Showing
4 changed files
with
62 additions
and
45 deletions
Show diff stats
document/document.go
1 | package document | 1 | package document |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "errors" | 4 | "errors" |
5 | "fmt" | 5 | "fmt" |
6 | "io" | 6 | "io" |
7 | "mime" | 7 | "mime" |
8 | "net/http" | 8 | "net/http" |
9 | "os" | 9 | "os" |
10 | "strings" | ||
11 | "time" | 10 | "time" |
12 | 11 | ||
13 | web "git.to-net.rs/marko.tikvic/webutility" | 12 | web "git.to-net.rs/marko.tikvic/webutility" |
14 | ) | 13 | ) |
15 | 14 | ||
16 | // Document ... | 15 | // Document ... |
17 | type Document struct { | 16 | type Document struct { |
18 | ID int64 `json:"id"` | 17 | ID int64 `json:"id"` |
19 | FileName string `json:"fileName"` | 18 | FileName string `json:"fileName"` |
20 | Extension string `json:"extension"` | 19 | Extension string `json:"extension"` |
21 | ContentType string `json:"contentType"` | 20 | ContentType string `json:"contentType"` |
22 | Size int64 `json:"fileSize"` | 21 | Size int64 `json:"fileSize"` |
23 | UploadedBy string `json:"uploadedBy"` | 22 | UploadedBy string `json:"uploadedBy"` |
24 | LastModifiedBy string `json:"lastModifiedBy"` | 23 | LastModifiedBy string `json:"lastModifiedBy"` |
25 | TimeUploaded int64 `json:"timeUploaded"` | 24 | TimeUploaded int64 `json:"timeUploaded"` |
26 | TimeLastModified int64 `json:"timeLastModified"` | 25 | TimeLastModified int64 `json:"timeLastModified"` |
27 | RoleAccessLevel int64 `json:"accessLevel"` | 26 | RoleAccessLevel int64 `json:"accessLevel"` |
28 | Description string `json:"description"` | 27 | Description string `json:"description"` |
29 | Download *DownloadLink `json:"download"` | 28 | Download *DownloadLink `json:"download"` |
30 | Path string `json:"-"` | 29 | Path string `json:"-"` |
31 | directory string | 30 | directory string |
32 | data []byte | 31 | data []byte |
33 | } | 32 | } |
34 | 33 | ||
35 | // OpenFileAsDocument ... | 34 | // OpenFileAsDocument ... |
36 | func OpenFileAsDocument(path string) (*Document, error) { | 35 | func OpenFileAsDocument(path string) (*Document, error) { |
37 | d := &Document{Path: path} | 36 | d := &Document{Path: path} |
38 | 37 | ||
39 | f, err := os.Open(d.Path) | 38 | f, err := os.Open(d.Path) |
40 | if err != nil { | 39 | if err != nil { |
41 | return nil, err | 40 | return nil, err |
42 | } | 41 | } |
43 | defer f.Close() | 42 | defer f.Close() |
44 | 43 | ||
45 | stats, err := f.Stat() | 44 | stats, err := f.Stat() |
46 | if err != nil { | 45 | if err != nil { |
47 | return nil, err | 46 | return nil, err |
48 | } | 47 | } |
49 | 48 | ||
50 | d.FileName = stats.Name() | 49 | d.FileName = stats.Name() |
51 | d.Size = stats.Size() | 50 | d.Size = stats.Size() |
52 | d.Extension = FileExtension(d.FileName) | 51 | d.Extension = web.FileExtension(d.FileName) |
53 | 52 | ||
54 | d.data = make([]byte, d.Size) | 53 | d.data = make([]byte, d.Size) |
55 | if _, err = f.Read(d.data); err != nil { | 54 | if _, err = f.Read(d.data); err != nil { |
56 | return nil, err | 55 | return nil, err |
57 | } | 56 | } |
58 | 57 | ||
59 | return d, err | 58 | return d, err |
60 | } | 59 | } |
61 | 60 | ||
62 | // DownloadLink ... | 61 | // DownloadLink ... |
63 | type DownloadLink struct { | 62 | type DownloadLink struct { |
64 | Method string `json:"method"` | 63 | Method string `json:"method"` |
65 | URL string `json:"url"` | 64 | URL string `json:"url"` |
66 | } | 65 | } |
67 | 66 | ||
68 | // SetDownloadInfo ... | 67 | // SetDownloadInfo ... |
69 | func (d *Document) SetDownloadInfo(method, url string) { | 68 | func (d *Document) SetDownloadInfo(method, url string) { |
70 | d.Download = &DownloadLink{ | 69 | d.Download = &DownloadLink{ |
71 | Method: method, | 70 | Method: method, |
72 | URL: url, | 71 | URL: url, |
73 | } | 72 | } |
74 | } | 73 | } |
75 | 74 | ||
76 | // ServeDocument writes d's buffer to w and sets appropriate headers according to d's content type | 75 | // ServeDocument writes d's buffer to w and sets appropriate headers according to d's content type |
77 | // and downloadPrompt. | 76 | // and downloadPrompt. |
78 | func ServeDocument(w http.ResponseWriter, d *Document, downloadPrompt bool) error { | 77 | func ServeDocument(w http.ResponseWriter, d *Document, downloadPrompt bool) error { |
79 | f, err := os.Open(d.Path) | 78 | f, err := os.Open(d.Path) |
80 | if err != nil { | 79 | if err != nil { |
81 | return err | 80 | return err |
82 | } | 81 | } |
83 | defer f.Close() | 82 | defer f.Close() |
84 | 83 | ||
85 | web.SetContentType(w, mime.TypeByExtension(d.Extension)) | 84 | web.SetContentType(w, mime.TypeByExtension(d.Extension)) |
86 | web.SetResponseStatus(w, http.StatusOK) | 85 | web.SetResponseStatus(w, http.StatusOK) |
87 | if downloadPrompt { | 86 | if downloadPrompt { |
88 | w.Header().Set("Content-Disposition", "attachment; filename="+d.FileName) | 87 | w.Header().Set("Content-Disposition", "attachment; filename="+d.FileName) |
89 | } | 88 | } |
90 | 89 | ||
91 | buf := make([]byte, d.Size) | 90 | buf := make([]byte, d.Size) |
92 | if _, err := f.Read(buf); err != nil { | 91 | if _, err := f.Read(buf); err != nil { |
93 | return err | 92 | return err |
94 | } | 93 | } |
95 | 94 | ||
96 | w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size)) | 95 | w.Header().Set("Content-Length", fmt.Sprintf("%d", d.Size)) |
97 | web.WriteResponse(w, buf) | 96 | web.WriteResponse(w, buf) |
98 | 97 | ||
99 | return nil | 98 | return nil |
100 | } | 99 | } |
101 | 100 | ||
102 | // FileExists ... | ||
103 | func FileExists(path string) bool { | ||
104 | temp, err := os.Open(path) | ||
105 | defer temp.Close() | ||
106 | |||
107 | if err != nil { | ||
108 | return false | ||
109 | } | ||
110 | |||
111 | return true | ||
112 | } | ||
113 | |||
114 | // ParseDocument ... | 101 | // ParseDocument ... |
115 | func ParseDocument(req *http.Request) (doc *Document, err error) { | 102 | func ParseDocument(req *http.Request) (doc *Document, err error) { |
116 | req.ParseMultipartForm(32 << 20) | 103 | req.ParseMultipartForm(32 << 20) |
117 | file, fheader, err := req.FormFile("document") | 104 | file, fheader, err := req.FormFile("document") |
118 | if err != nil { | 105 | if err != nil { |
119 | return doc, err | 106 | return doc, err |
120 | } | 107 | } |
121 | 108 | ||
122 | claims, _ := web.GetTokenClaims(req) | 109 | claims, _ := web.GetTokenClaims(req) |
123 | owner := claims.Username | 110 | owner := claims.Username |
124 | 111 | ||
125 | fname := fheader.Filename | 112 | fname := fheader.Filename |
126 | 113 | ||
127 | fsize := fheader.Size | 114 | fsize := fheader.Size |
128 | ftype := fmt.Sprintf("%v", fheader.Header["Content-Type"][0]) | 115 | ftype := fmt.Sprintf("%v", fheader.Header["Content-Type"][0]) |
129 | 116 | ||
130 | fextn := FileExtension(fname) | 117 | fextn := web.FileExtension(fname) |
131 | if fextn == "" { | 118 | if fextn == "" { |
132 | return doc, errors.New("invalid extension") | 119 | return doc, errors.New("invalid extension") |
133 | } | 120 | } |
134 | 121 | ||
135 | doc = new(Document) | 122 | doc = new(Document) |
136 | 123 | ||
137 | doc.FileName = fname | 124 | doc.FileName = fname |
138 | doc.Size = fsize | 125 | doc.Size = fsize |
139 | doc.ContentType = ftype | 126 | doc.ContentType = ftype |
140 | doc.Extension = "." + fextn | 127 | doc.Extension = "." + fextn |
141 | 128 | ||
142 | t := time.Now().Unix() | 129 | t := time.Now().Unix() |
143 | doc.TimeUploaded = t | 130 | doc.TimeUploaded = t |
144 | doc.TimeLastModified = t | 131 | doc.TimeLastModified = t |
145 | 132 | ||
146 | doc.UploadedBy = owner | 133 | doc.UploadedBy = owner |
147 | doc.LastModifiedBy = owner | 134 | doc.LastModifiedBy = owner |
148 | doc.RoleAccessLevel = 0 | 135 | doc.RoleAccessLevel = 0 |
149 | 136 | ||
150 | doc.data = make([]byte, doc.Size) | 137 | doc.data = make([]byte, doc.Size) |
151 | if _, err = io.ReadFull(file, doc.data); err != nil { | 138 | if _, err = io.ReadFull(file, doc.data); err != nil { |
152 | return doc, err | 139 | return doc, err |
153 | } | 140 | } |
154 | 141 | ||
155 | return doc, nil | 142 | return doc, nil |
156 | } | 143 | } |
157 | 144 | ||
158 | // DirectoryFromPath ... | ||
159 | func DirectoryFromPath(path string) (dir string) { | ||
160 | parts := strings.Split(path, "/") | ||
161 | if len(parts) == 1 { | ||
162 | return "" | ||
163 | } | ||
164 | |||
165 | dir = parts[0] | ||
166 | for _, p := range parts[1 : len(parts)-1] { | ||
167 | dir += "/" + p | ||
168 | } | ||
169 | |||
170 | return dir | ||
171 | } | ||
172 | |||
173 | // SaveToFile ... | 145 | // SaveToFile ... |
174 | func (d *Document) SaveToFile(path string) (f *os.File, err error) { | 146 | func (d *Document) SaveToFile(path string) (f *os.File, err error) { |
175 | d.Path = path | 147 | d.Path = path |
176 | 148 | ||
177 | if FileExists(path) { | 149 | if web.FileExists(path) { |
178 | err = fmt.Errorf("file %s alredy exists", path) | 150 | err = fmt.Errorf("file %s alredy exists", path) |
179 | return nil, err | 151 | return nil, err |
180 | } | 152 | } |
181 | 153 | ||
182 | if parentDir := DirectoryFromPath(path); parentDir != "" { | 154 | if parentDir := web.DirectoryFromPath(path); parentDir != "" { |
183 | if err = os.MkdirAll(parentDir, os.ModePerm); err != nil { | 155 | if err = os.MkdirAll(parentDir, os.ModePerm); err != nil { |
184 | if !os.IsExist(err) { | 156 | if !os.IsExist(err) { |
185 | return nil, err | 157 | return nil, err |
186 | } | 158 | } |
187 | } | 159 | } |
188 | } | 160 | } |
189 | 161 | ||
190 | if f, err = os.Create(path); err != nil { | 162 | if f, err = os.Create(path); err != nil { |
191 | return nil, err | 163 | return nil, err |
192 | } | 164 | } |
193 | 165 | ||
194 | if _, err = f.Write(d.data); err != nil { | 166 | if _, err = f.Write(d.data); err != nil { |
195 | f.Close() | 167 | f.Close() |
196 | d.DeleteFile() | 168 | d.DeleteFile() |
197 | return nil, err | 169 | return nil, err |
198 | } | 170 | } |
199 | f.Close() | 171 | f.Close() |
200 | 172 | ||
201 | return f, nil | 173 | return f, nil |
202 | } | 174 | } |
203 | 175 | ||
204 | func DeleteFile(path string) error { | ||
205 | return os.Remove(path) | ||
206 | } | ||
207 | |||
208 | func DeleteDocuments(docs []*Document) error { | 176 | func DeleteDocuments(docs []*Document) error { |
209 | for _, d := range docs { | 177 | for _, d := range docs { |
210 | if err := d.DeleteFile(); err != nil { | 178 | if err := d.DeleteFile(); err != nil { |
211 | return err | 179 | return err |
212 | } | 180 | } |
213 | } | 181 | } |
214 | return nil | 182 | return nil |
215 | } | 183 | } |
216 | 184 | ||
217 | // DeleteFile ... | 185 | // DeleteFile ... |
218 | func (d *Document) DeleteFile() error { | 186 | func (d *Document) DeleteFile() error { |
219 | return os.Remove(d.Path) | 187 | return os.Remove(d.Path) |
220 | } | 188 | } |
221 | |||
222 | func FileExtension(path string) string { | ||
223 | parts := strings.Split(path, ".") // because name can contain dots | ||
224 | if len(parts) < 2 { | ||
225 | return "" | ||
226 | } | ||
227 | return "." + parts[len(parts)-1] | ||
228 | } | ||
229 | 189 |
file_util.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | 4 | "bytes" |
5 | "fmt" | ||
5 | "io" | 6 | "io" |
6 | "io/ioutil" | 7 | "io/ioutil" |
7 | "os" | 8 | "os" |
8 | "strings" | 9 | "strings" |
9 | ) | 10 | ) |
10 | 11 | ||
11 | // ReadFileContent ... | 12 | // ReadFileContent ... |
12 | func ReadFileContent(path string) ([]byte, error) { | 13 | func ReadFileContent(path string) ([]byte, error) { |
13 | f, err := os.Open(path) | 14 | f, err := os.Open(path) |
14 | if err != nil { | 15 | if err != nil { |
15 | return nil, err | 16 | return nil, err |
16 | } | 17 | } |
17 | defer f.Close() | 18 | defer f.Close() |
18 | 19 | ||
19 | buf := &bytes.Buffer{} | 20 | buf := &bytes.Buffer{} |
20 | if _, err = io.Copy(buf, f); err != nil { | 21 | if _, err = io.Copy(buf, f); err != nil { |
21 | return nil, err | 22 | return nil, err |
22 | } | 23 | } |
23 | 24 | ||
24 | return buf.Bytes(), nil | 25 | return buf.Bytes(), nil |
25 | } | 26 | } |
26 | 27 | ||
27 | // ReadFileLines ... | 28 | // ReadFileLines ... |
28 | func ReadFileLines(path string) ([]string, error) { | 29 | func ReadFileLines(path string) ([]string, error) { |
29 | f, err := os.Open(path) | 30 | f, err := os.Open(path) |
30 | if err != nil { | 31 | if err != nil { |
31 | return nil, err | 32 | return nil, err |
32 | } | 33 | } |
33 | defer f.Close() | 34 | defer f.Close() |
34 | 35 | ||
35 | var s strings.Builder | 36 | var s strings.Builder |
36 | 37 | ||
37 | if _, err = io.Copy(&s, f); err != nil { | 38 | if _, err = io.Copy(&s, f); err != nil { |
38 | return nil, err | 39 | return nil, err |
39 | } | 40 | } |
40 | 41 | ||
41 | lines := strings.Split(s.String(), "\n") | 42 | lines := strings.Split(s.String(), "\n") |
42 | for i := range lines { | 43 | for i := range lines { |
43 | lines[i] = strings.TrimRight(lines[i], "\r\n") | 44 | lines[i] = strings.TrimRight(lines[i], "\r\n") |
44 | } | 45 | } |
45 | 46 | ||
46 | return lines, nil | 47 | return lines, nil |
47 | } | 48 | } |
48 | 49 | ||
49 | // LinesToFile ... | 50 | // LinesToFile ... |
50 | func LinesToFile(path string, lines []string) error { | 51 | func LinesToFile(path string, lines []string) error { |
51 | content := "" | 52 | content := "" |
52 | for _, l := range lines { | 53 | for _, l := range lines { |
53 | content += l + "\n" | 54 | content += l + "\n" |
54 | } | 55 | } |
55 | 56 | ||
56 | return ioutil.WriteFile(path, []byte(content), 0644) // drw-r--r-- | 57 | return ioutil.WriteFile(path, []byte(content), 0644) // drw-r--r-- |
57 | } | 58 | } |
58 | 59 | ||
59 | // InsertLine ... | 60 | // InsertLine ... |
60 | func InsertLine(lines *[]string, pos int64, l string) { | 61 | func InsertLine(lines *[]string, pos int64, l string) { |
61 | tail := append([]string{l}, (*lines)[pos:]...) | 62 | tail := append([]string{l}, (*lines)[pos:]...) |
62 | 63 | ||
63 | *lines = append((*lines)[:pos], tail...) | 64 | *lines = append((*lines)[:pos], tail...) |
64 | } | 65 | } |
65 | 66 | ||
66 | func WriteFile(path string, content []byte) error { | 67 | func WriteFile(path string, content []byte) error { |
67 | return ioutil.WriteFile(path, content, 0644) // drw-r--r-- | 68 | return ioutil.WriteFile(path, content, 0644) // drw-r--r-- |
68 | } | 69 | } |
69 | 70 | ||
70 | func ListDir(path string) (fnames []string, err error) { | 71 | func ListDir(path string) (fnames []string, err error) { |
71 | finfo, err := ioutil.ReadDir(path) | 72 | finfo, err := ioutil.ReadDir(path) |
72 | if err != nil { | 73 | if err != nil { |
73 | return nil, err | 74 | return nil, err |
74 | } | 75 | } |
75 | 76 | ||
76 | for _, f := range finfo { | 77 | for _, f := range finfo { |
77 | fnames = append(fnames, f.Name()) | 78 | fnames = append(fnames, f.Name()) |
78 | } | 79 | } |
79 | 80 | ||
80 | return fnames, nil | 81 | return fnames, nil |
81 | } | 82 | } |
82 | 83 | ||
83 | func WorkingDir() string { | 84 | func WorkingDir() string { |
84 | dir, _ := os.Getwd() | 85 | path, err := os.Getwd() |
86 | if err != nil { | ||
87 | fmt.Printf("couldn't get working directory: %s\n", err.Error()) | ||
88 | } | ||
89 | return path | ||
90 | } | ||
91 | |||
92 | func FileExtension(path string) string { | ||
93 | parts := strings.Split(path, ".") // because name can contain dots | ||
94 | if len(parts) < 2 { | ||
95 | return "" | ||
96 | } | ||
97 | return "." + parts[len(parts)-1] | ||
98 | } | ||
99 | |||
100 | func DeleteFile(path string) error { | ||
101 | return os.Remove(path) | ||
102 | } | ||
103 | |||
104 | // DirectoryFromPath ... | ||
105 | func DirectoryFromPath(path string) (dir string) { | ||
106 | parts := strings.Split(path, "/") | ||
107 | if len(parts) == 1 { | ||
108 | return "" | ||
109 | } | ||
110 | |||
111 | dir = parts[0] | ||
112 | for _, p := range parts[1 : len(parts)-1] { | ||
113 | dir += "/" + p | ||
114 | } | ||
115 | |||
85 | return dir | 116 | return dir |
86 | } | 117 | } |
118 | |||
119 | // FileExists ... | ||
120 | func FileExists(path string) bool { | ||
121 | temp, err := os.Open(path) | ||
122 | defer temp.Close() | ||
123 | |||
124 | if err != nil { | ||
125 | return false | ||
126 | } | ||
127 | |||
128 | return true | ||
129 | } | ||
87 | 130 |
float_util.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "math" | 5 | "math" |
6 | "math/big" | 6 | "math/big" |
7 | "strings" | 7 | "strings" |
8 | ) | 8 | ) |
9 | 9 | ||
10 | func RoundFloat64(f float64, dec int) float64 { | 10 | func RoundFloat64(f float64, dec int) float64 { |
11 | p := math.Pow(10, float64(dec)) | 11 | p := math.Pow(10, float64(dec)) |
12 | return math.Round(f*p) / p | 12 | return math.Round(f*p) / p |
13 | } | 13 | } |
14 | 14 | ||
15 | func NewBF(f float64, prec uint) *big.Float { | 15 | func NewBF(f float64, prec uint) *big.Float { |
16 | x := big.NewFloat(f) | 16 | x := big.NewFloat(f) |
17 | x.SetPrec(prec) | 17 | x.SetPrec(prec) |
18 | return x | 18 | return x |
19 | } | 19 | } |
20 | 20 | ||
21 | func AddBF(x, y *big.Float) *big.Float { | 21 | func AddBF(x, y *big.Float) *big.Float { |
22 | z := big.NewFloat(0.0) | 22 | z := big.NewFloat(0.0) |
23 | z.SetPrec(x.Prec()) | 23 | z.SetPrec(x.Prec()) |
24 | z.Add(x, y) | 24 | z.Add(x, y) |
25 | return z | 25 | return z |
26 | } | 26 | } |
27 | 27 | ||
28 | func SubBF(x, y *big.Float) *big.Float { | 28 | func SubBF(x, y *big.Float) *big.Float { |
29 | z := big.NewFloat(0.0) | 29 | z := big.NewFloat(0.0) |
30 | z.SetPrec(x.Prec()) | 30 | z.SetPrec(x.Prec()) |
31 | 31 | ||
32 | yneg := big.NewFloat(0.0) | 32 | yneg := big.NewFloat(0.0) |
33 | yneg.Neg(y) | 33 | yneg.Neg(y) |
34 | 34 | ||
35 | z.Add(x, yneg) | 35 | z.Add(x, yneg) |
36 | return z | 36 | return z |
37 | } | 37 | } |
38 | 38 | ||
39 | func MulBF(x, y *big.Float) *big.Float { | 39 | func MulBF(x, y *big.Float) *big.Float { |
40 | z := big.NewFloat(0.0) | 40 | z := big.NewFloat(0.0) |
41 | z.SetPrec(x.Prec()) | 41 | z.SetPrec(x.Prec()) |
42 | z.Mul(x, y) | 42 | z.Mul(x, y) |
43 | return z | 43 | return z |
44 | } | 44 | } |
45 | 45 | ||
46 | func DivBF(x, y *big.Float) *big.Float { | 46 | func DivBF(x, y *big.Float) *big.Float { |
47 | z := big.NewFloat(0.0) | 47 | z := big.NewFloat(0.0) |
48 | z.SetPrec(x.Prec()) | 48 | z.SetPrec(x.Prec()) |
49 | z.Quo(x, y) | 49 | z.Quo(x, y) |
50 | return z | 50 | return z |
51 | } | 51 | } |
52 | 52 | ||
53 | func BFtoFloat(f *big.Float) float64 { | 53 | func BFtoFloat(f *big.Float) float64 { |
54 | v, _ := f.Float64() | 54 | v, _ := f.Float64() |
55 | return v | 55 | return v |
56 | } | 56 | } |
57 | 57 | ||
58 | func Float64ToString(f float64) string { | 58 | func Float64ToString(f float64) string { |
59 | return fmt.Sprintf("%.2f", f) | 59 | return fmt.Sprintf("%.2f", f) |
60 | } | 60 | } |
61 | 61 | ||
62 | func Float64PtrToString(f *float64) string { | 62 | func Float64PtrToString(f *float64) string { |
63 | if f == nil { | 63 | if f == nil { |
64 | return "" | 64 | return "" |
65 | } | 65 | } |
66 | return fmt.Sprintf("%.2f", *f) | 66 | return fmt.Sprintf("%.2f", *f) |
67 | } | 67 | } |
68 | 68 | ||
69 | func FormatFloat64Number(f float64, dec int) string { | 69 | func FormatFloat64Number(f float64, dec int) string { |
70 | res := "" | 70 | res := "" |
71 | 71 | ||
72 | f = RoundFloat64(f, dec) | 72 | f = RoundFloat64(f, dec) |
73 | 73 | ||
74 | i := int64(f) | 74 | i := int64(f) |
75 | 75 | ||
76 | format := fmt.Sprintf("%%.%df", dec) | 76 | format := fmt.Sprintf("%%.%df", dec) |
77 | parts := strings.Split(fmt.Sprintf(format, f-float64(i)), ".") | 77 | parts := strings.Split(fmt.Sprintf(format, f-float64(i)), ".") |
78 | 78 | ||
79 | decimals := parts[1] | 79 | decimals := parts[1] |
80 | 80 | ||
81 | res = FormatInt64Number(i) + "," + decimals | 81 | res = FormatInt64Number(i) + "," + decimals |
82 | 82 | ||
83 | return res | 83 | return res |
84 | } | 84 | } |
85 | |||
86 | func MaxFlaot64(vars ...float64) (max float64) { | ||
87 | max = vars[0] | ||
88 | for _, v := range vars { | ||
89 | if v > max { | ||
90 | max = v | ||
91 | } | ||
92 | } | ||
93 | return max | ||
94 | } | ||
85 | 95 |
server.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "database/sql" | 4 | "database/sql" |
5 | "fmt" | 5 | "fmt" |
6 | "net/http" | 6 | "net/http" |
7 | 7 | ||
8 | "git.to-net.rs/marko.tikvic/gologger" | 8 | "git.to-net.rs/marko.tikvic/gologger" |
9 | "github.com/gorilla/mux" | 9 | "github.com/gorilla/mux" |
10 | ) | 10 | ) |
11 | 11 | ||
12 | type Server struct { | 12 | type Server struct { |
13 | DB *sql.DB | 13 | DB *sql.DB |
14 | Router *mux.Router | 14 | Router *mux.Router |
15 | Logger *gologger.Logger | 15 | Logger *gologger.Logger |
16 | Port string | 16 | Port string |
17 | UTCOffset int64 | 17 | UTCOffset int64 |
18 | DBs map[string]*sql.DB | ||
18 | } | 19 | } |
19 | 20 | ||
20 | func NewODBCServer(dsn, port, logDir string, utcOffset int64) (s *Server, err error) { | 21 | func NewODBCServer(dsn, port, logDir string, utcOffset int64) (s *Server, err error) { |
21 | s = new(Server) | 22 | s = new(Server) |
22 | 23 | ||
23 | s.Port = port | 24 | s.Port = port |
24 | 25 | ||
25 | if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil { | 26 | if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil { |
26 | return nil, err | 27 | return nil, err |
27 | } | 28 | } |
28 | 29 | ||
29 | s.Router = mux.NewRouter() | 30 | s.Router = mux.NewRouter() |
30 | 31 | ||
31 | if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil { | 32 | if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil { |
32 | return nil, fmt.Errorf("can't create logger: %s", err.Error()) | 33 | return nil, fmt.Errorf("can't create logger: %s", err.Error()) |
33 | } | 34 | } |
34 | 35 | ||
35 | s.UTCOffset = utcOffset | 36 | s.UTCOffset = utcOffset |
36 | 37 | ||
38 | s.DBs = make(map[string]*sql.DB) | ||
39 | s.DBs["default"] = s.DB | ||
40 | |||
37 | return s, nil | 41 | return s, nil |
38 | } | 42 | } |
39 | 43 | ||
40 | func (s *Server) Run() { | 44 | func (s *Server) Run() { |
41 | s.Logger.Print("Server listening on %s", s.Port) | 45 | s.Logger.Print("Server listening on %s", s.Port) |
42 | s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error()) | 46 | s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error()) |
43 | } | 47 | } |
44 | 48 | ||
45 | func (s *Server) Cleanup() { | 49 | func (s *Server) Cleanup() { |
46 | if s.DB != nil { | 50 | if s.DB != nil { |
47 | s.DB.Close() | 51 | s.DB.Close() |
48 | } | 52 | } |
49 | 53 | ||
50 | if s.Logger != nil { | 54 | if s.Logger != nil { |
51 | s.Logger.Close() | 55 | s.Logger.Close() |
52 | } | 56 | } |
53 | } | 57 | } |
54 | 58 | ||
55 | func (s *Server) StartTransaction() (*sql.Tx, error) { | 59 | func (s *Server) StartTransaction() (*sql.Tx, error) { |
56 | return s.DB.Begin() | 60 | return s.DB.Begin() |
57 | } | 61 | } |
58 | 62 | ||
59 | func CommitChanges(tx *sql.Tx, err *error, opt ...error) { | 63 | func CommitChanges(tx *sql.Tx, err *error, opt ...error) { |
60 | if *err != nil { | 64 | if *err != nil { |
61 | tx.Rollback() | 65 | tx.Rollback() |
62 | return | 66 | return |
63 | } | 67 | } |
64 | 68 | ||
65 | for _, e := range opt { | 69 | for _, e := range opt { |
66 | if e != nil { | 70 | if e != nil { |
67 | tx.Rollback() | 71 | tx.Rollback() |
68 | return | 72 | return |
69 | } | 73 | } |
70 | } | 74 | } |
71 | 75 | ||
72 | if *err = tx.Commit(); *err != nil { | 76 | if *err = tx.Commit(); *err != nil { |
73 | tx.Rollback() | 77 | tx.Rollback() |
74 | } | 78 | } |
75 | } | 79 | } |
76 | 80 |