-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Zach Abrahamson
committed
Jul 18, 2016
1 parent
ce262c9
commit 837855f
Showing
4 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package box | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/dgrijalva/jwt-go" | ||
) | ||
|
||
type Config struct { | ||
Client ClientConfig `json:"client"` | ||
Events EventsConfig `json:"events"` | ||
} | ||
|
||
type ClientConfig struct { | ||
Token string `json:"token"` | ||
UrlBase string `json:"url_base"` | ||
ClientID string `json:"client_id"` | ||
ClientSecret string `json:"client_secret"` | ||
JWTCustomClaims JWTCustomClaims `json:"jwt_custom_claims"` | ||
} | ||
|
||
type EventsConfig struct { | ||
StartTime string `json:"start_time"` | ||
EventLimit string `json:"event_limit"` | ||
} | ||
|
||
type JWTCustomClaims struct { | ||
Iss string `json:"iss"` | ||
Sub string `json:"sub"` | ||
SubType string `json:"box_sub_type"` | ||
Aud string `json:"aud"` | ||
Jti string `json:"jti"` | ||
Exp int64 `json:"exp"` | ||
KeyID string `json:"key_id"` | ||
jwt.StandardClaims | ||
} | ||
|
||
type Client struct { | ||
HttpClient *http.Client | ||
BaseUrl *url.URL | ||
Token string | ||
} | ||
|
||
func NewClient(tok string, urlBase string) *Client { | ||
baseURL, _ := url.Parse(urlBase) | ||
return &Client{ | ||
HttpClient: &http.Client{}, | ||
BaseUrl: baseURL, | ||
Token: tok, | ||
} | ||
} | ||
|
||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { | ||
_, err := url.Parse(urlStr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
resolvedUrl, err := url.Parse(c.BaseUrl.String() + urlStr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buf := new(bytes.Buffer) | ||
if body != nil { | ||
if err = json.NewEncoder(buf).Encode(body); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
req, err := http.NewRequest(method, resolvedUrl.String(), buf) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return req, nil | ||
} | ||
|
||
func (c *Client) Do(req *http.Request, respStr interface{}) (*http.Response, error) { | ||
resp, err := c.HttpClient.Do(req) | ||
if err != nil { | ||
//fmt.Printf("box client.Do error: %s\n", err) | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode > 299 || resp.StatusCode < 200 { | ||
if resp.StatusCode == 429 { | ||
retrySecs, _ := strconv.Atoi(resp.Header.Get("Retry-after")) | ||
time.Sleep(time.Duration(retrySecs) * time.Second) | ||
return nil, fmt.Errorf("rate limited for %d seconds", retrySecs) | ||
} else { | ||
return nil, fmt.Errorf("http request failed, resp: %#v", resp) | ||
} | ||
} | ||
|
||
if respStr != nil { | ||
err = json.NewDecoder(resp.Body).Decode(respStr) | ||
} | ||
return resp, err | ||
} | ||
|
||
func (c *Client) DoWithRetries(req *http.Request, respStr interface{}, retries int) (*http.Response, error) { | ||
var resp http.Response | ||
for i := 0; i < retries; i++ { | ||
resp, err := c.Do(req, respStr) | ||
if err != nil { | ||
if i >= retries { | ||
return nil, fmt.Errorf("http request failed, resp: %#v", resp) | ||
} | ||
continue | ||
} | ||
} | ||
return &resp, nil | ||
} | ||
|
||
func (c *Client) EventService() *EventService { | ||
return &EventService{ | ||
Client: c, | ||
} | ||
} | ||
|
||
func (c *Client) FileService() *FileService { | ||
return &FileService{ | ||
Client: c, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package box | ||
|
||
type User struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
Login string `json:"login"` | ||
} | ||
|
||
type ItemParent struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
SequenceID string `json:"sequence_id"` | ||
Etag string `json:"etag"` | ||
Name string `json:"name"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package box | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
) | ||
|
||
type EventService struct { | ||
*Client | ||
} | ||
|
||
type EventDetails struct { | ||
ServiceID string `json:"service_id"` | ||
EkmID string `json:"ekm_id"` | ||
VersionID string `json:"version_id"` | ||
ServiceName string `json:"service_name"` | ||
} | ||
|
||
type EventSource struct { | ||
ItemID string `json:"item_id"` | ||
ItemType string `json:"item_type"` | ||
Parent *ItemParent `json:"parent"` | ||
ItemName string `json:"item_name"` | ||
} | ||
|
||
type Event struct { | ||
EventType string `json:"event_type"` | ||
EventID string `json:"event_id"` | ||
Type string `json:"type"` | ||
CreatedAt string `json:"created_at"` | ||
CreatedBy *User `json:"created_by"` | ||
Source *EventSource `json:"source"` | ||
SessionID interface{} `json:"session_id"` | ||
AdditionalDetails *EventDetails `json:"additional_details"` | ||
IPAddress string `json:"ip_address"` | ||
} | ||
|
||
type EventsCollection struct { | ||
ChunkSize int `json:"chunk_size"` | ||
NextStreamPosition string `json:"next_stream_position"` | ||
Entries []*Event `json:"entries"` | ||
} | ||
|
||
func (e *EventService) getSeedStreamPos(startTime string) string { | ||
var respBoxEventsJSON EventsCollection | ||
req, err := http.NewRequest("GET", e.BaseUrl.String()+"/events?stream_type=admin_logs&limit=1&created_after="+startTime, nil) | ||
req.Header.Add("Authorization", "Bearer "+e.Token) | ||
_, err = e.DoWithRetries(req, &respBoxEventsJSON, 5) | ||
if err != nil { | ||
fmt.Println("this unmarshal") | ||
fmt.Println(err) | ||
} | ||
return respBoxEventsJSON.NextStreamPosition | ||
} | ||
|
||
func (e *EventService) getEvents(eventLimit string, streamPos string) *EventsCollection { | ||
var respBoxEventsJSON EventsCollection | ||
req, err := http.NewRequest("GET", e.BaseUrl.String()+"/events?stream_type=admin_logs&limit="+eventLimit+"&stream_position="+streamPos, nil) | ||
req.Header.Add("Authorization", "Bearer "+e.Token) | ||
_, err = e.DoWithRetries(req, &respBoxEventsJSON, 5) | ||
if err != nil { | ||
|
||
fmt.Println(err) | ||
} | ||
return &respBoxEventsJSON | ||
} | ||
|
||
func (e *EventService) streamEvents(eventLimit string, streamPos string, tunnel chan *Event) { | ||
for { | ||
if streamPos == "" { | ||
close(tunnel) | ||
return | ||
} | ||
eventsCollection := e.getEvents(eventLimit, streamPos) | ||
for _, event := range eventsCollection.Entries { | ||
tunnel <- event | ||
} | ||
streamPos = eventsCollection.NextStreamPosition | ||
//time.Sleep(2 * time.Second) | ||
} | ||
} | ||
|
||
func (e *EventService) Channel(eventLimit string, startTime string) chan *Event { | ||
streamPos := e.getSeedStreamPos(startTime) | ||
eventStream := make(chan *Event) | ||
go e.streamEvents(eventLimit, streamPos, eventStream) | ||
return eventStream | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package box | ||
|
||
import "net/http" | ||
|
||
type FileService struct { | ||
*Client | ||
} | ||
|
||
type FileVersion struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
Sha1 string `json:"sha1"` | ||
} | ||
|
||
type FileEntry struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
SequenceID interface{} `json:"sequence_id"` | ||
Etag interface{} `json:"etag"` | ||
Name string `json:"name"` | ||
} | ||
|
||
type FilePathCollection struct { | ||
TotalCount int `json:"total_count"` | ||
Entries *[]FileEntry `json:"entries"` | ||
} | ||
|
||
type SharedLinkPermissions struct { | ||
CanDownload bool `json:"can_download"` | ||
CanPreview bool `json:"can_preview"` | ||
} | ||
|
||
type SharedLink struct { | ||
URL string `json:"url"` | ||
DownloadURL string `json:"download_url"` | ||
VanityURL interface{} `json:"vanity_url"` | ||
IsPasswordEnabled bool `json:"is_password_enabled"` | ||
UnsharedAt interface{} `json:"unshared_at"` | ||
DownloadCount int `json:"download_count"` | ||
PreviewCount int `json:"preview_count"` | ||
Access string `json:"access"` | ||
Permissions *SharedLinkPermissions `json:"permissions"` | ||
} | ||
|
||
type FileParent struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
SequenceID string `json:"sequence_id"` | ||
Etag string `json:"etag"` | ||
Name string `json:"name"` | ||
} | ||
|
||
type File struct { | ||
Type string `json:"type"` | ||
ID string `json:"id"` | ||
FileVersion *FileVersion `json:"file_version"` | ||
SequenceID string `json:"sequence_id"` | ||
Etag string `json:"etag"` | ||
Sha1 string `json:"sha1"` | ||
Name string `json:"name"` | ||
Description string `json:"description"` | ||
Size int `json:"size"` | ||
PathCollection *FilePathCollection `json:"path_collection"` | ||
CreatedAt string `json:"created_at"` | ||
ModifiedAt string `json:"modified_at"` | ||
CreatedBy *User `json:"created_by"` | ||
ModifiedBy *User `json:"modified_by"` | ||
OwnedBy *User `json:"owned_by"` | ||
SharedLink *SharedLink `json:"shared_link"` | ||
Parent *ItemParent `json:"parent"` | ||
ItemStatus string `json:"item_status"` | ||
} | ||
|
||
func (f *FileService) GetFileHash(fileID string) (string, error) { | ||
var respFileJSON File | ||
req, err := http.NewRequest("GET", f.BaseUrl.String()+"/files/"+fileID, nil) | ||
req.Header.Add("Authorization", "Bearer "+f.Token) | ||
_, err = f.Do(req, &respFileJSON) | ||
if err != nil { | ||
return "", err | ||
} | ||
return respFileJSON.Sha1, nil | ||
} |