-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
185 lines (160 loc) · 3.78 KB
/
main.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package main
import (
"bytes"
"context"
"encoding/json"
"encoding/xml"
"log"
"net/http"
"os/exec"
)
type TagXML struct {
Text string `xml:",chardata"`
ID string `xml:"id,attr"`
Name string `xml:"name,attr"`
Type string `xml:"type,attr"`
Writable string `xml:"writable,attr"`
G2 string `xml:"g2,attr"`
Desc []struct {
Text string `xml:",chardata"`
Lang string `xml:"lang,attr"`
} `xml:"desc"`
}
type TableXML struct {
Text string `xml:",chardata"`
Name string `xml:"name,attr"`
G0 string `xml:"g0,attr"`
G1 string `xml:"g1,attr"`
G2 string `xml:"g2,attr"`
Desc struct {
Text string `xml:",chardata"`
Lang string `xml:"lang,attr"`
} `xml:"desc"`
Tag []TagXML `xml:"tag"`
}
func main() {
log.Println("Please visit: http://localhost:3333/tags")
// handle the endpoint
http.HandleFunc("/tags", handleTags)
if err := http.ListenAndServe(":3333", nil); err != nil {
panic(err)
}
}
type Tag struct {
Writable string `json:"writable"`
Path string `json:"path"`
Group string `json:"group"`
Description []map[string]string `json:"description"`
Type string `json:"type"`
}
type Response struct {
Tags []Tag `json:"tags"`
}
var (
xmlData chan string
jsonData chan Response
quit chan int
)
func handleXMLStream(ctx context.Context) {
select {
case data := <-xmlData:
// response struct
var resp Response
// initiate buffer and Decoder for streaming
b := bytes.NewBufferString(data)
d := xml.NewDecoder(b)
for {
// XML token in the stream
t, err := d.Token()
if err != nil {
break
}
// get an instance
switch et := t.(type) {
case xml.StartElement:
// get the desired element when it starts
if et.Name.Local == "table" {
tableXml := &TableXML{}
// Decode it
if err := d.DecodeElement(&tableXml, &et); err != nil {
log.Fatal(err)
}
// Populate the data
for _, tagXml := range tableXml.Tag {
var tag Tag
tag.Path = tagXml.Name
tag.Writable = tagXml.Writable
tag.Path = tableXml.Name + ":" + tagXml.Name
tag.Group = tableXml.Name
tag.Type = tagXml.Type
for _, val := range tagXml.Desc {
d := map[string]string{
val.Lang: val.Text,
}
tag.Description = append(tag.Description, d)
}
resp.Tags = append(resp.Tags, tag)
}
} else if et.Name.Local == "taginfo" {
log.Println("XML Decode Stream begins")
}
case xml.EndElement:
if et.Name.Local != "taginfo" {
continue
}
if et.Name.Local != "table" {
continue
}
}
}
// push some bits
jsonData <- resp
case <-ctx.Done():
quit <- 1
}
}
func handleTags(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// initiate the chanels
xmlData = make(chan string)
jsonData = make(chan Response)
quit = make(chan int)
// handle the xml
go handleXMLStream(ctx)
cmd := exec.Command("exiftool", "-listx")
_, err := cmd.StdinPipe()
if err != nil {
w.Write([]byte("Something went wrong"))
return
}
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
xmlData <- out.String()
select {
case d := <-jsonData:
// Wait for decoded data
log.Println("JSON Encode stream begins")
flusher, ok := w.(http.Flusher)
if !ok {
panic("expected http.ResponseWriter to be an http.Flusher")
}
// Encode data and push some bits into screen
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
if err := enc.Encode(&d); err != nil {
log.Println(err)
}
flusher.Flush()
log.Println("Operation Completed")
case <-ctx.Done():
cmd.Process.Kill()
log.Println("Command Killed!")
case <-quit:
cmd.Process.Kill()
log.Println("Command Killed")
}
}