Skip to content

Commit c9f5b90

Browse files
author
nauman
committed
adding sse client
1 parent 94911ba commit c9f5b90

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

sseclient/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Server-sent events (SSE) client in Go
2+
3+
I needed a simple client for the events sent from my Spark Core via the
4+
[Spark API](http://docs.spark.io/api/), unfortunately it includes extra
5+
lines like `:ok` that is not part of any event.
6+
7+
[![GoDoc](https://godoc.org/github.com/peterhellberg/sseclient?status.svg)](https://godoc.org/github.com/peterhellberg/sseclient)
8+
9+
Based on the work by [@cryptix](https://github.com/cryptix/goSSEClient)
10+
11+
## LICENSE
12+
13+
```
14+
Copyright (C) 2014 Peter Hellberg
15+
16+
Permission is hereby granted, free of charge, to any person obtaining
17+
a copy of this software and associated documentation files (the "Software"),
18+
to deal in the Software without restriction, including without limitation
19+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
20+
and/or sell copies of the Software, and to permit persons to whom the
21+
Software is furnished to do so, subject to the following conditions:
22+
23+
The above copyright notice and this permission notice shall be included
24+
in all copies or substantial portions of the Software.
25+
26+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
29+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
30+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
32+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33+
```

sseclient/sseclient.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (C) 2014 Peter Hellberg
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining
4+
// a copy of this software and associated documentation files (the "Software"),
5+
// to deal in the Software without restriction, including without limitation
6+
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7+
// and/or sell copies of the Software, and to permit persons to whom the
8+
// Software is furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included
11+
// in all copies or substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
19+
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
package sseclient
21+
22+
import (
23+
"bufio"
24+
"bytes"
25+
"encoding/json"
26+
"fmt"
27+
"net/http"
28+
"os"
29+
)
30+
31+
// Event represents a Server-Sent Event
32+
type Event struct {
33+
Name string
34+
ID string
35+
Data map[string]interface{}
36+
}
37+
38+
// OpenURL opens a connection to a stream of server sent events
39+
func OpenURL(url string) (events chan Event, err error) {
40+
resp, err := http.Get(url)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
if resp.StatusCode != 200 {
46+
return nil, fmt.Errorf("got response status code %d\n", resp.StatusCode)
47+
}
48+
49+
events = make(chan Event)
50+
var buf bytes.Buffer
51+
52+
go func() {
53+
ev := Event{}
54+
55+
reader := bufio.NewReader(resp.Body)
56+
57+
for {
58+
line, err := reader.ReadBytes('\n')
59+
if err != nil {
60+
fmt.Fprintf(os.Stderr, "error during resp.Body read:%s\n", err)
61+
close(events)
62+
}
63+
64+
switch {
65+
// OK line
66+
case bytes.HasPrefix(line, []byte(":ok")):
67+
// Do nothing
68+
69+
// id of event
70+
case bytes.HasPrefix(line, []byte("id: ")):
71+
ev.ID = string(line[4:])
72+
case bytes.HasPrefix(line, []byte("id:")):
73+
ev.ID = string(line[3:])
74+
75+
// name of event
76+
case bytes.HasPrefix(line, []byte("event: ")):
77+
ev.Name = string(line[7 : len(line)-1])
78+
case bytes.HasPrefix(line, []byte("event:")):
79+
ev.Name = string(line[6 : len(line)-1])
80+
81+
// event data
82+
case bytes.HasPrefix(line, []byte("data: ")):
83+
buf.Write(line[6:])
84+
case bytes.HasPrefix(line, []byte("data:")):
85+
buf.Write(line[5:])
86+
87+
// end of event
88+
case bytes.Equal(line, []byte("\n")):
89+
b := buf.Bytes()
90+
91+
if bytes.HasPrefix(b, []byte("{")) {
92+
var data map[string]interface{}
93+
err := json.Unmarshal(b, &data)
94+
95+
if err == nil {
96+
ev.Data = data
97+
buf.Reset()
98+
events <- ev
99+
ev = Event{}
100+
}
101+
}
102+
103+
default:
104+
fmt.Fprintf(os.Stderr, "Error: len:%d\n%s", len(line), line)
105+
close(events)
106+
}
107+
}
108+
}()
109+
110+
return events, nil
111+
}

0 commit comments

Comments
 (0)