mirror of
https://github.com/go-micro/go-micro.git
synced 2025-08-04 21:42:57 +02:00
Update services/ (#2392)
This commit is contained in:
@ -18,8 +18,10 @@ type AddressService struct {
|
||||
|
||||
// Lookup a list of UK addresses by postcode
|
||||
func (t *AddressService) LookupPostcode(request *LookupPostcodeRequest) (*LookupPostcodeResponse, error) {
|
||||
|
||||
rsp := &LookupPostcodeResponse{}
|
||||
return rsp, t.client.Call("address", "LookupPostcode", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type LookupPostcodeRequest struct {
|
||||
@ -33,13 +35,13 @@ type LookupPostcodeResponse struct {
|
||||
|
||||
type Record struct {
|
||||
// building name
|
||||
BuildingName string `json:"buildingName"`
|
||||
BuildingName string `json:"building_name"`
|
||||
// the county
|
||||
County string `json:"county"`
|
||||
// line one of address
|
||||
LineOne string `json:"lineOne"`
|
||||
LineOne string `json:"line_one"`
|
||||
// line two of address
|
||||
LineTwo string `json:"lineTwo"`
|
||||
LineTwo string `json:"line_two"`
|
||||
// dependent locality
|
||||
Locality string `json:"locality"`
|
||||
// organisation if present
|
||||
|
@ -18,8 +18,10 @@ type AnswerService struct {
|
||||
|
||||
// Ask a question and receive an instant answer
|
||||
func (t *AnswerService) Question(request *QuestionRequest) (*QuestionResponse, error) {
|
||||
|
||||
rsp := &QuestionResponse{}
|
||||
return rsp, t.client.Call("answer", "Question", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type QuestionRequest struct {
|
||||
|
202
services/app/app.go
Executable file
202
services/app/app.go
Executable file
@ -0,0 +1,202 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewAppService(token string) *AppService {
|
||||
return &AppService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type AppService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Delete an app
|
||||
func (t *AppService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("app", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List all the apps
|
||||
func (t *AppService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("app", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Return the support regions
|
||||
func (t *AppService) Regions(request *RegionsRequest) (*RegionsResponse, error) {
|
||||
|
||||
rsp := &RegionsResponse{}
|
||||
return rsp, t.client.Call("app", "Regions", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Reserve apps beyond the free quota. Call Run after.
|
||||
func (t *AppService) Reserve(request *ReserveRequest) (*ReserveResponse, error) {
|
||||
|
||||
rsp := &ReserveResponse{}
|
||||
return rsp, t.client.Call("app", "Reserve", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Resolve an app by id to its raw backend endpoint
|
||||
func (t *AppService) Resolve(request *ResolveRequest) (*ResolveResponse, error) {
|
||||
|
||||
rsp := &ResolveResponse{}
|
||||
return rsp, t.client.Call("app", "Resolve", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Run an app from a source repo. Specify region etc.
|
||||
func (t *AppService) Run(request *RunRequest) (*RunResponse, error) {
|
||||
|
||||
rsp := &RunResponse{}
|
||||
return rsp, t.client.Call("app", "Run", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the status of an app
|
||||
func (t *AppService) Status(request *StatusRequest) (*StatusResponse, error) {
|
||||
|
||||
rsp := &StatusResponse{}
|
||||
return rsp, t.client.Call("app", "Status", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update the app. The latest source code will be downloaded, built and deployed.
|
||||
func (t *AppService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("app", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
// all the apps
|
||||
Services []Service `json:"services"`
|
||||
}
|
||||
|
||||
type RegionsRequest struct {
|
||||
}
|
||||
|
||||
type RegionsResponse struct {
|
||||
Regions []string `json:"regions"`
|
||||
}
|
||||
|
||||
type Reservation struct {
|
||||
// time of reservation
|
||||
Created string `json:"created"`
|
||||
// time reservation expires
|
||||
Expires string `json:"expires"`
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
// owner id
|
||||
Owner string `json:"owner"`
|
||||
// associated token
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type ReserveRequest struct {
|
||||
// name of your app e.g helloworld
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ReserveResponse struct {
|
||||
// The app reservation
|
||||
Reservation *Reservation `json:"reservation"`
|
||||
}
|
||||
|
||||
type ResolveRequest struct {
|
||||
// the service id
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type ResolveResponse struct {
|
||||
// the end provider url
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type RunRequest struct {
|
||||
// branch. defaults to master
|
||||
Branch string `json:"branch"`
|
||||
// associatede env vars to pass in
|
||||
EnvVars map[string]string `json:"env_vars"`
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
// port to run on
|
||||
Port int32 `json:"port"`
|
||||
// region to run in
|
||||
Region string `json:"region"`
|
||||
// source repository
|
||||
Repo string `json:"repo"`
|
||||
}
|
||||
|
||||
type RunResponse struct {
|
||||
// The running service
|
||||
Service *Service `json:"service"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
// branch of code
|
||||
Branch string `json:"branch"`
|
||||
// time of creation
|
||||
Created string `json:"created"`
|
||||
// custom domains
|
||||
CustomDomains string `json:"custom_domains"`
|
||||
// associated env vars
|
||||
EnvVars map[string]string `json:"env_vars"`
|
||||
// unique id
|
||||
Id string `json:"id"`
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
// port running on
|
||||
Port int32 `json:"port"`
|
||||
// region running in
|
||||
Region string `json:"region"`
|
||||
// source repository
|
||||
Repo string `json:"repo"`
|
||||
// status of the app
|
||||
Status string `json:"status"`
|
||||
// last updated
|
||||
Updated string `json:"updated"`
|
||||
// app url
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type StatusRequest struct {
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type StatusResponse struct {
|
||||
// running service info
|
||||
Service *Service `json:"service"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type UpdateResponse struct {
|
||||
}
|
46
services/avatar/avatar.go
Executable file
46
services/avatar/avatar.go
Executable file
@ -0,0 +1,46 @@
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewAvatarService(token string) *AvatarService {
|
||||
return &AvatarService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type AvatarService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
//
|
||||
func (t *AvatarService) Generate(request *GenerateRequest) (*GenerateResponse, error) {
|
||||
|
||||
rsp := &GenerateResponse{}
|
||||
return rsp, t.client.Call("avatar", "Generate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type GenerateRequest struct {
|
||||
// encode format of avatar image, `png` or `jpeg`, default is `jpeg`
|
||||
Format string `json:"format"`
|
||||
// avatar's gender, `male` or `female`, default is `male`
|
||||
Gender string `json:"gender"`
|
||||
// if upload to m3o CDN, default is `false`
|
||||
// if update = true, then it'll return the CDN url
|
||||
Upload bool `json:"upload"`
|
||||
// avatar's username, unique username will generates the unique avatar;
|
||||
// if username == "", will generate a random avatar in every request
|
||||
// if upload == true, username will be used as CDN filename rather than a random uuid string
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type GenerateResponse struct {
|
||||
// base64encode string of the avatar image
|
||||
Base64 string `json:"base64"`
|
||||
// Micro's CDN url of the avatar image
|
||||
Url string `json:"url"`
|
||||
}
|
18
services/cache/cache.go
vendored
18
services/cache/cache.go
vendored
@ -16,34 +16,44 @@ type CacheService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Decrement a value (if it's a number)
|
||||
// Decrement a value (if it's a number). If key not found it is equivalent to set.
|
||||
func (t *CacheService) Decrement(request *DecrementRequest) (*DecrementResponse, error) {
|
||||
|
||||
rsp := &DecrementResponse{}
|
||||
return rsp, t.client.Call("cache", "Decrement", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete a value from the cache
|
||||
// Delete a value from the cache. If key not found a success response is returned.
|
||||
func (t *CacheService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("cache", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get an item from the cache by key
|
||||
// Get an item from the cache by key. If key is not found, an empty response is returned.
|
||||
func (t *CacheService) Get(request *GetRequest) (*GetResponse, error) {
|
||||
|
||||
rsp := &GetResponse{}
|
||||
return rsp, t.client.Call("cache", "Get", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Increment a value (if it's a number)
|
||||
// Increment a value (if it's a number). If key not found it is equivalent to set.
|
||||
func (t *CacheService) Increment(request *IncrementRequest) (*IncrementResponse, error) {
|
||||
|
||||
rsp := &IncrementResponse{}
|
||||
return rsp, t.client.Call("cache", "Increment", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Set an item in the cache. Overwrites any existing value already set.
|
||||
func (t *CacheService) Set(request *SetRequest) (*SetResponse, error) {
|
||||
|
||||
rsp := &SetResponse{}
|
||||
return rsp, t.client.Call("cache", "Set", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type DecrementRequest struct {
|
||||
|
220
services/client/client.go
Normal file
220
services/client/client.go
Normal file
@ -0,0 +1,220 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
// local address for api
|
||||
localAddress = "http://localhost:8080"
|
||||
// public address for api
|
||||
liveAddress = "https://api.m3o.com"
|
||||
)
|
||||
|
||||
// Options of the Client
|
||||
type Options struct {
|
||||
// Token for authentication
|
||||
Token string
|
||||
// Address of the micro platform.
|
||||
// By default it connects to live. Change it or use the local flag
|
||||
// to connect to your local installation.
|
||||
Address string
|
||||
// Helper flag to help users connect to the default local address
|
||||
Local bool
|
||||
// set a timeout
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Request is the request of the generic `api-client` call
|
||||
type Request struct {
|
||||
// eg. "go.micro.srv.greeter"
|
||||
Service string `json:"service"`
|
||||
// eg. "Say.Hello"
|
||||
Endpoint string `json:"endpoint"`
|
||||
// json and then base64 encoded body
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// Response is the response of the generic `api-client` call.
|
||||
type Response struct {
|
||||
// json and base64 encoded response body
|
||||
Body string `json:"body"`
|
||||
// error fields. Error json example
|
||||
// {"id":"go.micro.client","code":500,"detail":"malformed method name: \"\"","status":"Internal Server Error"}
|
||||
Code int `json:"code"`
|
||||
ID string `json:"id"`
|
||||
Detail string `json:"detail"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// Client enables generic calls to micro
|
||||
type Client struct {
|
||||
options Options
|
||||
}
|
||||
|
||||
type Stream struct {
|
||||
conn *websocket.Conn
|
||||
service, endpoint string
|
||||
}
|
||||
|
||||
// NewClient returns a generic micro client that connects to live by default
|
||||
func NewClient(options *Options) *Client {
|
||||
ret := new(Client)
|
||||
ret.options = Options{
|
||||
Address: liveAddress,
|
||||
}
|
||||
|
||||
// no options provided
|
||||
if options == nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
if options.Token != "" {
|
||||
ret.options.Token = options.Token
|
||||
}
|
||||
|
||||
if options.Local {
|
||||
ret.options.Address = localAddress
|
||||
ret.options.Local = true
|
||||
}
|
||||
|
||||
if options.Timeout > 0 {
|
||||
ret.options.Timeout = options.Timeout
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// SetToken sets the api auth token
|
||||
func (client *Client) SetToken(t string) {
|
||||
client.options.Token = t
|
||||
}
|
||||
|
||||
// SetTimeout sets the http client's timeout
|
||||
func (client *Client) SetTimeout(d time.Duration) {
|
||||
client.options.Timeout = d
|
||||
}
|
||||
|
||||
// Call enables you to access any endpoint of any service on Micro
|
||||
func (client *Client) Call(service, endpoint string, request, response interface{}) error {
|
||||
// example curl: curl -XPOST -d '{"service": "go.micro.srv.greeter", "endpoint": "Say.Hello"}'
|
||||
// -H 'Content-Type: application/json' http://localhost:8080/client {"body":"eyJtc2ciOiJIZWxsbyAifQ=="}
|
||||
uri, err := url.Parse(client.options.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the url to go through the v1 api
|
||||
uri.Path = "/v1/" + service + "/" + endpoint
|
||||
|
||||
b, err := marshalRequest(service, endpoint, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", uri.String(), bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the token if it exists
|
||||
if len(client.options.Token) > 0 {
|
||||
req.Header.Set("Authorization", "Bearer "+client.options.Token)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// if user didn't specify Timeout the default is 0 i.e no timeout
|
||||
httpClient := &http.Client{
|
||||
Timeout: client.options.Timeout,
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
|
||||
return errors.New(string(body))
|
||||
}
|
||||
return unmarshalResponse(body, response)
|
||||
}
|
||||
|
||||
// Stream enables the ability to stream via websockets
|
||||
func (client *Client) Stream(service, endpoint string, request interface{}) (*Stream, error) {
|
||||
b, err := marshalRequest(service, endpoint, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uri, err := url.Parse(client.options.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set the url to go through the v1 api
|
||||
uri.Path = "/v1/" + service + "/" + endpoint
|
||||
|
||||
// replace http with websocket
|
||||
uri.Scheme = strings.Replace(uri.Scheme, "http", "ws", 1)
|
||||
|
||||
// create the headers
|
||||
header := make(http.Header)
|
||||
// set the token if it exists
|
||||
if len(client.options.Token) > 0 {
|
||||
header.Set("Authorization", "Bearer "+client.options.Token)
|
||||
}
|
||||
header.Set("Content-Type", "application/json")
|
||||
|
||||
// dial the connection
|
||||
conn, _, err := websocket.DefaultDialer.Dial(uri.String(), header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// send the first request
|
||||
if err := conn.WriteMessage(websocket.TextMessage, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Stream{conn, service, endpoint}, nil
|
||||
}
|
||||
|
||||
func (s *Stream) Recv(v interface{}) error {
|
||||
// read response
|
||||
_, message, err := s.conn.ReadMessage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return unmarshalResponse(message, v)
|
||||
}
|
||||
|
||||
func (s *Stream) Send(v interface{}) error {
|
||||
b, err := marshalRequest(s.service, s.endpoint, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.conn.WriteMessage(websocket.TextMessage, b)
|
||||
}
|
||||
|
||||
func marshalRequest(service, endpoint string, v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func unmarshalResponse(body []byte, v interface{}) error {
|
||||
return json.Unmarshal(body, &v)
|
||||
}
|
24
services/client/client_test.go
Normal file
24
services/client/client_test.go
Normal file
@ -0,0 +1,24 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBasicCall(t *testing.T) {
|
||||
if v := os.Getenv("IN_TRAVIS"); v == "yes" {
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{}
|
||||
if err := NewClient(&Options{
|
||||
Token: os.Getenv("TOKEN"),
|
||||
}).Call("groups", "list", map[string]interface{}{
|
||||
"memberId": "random",
|
||||
}, &response); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(response) > 0 {
|
||||
t.Fatal(len(response))
|
||||
}
|
||||
}
|
201
services/cmd/m3o-go-url/LICENSE
Normal file
201
services/cmd/m3o-go-url/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
10
services/cmd/m3o-go-url/go.mod
Normal file
10
services/cmd/m3o-go-url/go.mod
Normal file
@ -0,0 +1,10 @@
|
||||
module github.com/m3o/m3o-go/cmd/m3o-go-url
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.3.3 // indirect
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
|
||||
google.golang.org/appengine v1.6.5
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
13
services/cmd/m3o-go-url/go.sum
Normal file
13
services/cmd/m3o-go-url/go.sum
Normal file
@ -0,0 +1,13 @@
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
225
services/cmd/m3o-go-url/handler.go
Normal file
225
services/cmd/m3o-go-url/handler.go
Normal file
@ -0,0 +1,225 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// govanityurls serves Go vanity URLs.
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
host string
|
||||
cacheControl string
|
||||
paths pathConfigSet
|
||||
}
|
||||
|
||||
type pathConfig struct {
|
||||
path string
|
||||
repo string
|
||||
display string
|
||||
vcs string
|
||||
}
|
||||
|
||||
func newHandler(config []byte) (*handler, error) {
|
||||
var parsed struct {
|
||||
Host string `yaml:"host,omitempty"`
|
||||
CacheAge *int64 `yaml:"cache_max_age,omitempty"`
|
||||
Paths map[string]struct {
|
||||
Repo string `yaml:"repo,omitempty"`
|
||||
Display string `yaml:"display,omitempty"`
|
||||
VCS string `yaml:"vcs,omitempty"`
|
||||
} `yaml:"paths,omitempty"`
|
||||
}
|
||||
if err := yaml.Unmarshal(config, &parsed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := &handler{host: parsed.Host}
|
||||
cacheAge := int64(86400) // 24 hours (in seconds)
|
||||
if parsed.CacheAge != nil {
|
||||
cacheAge = *parsed.CacheAge
|
||||
if cacheAge < 0 {
|
||||
return nil, errors.New("cache_max_age is negative")
|
||||
}
|
||||
}
|
||||
h.cacheControl = fmt.Sprintf("public, max-age=%d", cacheAge)
|
||||
for path, e := range parsed.Paths {
|
||||
pc := pathConfig{
|
||||
path: strings.TrimSuffix(path, "/"),
|
||||
repo: e.Repo,
|
||||
display: e.Display,
|
||||
vcs: e.VCS,
|
||||
}
|
||||
switch {
|
||||
case e.Display != "":
|
||||
// Already filled in.
|
||||
case strings.HasPrefix(e.Repo, "https://github.com/"):
|
||||
pc.display = fmt.Sprintf("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}", e.Repo, e.Repo, e.Repo)
|
||||
case strings.HasPrefix(e.Repo, "https://bitbucket.org"):
|
||||
pc.display = fmt.Sprintf("%v %v/src/default{/dir} %v/src/default{/dir}/{file}#{file}-{line}", e.Repo, e.Repo, e.Repo)
|
||||
}
|
||||
switch {
|
||||
case e.VCS != "":
|
||||
// Already filled in.
|
||||
if e.VCS != "bzr" && e.VCS != "git" && e.VCS != "hg" && e.VCS != "svn" {
|
||||
return nil, fmt.Errorf("configuration for %v: unknown VCS %s", path, e.VCS)
|
||||
}
|
||||
case strings.HasPrefix(e.Repo, "https://github.com/"):
|
||||
pc.vcs = "git"
|
||||
default:
|
||||
return nil, fmt.Errorf("configuration for %v: cannot infer VCS from %s", path, e.Repo)
|
||||
}
|
||||
h.paths = append(h.paths, pc)
|
||||
}
|
||||
sort.Sort(h.paths)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
current := r.URL.Path
|
||||
pc, subpath := h.paths.find(current)
|
||||
if pc == nil && current == "/" {
|
||||
h.serveIndex(w, r)
|
||||
return
|
||||
}
|
||||
if pc == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Cache-Control", h.cacheControl)
|
||||
if err := vanityTmpl.Execute(w, struct {
|
||||
Import string
|
||||
Subpath string
|
||||
Repo string
|
||||
Display string
|
||||
VCS string
|
||||
}{
|
||||
Import: h.Host(r) + pc.path,
|
||||
Subpath: subpath,
|
||||
Repo: pc.repo,
|
||||
Display: pc.display,
|
||||
VCS: pc.vcs,
|
||||
}); err != nil {
|
||||
http.Error(w, "cannot render the page", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
host := h.Host(r)
|
||||
handlers := make([]string, len(h.paths))
|
||||
for i, h := range h.paths {
|
||||
handlers[i] = host + h.path
|
||||
}
|
||||
if err := indexTmpl.Execute(w, struct {
|
||||
Host string
|
||||
Handlers []string
|
||||
}{
|
||||
Host: host,
|
||||
Handlers: handlers,
|
||||
}); err != nil {
|
||||
http.Error(w, "cannot render the page", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) Host(r *http.Request) string {
|
||||
host := h.host
|
||||
if host == "" {
|
||||
host = defaultHost(r)
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
var indexTmpl = template.Must(template.New("index").Parse(`<!DOCTYPE html>
|
||||
<html>
|
||||
<h1>{{.Host}}</h1>
|
||||
<ul>
|
||||
{{range .Handlers}}<li><a href="https://pkg.go.dev/{{.}}">{{.}}</a></li>{{end}}
|
||||
</ul>
|
||||
</html>
|
||||
`))
|
||||
|
||||
var vanityTmpl = template.Must(template.New("vanity").Parse(`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="go-import" content="{{.Import}} {{.VCS}} {{.Repo}}">
|
||||
<meta name="go-source" content="{{.Import}} {{.Display}}">
|
||||
<meta http-equiv="refresh" content="0; url=https://pkg.go.dev/{{.Import}}/{{.Subpath}}">
|
||||
</head>
|
||||
<body>
|
||||
Nothing to see here; <a href="https://pkg.go.dev/{{.Import}}/{{.Subpath}}">see the package on pkg.go.dev</a>.
|
||||
</body>
|
||||
</html>`))
|
||||
|
||||
type pathConfigSet []pathConfig
|
||||
|
||||
func (pset pathConfigSet) Len() int {
|
||||
return len(pset)
|
||||
}
|
||||
|
||||
func (pset pathConfigSet) Less(i, j int) bool {
|
||||
return pset[i].path < pset[j].path
|
||||
}
|
||||
|
||||
func (pset pathConfigSet) Swap(i, j int) {
|
||||
pset[i], pset[j] = pset[j], pset[i]
|
||||
}
|
||||
|
||||
func (pset pathConfigSet) find(path string) (pc *pathConfig, subpath string) {
|
||||
// Fast path with binary search to retrieve exact matches
|
||||
// e.g. given pset ["/", "/abc", "/xyz"], path "/def" won't match.
|
||||
i := sort.Search(len(pset), func(i int) bool {
|
||||
return pset[i].path >= path
|
||||
})
|
||||
if i < len(pset) && pset[i].path == path {
|
||||
return &pset[i], ""
|
||||
}
|
||||
if i > 0 && strings.HasPrefix(path, pset[i-1].path+"/") {
|
||||
return &pset[i-1], path[len(pset[i-1].path)+1:]
|
||||
}
|
||||
|
||||
// Slow path, now looking for the longest prefix/shortest subpath i.e.
|
||||
// e.g. given pset ["/", "/abc/", "/abc/def/", "/xyz"/]
|
||||
// * query "/abc/foo" returns "/abc/" with a subpath of "foo"
|
||||
// * query "/x" returns "/" with a subpath of "x"
|
||||
lenShortestSubpath := len(path)
|
||||
var bestMatchConfig *pathConfig
|
||||
|
||||
// After binary search with the >= lexicographic comparison,
|
||||
// nothing greater than i will be a prefix of path.
|
||||
max := i
|
||||
for i := 0; i < max; i++ {
|
||||
ps := pset[i]
|
||||
if len(ps.path) >= len(path) {
|
||||
// We previously didn't find the path by search, so any
|
||||
// route with equal or greater length is NOT a match.
|
||||
continue
|
||||
}
|
||||
sSubpath := strings.TrimPrefix(path, ps.path)
|
||||
if len(sSubpath) < lenShortestSubpath {
|
||||
subpath = sSubpath
|
||||
lenShortestSubpath = len(sSubpath)
|
||||
bestMatchConfig = &pset[i]
|
||||
}
|
||||
}
|
||||
return bestMatchConfig, subpath
|
||||
}
|
315
services/cmd/m3o-go-url/handler_test.go
Normal file
315
services/cmd/m3o-go-url/handler_test.go
Normal file
@ -0,0 +1,315 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
path string
|
||||
|
||||
goImport string
|
||||
goSource string
|
||||
}{
|
||||
{
|
||||
name: "explicit display",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /portmidi:\n" +
|
||||
" repo: https://github.com/rakyll/portmidi\n" +
|
||||
" display: https://github.com/rakyll/portmidi _ _\n",
|
||||
path: "/portmidi",
|
||||
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
|
||||
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
|
||||
},
|
||||
{
|
||||
name: "display GitHub inference",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /portmidi:\n" +
|
||||
" repo: https://github.com/rakyll/portmidi\n",
|
||||
path: "/portmidi",
|
||||
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
|
||||
goSource: "example.com/portmidi https://github.com/rakyll/portmidi https://github.com/rakyll/portmidi/tree/master{/dir} https://github.com/rakyll/portmidi/blob/master{/dir}/{file}#L{line}",
|
||||
},
|
||||
{
|
||||
name: "Bitbucket Mercurial",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /gopdf:\n" +
|
||||
" repo: https://bitbucket.org/zombiezen/gopdf\n" +
|
||||
" vcs: hg\n",
|
||||
path: "/gopdf",
|
||||
goImport: "example.com/gopdf hg https://bitbucket.org/zombiezen/gopdf",
|
||||
goSource: "example.com/gopdf https://bitbucket.org/zombiezen/gopdf https://bitbucket.org/zombiezen/gopdf/src/default{/dir} https://bitbucket.org/zombiezen/gopdf/src/default{/dir}/{file}#{file}-{line}",
|
||||
},
|
||||
{
|
||||
name: "Bitbucket Git",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /mygit:\n" +
|
||||
" repo: https://bitbucket.org/zombiezen/mygit\n" +
|
||||
" vcs: git\n",
|
||||
path: "/mygit",
|
||||
goImport: "example.com/mygit git https://bitbucket.org/zombiezen/mygit",
|
||||
goSource: "example.com/mygit https://bitbucket.org/zombiezen/mygit https://bitbucket.org/zombiezen/mygit/src/default{/dir} https://bitbucket.org/zombiezen/mygit/src/default{/dir}/{file}#{file}-{line}",
|
||||
},
|
||||
{
|
||||
name: "subpath",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /portmidi:\n" +
|
||||
" repo: https://github.com/rakyll/portmidi\n" +
|
||||
" display: https://github.com/rakyll/portmidi _ _\n",
|
||||
path: "/portmidi/foo",
|
||||
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
|
||||
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
|
||||
},
|
||||
{
|
||||
name: "subpath with trailing config slash",
|
||||
config: "host: example.com\n" +
|
||||
"paths:\n" +
|
||||
" /portmidi/:\n" +
|
||||
" repo: https://github.com/rakyll/portmidi\n" +
|
||||
" display: https://github.com/rakyll/portmidi _ _\n",
|
||||
path: "/portmidi/foo",
|
||||
goImport: "example.com/portmidi git https://github.com/rakyll/portmidi",
|
||||
goSource: "example.com/portmidi https://github.com/rakyll/portmidi _ _",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
h, err := newHandler([]byte(test.config))
|
||||
if err != nil {
|
||||
t.Errorf("%s: newHandler: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
s := httptest.NewServer(h)
|
||||
resp, err := http.Get(s.URL + test.path)
|
||||
if err != nil {
|
||||
s.Close()
|
||||
t.Errorf("%s: http.Get: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
s.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("%s: status code = %s; want 200 OK", test.name, resp.Status)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("%s: ioutil.ReadAll: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if got := findMeta(data, "go-import"); got != test.goImport {
|
||||
t.Errorf("%s: meta go-import = %q; want %q", test.name, got, test.goImport)
|
||||
}
|
||||
if got := findMeta(data, "go-source"); got != test.goSource {
|
||||
t.Errorf("%s: meta go-source = %q; want %q", test.name, got, test.goSource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadConfigs(t *testing.T) {
|
||||
badConfigs := []string{
|
||||
"paths:\n" +
|
||||
" /missingvcs:\n" +
|
||||
" repo: https://bitbucket.org/zombiezen/gopdf\n",
|
||||
"paths:\n" +
|
||||
" /unknownvcs:\n" +
|
||||
" repo: https://bitbucket.org/zombiezen/gopdf\n" +
|
||||
" vcs: xyzzy\n",
|
||||
"cache_max_age: -1\n" +
|
||||
"paths:\n" +
|
||||
" /portmidi:\n" +
|
||||
" repo: https://github.com/rakyll/portmidi\n",
|
||||
}
|
||||
for _, config := range badConfigs {
|
||||
_, err := newHandler([]byte(config))
|
||||
if err == nil {
|
||||
t.Errorf("expected config to produce an error, but did not:\n%s", config)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findMeta(data []byte, name string) string {
|
||||
var sep []byte
|
||||
sep = append(sep, `<meta name="`...)
|
||||
sep = append(sep, name...)
|
||||
sep = append(sep, `" content="`...)
|
||||
i := bytes.Index(data, sep)
|
||||
if i == -1 {
|
||||
return ""
|
||||
}
|
||||
content := data[i+len(sep):]
|
||||
j := bytes.IndexByte(content, '"')
|
||||
if j == -1 {
|
||||
return ""
|
||||
}
|
||||
return string(content[:j])
|
||||
}
|
||||
|
||||
func TestPathConfigSetFind(t *testing.T) {
|
||||
tests := []struct {
|
||||
paths []string
|
||||
query string
|
||||
want string
|
||||
subpath string
|
||||
}{
|
||||
{
|
||||
paths: []string{"/portmidi"},
|
||||
query: "/portmidi",
|
||||
want: "/portmidi",
|
||||
},
|
||||
{
|
||||
paths: []string{"/portmidi"},
|
||||
query: "/portmidi/",
|
||||
want: "/portmidi",
|
||||
},
|
||||
{
|
||||
paths: []string{"/portmidi"},
|
||||
query: "/foo",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
paths: []string{"/portmidi"},
|
||||
query: "/zzz",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
paths: []string{"/abc", "/portmidi", "/xyz"},
|
||||
query: "/portmidi",
|
||||
want: "/portmidi",
|
||||
},
|
||||
{
|
||||
paths: []string{"/abc", "/portmidi", "/xyz"},
|
||||
query: "/portmidi/foo",
|
||||
want: "/portmidi",
|
||||
subpath: "foo",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/x",
|
||||
want: "/",
|
||||
subpath: "x",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/",
|
||||
want: "/",
|
||||
subpath: "",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/example",
|
||||
want: "/",
|
||||
subpath: "example",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/example/foo",
|
||||
want: "/",
|
||||
subpath: "example/foo",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/y",
|
||||
want: "/y",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/", "/y", "/foo"},
|
||||
query: "/x/y/",
|
||||
want: "/",
|
||||
subpath: "x/y/",
|
||||
},
|
||||
{
|
||||
paths: []string{"/example/helloworld", "/y", "/foo"},
|
||||
query: "/x",
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
emptyToNil := func(s string) string {
|
||||
if s == "" {
|
||||
return "<nil>"
|
||||
}
|
||||
return s
|
||||
}
|
||||
for _, test := range tests {
|
||||
pset := make(pathConfigSet, len(test.paths))
|
||||
for i := range test.paths {
|
||||
pset[i].path = test.paths[i]
|
||||
}
|
||||
sort.Sort(pset)
|
||||
pc, subpath := pset.find(test.query)
|
||||
var got string
|
||||
if pc != nil {
|
||||
got = pc.path
|
||||
}
|
||||
if got != test.want || subpath != test.subpath {
|
||||
t.Errorf("pathConfigSet(%v).find(%q) = %v, %v; want %v, %v",
|
||||
test.paths, test.query, emptyToNil(got), subpath, emptyToNil(test.want), test.subpath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheHeader(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
cacheControl string
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
cacheControl: "public, max-age=86400",
|
||||
},
|
||||
{
|
||||
name: "specify time",
|
||||
config: "cache_max_age: 60\n",
|
||||
cacheControl: "public, max-age=60",
|
||||
},
|
||||
{
|
||||
name: "zero",
|
||||
config: "cache_max_age: 0\n",
|
||||
cacheControl: "public, max-age=0",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
h, err := newHandler([]byte("paths:\n /portmidi:\n repo: https://github.com/rakyll/portmidi\n" +
|
||||
test.config))
|
||||
if err != nil {
|
||||
t.Errorf("%s: newHandler: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
s := httptest.NewServer(h)
|
||||
resp, err := http.Get(s.URL + "/portmidi")
|
||||
if err != nil {
|
||||
t.Errorf("%s: http.Get: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
resp.Body.Close()
|
||||
got := resp.Header.Get("Cache-Control")
|
||||
if got != test.cacheControl {
|
||||
t.Errorf("%s: Cache-Control header = %q; want %q", test.name, got, test.cacheControl)
|
||||
}
|
||||
}
|
||||
}
|
55
services/cmd/m3o-go-url/main.go
Normal file
55
services/cmd/m3o-go-url/main.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var configPath string
|
||||
switch len(os.Args) {
|
||||
case 1:
|
||||
configPath = "vanity.yaml"
|
||||
case 2:
|
||||
configPath = os.Args[1]
|
||||
default:
|
||||
log.Fatal("usage: m3o-go-url [CONFIG]")
|
||||
}
|
||||
vanity, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
h, err := newHandler(vanity)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
http.Handle("/", h)
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "8080"
|
||||
}
|
||||
if err := http.ListenAndServe(":"+port, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func defaultHost(r *http.Request) string {
|
||||
return r.Host
|
||||
}
|
5
services/cmd/m3o-go-url/vanity.yaml
Normal file
5
services/cmd/m3o-go-url/vanity.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
host: go.m3o.com
|
||||
|
||||
paths:
|
||||
/:
|
||||
repo: https://github.com/m3o/m3o-go
|
192
services/contact/contact.go
Executable file
192
services/contact/contact.go
Executable file
@ -0,0 +1,192 @@
|
||||
package contact
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewContactService(token string) *ContactService {
|
||||
return &ContactService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type ContactService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
//
|
||||
func (t *ContactService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("contact", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
func (t *ContactService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("contact", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
func (t *ContactService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("contact", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
func (t *ContactService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("contact", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
func (t *ContactService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("contact", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
// the label of the address
|
||||
Label string `json:"label"`
|
||||
// the address location
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
type ContactInfo struct {
|
||||
// the address
|
||||
Addresses []Address `json:"addresses"`
|
||||
// the birthday
|
||||
Birthday string `json:"birthday"`
|
||||
// create date string in RFC3339
|
||||
CreatedAt string `json:"created_at"`
|
||||
// the emails
|
||||
Emails []Email `json:"emails"`
|
||||
// contact id
|
||||
Id string `json:"id"`
|
||||
// the contact links
|
||||
Links []Link `json:"links"`
|
||||
// the contact name
|
||||
Name string `json:"name"`
|
||||
// note of the contact
|
||||
Note string `json:"note"`
|
||||
// the phone numbers
|
||||
Phones []Phone `json:"phones"`
|
||||
// the social media username
|
||||
SocialMedias *SocialMedia `json:"social_medias"`
|
||||
// update date string in RFC3339
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
// optional, location
|
||||
Addresses []Address `json:"addresses"`
|
||||
// optional, birthday
|
||||
Birthday string `json:"birthday"`
|
||||
// optional, emails
|
||||
Emails []Email `json:"emails"`
|
||||
// optional, links
|
||||
Links []Link `json:"links"`
|
||||
// required, the name of the contact
|
||||
Name string `json:"name"`
|
||||
// optional, note of the contact
|
||||
Note string `json:"note"`
|
||||
// optional, phone numbers
|
||||
Phones []Phone `json:"phones"`
|
||||
// optional, social media
|
||||
SocialMedias *SocialMedia `json:"social_medias"`
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
Contact *ContactInfo `json:"contact"`
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
// the id of the contact
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type Email struct {
|
||||
// the email address
|
||||
Address string `json:"address"`
|
||||
// the label of the email
|
||||
Label string `json:"label"`
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
// the label of the link
|
||||
Label string `json:"label"`
|
||||
// the url of the contact
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
// optional, default is 30
|
||||
Limit int32 `json:"limit"`
|
||||
// optional
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
Contacts []ContactInfo `json:"contacts"`
|
||||
}
|
||||
|
||||
type Phone struct {
|
||||
// the label of the phone number
|
||||
Label string `json:"label"`
|
||||
// phone number
|
||||
Number string `json:"number"`
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type ReadResponse struct {
|
||||
Contact *ContactInfo `json:"contact"`
|
||||
}
|
||||
|
||||
type SocialMedia struct {
|
||||
// the label of the social
|
||||
Label string `json:"label"`
|
||||
// the username of social media
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
// optional, addresses
|
||||
Addresses []Address `json:"addresses"`
|
||||
// optional, birthday
|
||||
Birthday string `json:"birthday"`
|
||||
// optional, emails
|
||||
Emails []Email `json:"emails"`
|
||||
// required, the contact id
|
||||
Id string `json:"id"`
|
||||
// optional, links
|
||||
Links []Link `json:"links"`
|
||||
// required, the name
|
||||
Name string `json:"name"`
|
||||
// optional, note
|
||||
Note string `json:"note"`
|
||||
// optional, phone number
|
||||
Phones []Phone `json:"phones"`
|
||||
// optional, social media
|
||||
SocialMedias *SocialMedia `json:"social_medias"`
|
||||
}
|
||||
|
||||
type UpdateResponse struct {
|
||||
Contact *ContactInfo `json:"contact"`
|
||||
}
|
@ -18,26 +18,34 @@ type CryptoService struct {
|
||||
|
||||
// Returns the history for the previous close
|
||||
func (t *CryptoService) History(request *HistoryRequest) (*HistoryResponse, error) {
|
||||
|
||||
rsp := &HistoryResponse{}
|
||||
return rsp, t.client.Call("crypto", "History", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get news related to a currency
|
||||
func (t *CryptoService) News(request *NewsRequest) (*NewsResponse, error) {
|
||||
|
||||
rsp := &NewsResponse{}
|
||||
return rsp, t.client.Call("crypto", "News", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the last price for a given crypto ticker
|
||||
func (t *CryptoService) Price(request *PriceRequest) (*PriceResponse, error) {
|
||||
|
||||
rsp := &PriceResponse{}
|
||||
return rsp, t.client.Call("crypto", "Price", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the last quote for a given crypto ticker
|
||||
func (t *CryptoService) Quote(request *QuoteRequest) (*QuoteResponse, error) {
|
||||
|
||||
rsp := &QuoteResponse{}
|
||||
return rsp, t.client.Call("crypto", "Quote", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Article struct {
|
||||
@ -106,13 +114,13 @@ type QuoteRequest struct {
|
||||
|
||||
type QuoteResponse struct {
|
||||
// the asking price
|
||||
AskPrice float64 `json:"askPrice"`
|
||||
AskPrice float64 `json:"ask_price"`
|
||||
// the ask size
|
||||
AskSize float64 `json:"askSize"`
|
||||
AskSize float64 `json:"ask_size"`
|
||||
// the bidding price
|
||||
BidPrice float64 `json:"bidPrice"`
|
||||
BidPrice float64 `json:"bid_price"`
|
||||
// the bid size
|
||||
BidSize float64 `json:"bidSize"`
|
||||
BidSize float64 `json:"bid_size"`
|
||||
// the crypto symbol
|
||||
Symbol string `json:"symbol"`
|
||||
// the UTC timestamp of the quote
|
||||
|
@ -18,26 +18,34 @@ type CurrencyService struct {
|
||||
|
||||
// Codes returns the supported currency codes for the API
|
||||
func (t *CurrencyService) Codes(request *CodesRequest) (*CodesResponse, error) {
|
||||
|
||||
rsp := &CodesResponse{}
|
||||
return rsp, t.client.Call("currency", "Codes", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Convert returns the currency conversion rate between two pairs e.g USD/GBP
|
||||
func (t *CurrencyService) Convert(request *ConvertRequest) (*ConvertResponse, error) {
|
||||
|
||||
rsp := &ConvertResponse{}
|
||||
return rsp, t.client.Call("currency", "Convert", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Returns the historic rates for a currency on a given date
|
||||
func (t *CurrencyService) History(request *HistoryRequest) (*HistoryResponse, error) {
|
||||
|
||||
rsp := &HistoryResponse{}
|
||||
return rsp, t.client.Call("currency", "History", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Rates returns the currency rates for a given code e.g USD
|
||||
func (t *CurrencyService) Rates(request *RatesRequest) (*RatesResponse, error) {
|
||||
|
||||
rsp := &RatesResponse{}
|
||||
return rsp, t.client.Call("currency", "Rates", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Code struct {
|
||||
|
@ -18,38 +18,74 @@ type DbService struct {
|
||||
|
||||
// Count records in a table
|
||||
func (t *DbService) Count(request *CountRequest) (*CountResponse, error) {
|
||||
|
||||
rsp := &CountResponse{}
|
||||
return rsp, t.client.Call("db", "Count", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Create a record in the database. Optionally include an "id" field otherwise it's set automatically.
|
||||
func (t *DbService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("db", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete a record in the database by id.
|
||||
func (t *DbService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("db", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Drop a table in the DB
|
||||
func (t *DbService) DropTable(request *DropTableRequest) (*DropTableResponse, error) {
|
||||
|
||||
rsp := &DropTableResponse{}
|
||||
return rsp, t.client.Call("db", "DropTable", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List tables in the DB
|
||||
func (t *DbService) ListTables(request *ListTablesRequest) (*ListTablesResponse, error) {
|
||||
|
||||
rsp := &ListTablesResponse{}
|
||||
return rsp, t.client.Call("db", "ListTables", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read data from a table. Lookup can be by ID or via querying any field in the record.
|
||||
func (t *DbService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("db", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Rename a table
|
||||
func (t *DbService) RenameTable(request *RenameTableRequest) (*RenameTableResponse, error) {
|
||||
|
||||
rsp := &RenameTableResponse{}
|
||||
return rsp, t.client.Call("db", "RenameTable", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Truncate the records in a table
|
||||
func (t *DbService) Truncate(request *TruncateRequest) (*TruncateResponse, error) {
|
||||
|
||||
rsp := &TruncateResponse{}
|
||||
return rsp, t.client.Call("db", "Truncate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update a record in the database. Include an "id" in the record to update.
|
||||
func (t *DbService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("db", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type CountRequest struct {
|
||||
@ -63,6 +99,8 @@ type CountResponse struct {
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
// optional record id to use
|
||||
Id string `json:"id"`
|
||||
// JSON encoded record or records (can be array or object)
|
||||
Record map[string]interface{} `json:"record"`
|
||||
// Optional table name. Defaults to 'default'
|
||||
@ -84,6 +122,21 @@ type DeleteRequest struct {
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type DropTableRequest struct {
|
||||
Table string `json:"table"`
|
||||
}
|
||||
|
||||
type DropTableResponse struct {
|
||||
}
|
||||
|
||||
type ListTablesRequest struct {
|
||||
}
|
||||
|
||||
type ListTablesResponse struct {
|
||||
// list of tables
|
||||
Tables []string `json:"tables"`
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
// Read by id. Equivalent to 'id == "your-id"'
|
||||
Id string `json:"id"`
|
||||
@ -110,14 +163,21 @@ type ReadResponse struct {
|
||||
Records []map[string]interface{} `json:"records"`
|
||||
}
|
||||
|
||||
type RenameTableRequest struct {
|
||||
// current table name
|
||||
From string `json:"from"`
|
||||
// new table name
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
type RenameTableResponse struct {
|
||||
}
|
||||
|
||||
type TruncateRequest struct {
|
||||
// Optional table name. Defaults to 'default'
|
||||
Table string `json:"table"`
|
||||
}
|
||||
|
||||
type TruncateResponse struct {
|
||||
// The table truncated
|
||||
Table string `json:"table"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
|
@ -18,21 +18,23 @@ type EmailService struct {
|
||||
|
||||
// Send an email by passing in from, to, subject, and a text or html body
|
||||
func (t *EmailService) Send(request *SendRequest) (*SendResponse, error) {
|
||||
|
||||
rsp := &SendResponse{}
|
||||
return rsp, t.client.Call("email", "Send", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type SendRequest struct {
|
||||
// the display name of the sender
|
||||
From string `json:"from"`
|
||||
// the html body
|
||||
HtmlBody string `json:"htmlBody"`
|
||||
HtmlBody string `json:"html_body"`
|
||||
// an optional reply to email address
|
||||
ReplyTo string `json:"replyTo"`
|
||||
ReplyTo string `json:"reply_to"`
|
||||
// the email subject
|
||||
Subject string `json:"subject"`
|
||||
// the text body
|
||||
TextBody string `json:"textBody"`
|
||||
TextBody string `json:"text_body"`
|
||||
// the email address of the recipient
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
@ -18,27 +18,35 @@ type EmojiService struct {
|
||||
|
||||
// Find an emoji by its alias e.g :beer:
|
||||
func (t *EmojiService) Find(request *FindRequest) (*FindResponse, error) {
|
||||
|
||||
rsp := &FindResponse{}
|
||||
return rsp, t.client.Call("emoji", "Find", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the flag for a country. Requires country code e.g GB for great britain
|
||||
func (t *EmojiService) Flag(request *FlagRequest) (*FlagResponse, error) {
|
||||
|
||||
rsp := &FlagResponse{}
|
||||
return rsp, t.client.Call("emoji", "Flag", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Print text and renders the emojis with aliases e.g
|
||||
// let's grab a :beer: becomes let's grab a 🍺
|
||||
func (t *EmojiService) Print(request *PrintRequest) (*PrintResponse, error) {
|
||||
|
||||
rsp := &PrintResponse{}
|
||||
return rsp, t.client.Call("emoji", "Print", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Send an emoji to anyone via SMS. Messages are sent in the form '<message> Sent from <from>'
|
||||
func (t *EmojiService) Send(request *SendRequest) (*SendResponse, error) {
|
||||
|
||||
rsp := &SendResponse{}
|
||||
return rsp, t.client.Call("emoji", "Send", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type FindRequest struct {
|
||||
|
@ -18,62 +18,66 @@ type EvchargersService struct {
|
||||
|
||||
// Retrieve reference data as used by this API and in conjunction with the Search endpoint
|
||||
func (t *EvchargersService) ReferenceData(request *ReferenceDataRequest) (*ReferenceDataResponse, error) {
|
||||
|
||||
rsp := &ReferenceDataResponse{}
|
||||
return rsp, t.client.Call("evchargers", "ReferenceData", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Search by giving a coordinate and a max distance, or bounding box and optional filters
|
||||
func (t *EvchargersService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("evchargers", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
// Any comments about how to access the charger
|
||||
AccessComments string `json:"accessComments"`
|
||||
AddressLine1 string `json:"addressLine1"`
|
||||
AddressLine2 string `json:"addressLine2"`
|
||||
AccessComments string `json:"access_comments"`
|
||||
AddressLine1 string `json:"address_line_1"`
|
||||
AddressLine2 string `json:"address_line_2"`
|
||||
Country *Country `json:"country"`
|
||||
CountryId string `json:"countryId"`
|
||||
LatLng string `json:"latLng"`
|
||||
CountryId string `json:"country_id"`
|
||||
LatLng string `json:"lat_lng"`
|
||||
Location *Coordinates `json:"location"`
|
||||
Postcode string `json:"postcode"`
|
||||
StateOrProvince string `json:"stateOrProvince"`
|
||||
StateOrProvince string `json:"state_or_province"`
|
||||
Title string `json:"title"`
|
||||
Town string `json:"town"`
|
||||
}
|
||||
|
||||
type BoundingBox struct {
|
||||
BottomLeft *Coordinates `json:"bottomLeft"`
|
||||
TopRight *Coordinates `json:"topRight"`
|
||||
BottomLeft *Coordinates `json:"bottom_left"`
|
||||
TopRight *Coordinates `json:"top_right"`
|
||||
}
|
||||
|
||||
type ChargerType struct {
|
||||
Comments string `json:"comments"`
|
||||
Id string `json:"id"`
|
||||
// Is this 40KW+
|
||||
IsFastChargeCapable bool `json:"isFastChargeCapable"`
|
||||
IsFastChargeCapable bool `json:"is_fast_charge_capable"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type CheckinStatusType struct {
|
||||
Id string `json:"id"`
|
||||
IsAutomated bool `json:"isAutomated"`
|
||||
IsPositive bool `json:"isPositive"`
|
||||
IsAutomated bool `json:"is_automated"`
|
||||
IsPositive bool `json:"is_positive"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
// The amps offered
|
||||
Amps float64 `json:"amps"`
|
||||
ConnectionType *ConnectionType `json:"connectionType"`
|
||||
ConnectionType *ConnectionType `json:"connection_type"`
|
||||
// The ID of the connection type
|
||||
ConnectionTypeId string `json:"connectionTypeId"`
|
||||
ConnectionTypeId string `json:"connection_type_id"`
|
||||
// The current
|
||||
Current string `json:"current"`
|
||||
Level *ChargerType `json:"level"`
|
||||
// The level of charging power available
|
||||
LevelId string `json:"levelId"`
|
||||
LevelId string `json:"level_id"`
|
||||
// The power in KW
|
||||
Power float64 `json:"power"`
|
||||
Reference string `json:"reference"`
|
||||
@ -82,10 +86,10 @@ type Connection struct {
|
||||
}
|
||||
|
||||
type ConnectionType struct {
|
||||
FormalName string `json:"formalName"`
|
||||
FormalName string `json:"formal_name"`
|
||||
Id string `json:"id"`
|
||||
IsDiscontinued bool `json:"isDiscontinued"`
|
||||
IsObsolete bool `json:"isObsolete"`
|
||||
IsDiscontinued bool `json:"is_discontinued"`
|
||||
IsObsolete bool `json:"is_obsolete"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
@ -95,9 +99,9 @@ type Coordinates struct {
|
||||
}
|
||||
|
||||
type Country struct {
|
||||
ContinentCode string `json:"continentCode"`
|
||||
ContinentCode string `json:"continent_code"`
|
||||
Id string `json:"id"`
|
||||
IsoCode string `json:"isoCode"`
|
||||
IsoCode string `json:"iso_code"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
@ -109,7 +113,7 @@ type CurrentType struct {
|
||||
|
||||
type DataProvider struct {
|
||||
Comments string `json:"comments"`
|
||||
DataProviderStatusType *DataProviderStatusType `json:"dataProviderStatusType"`
|
||||
DataProviderStatusType *DataProviderStatusType `json:"data_provider_status_type"`
|
||||
Id string `json:"id"`
|
||||
// How is this data licensed
|
||||
License string `json:"license"`
|
||||
@ -119,19 +123,19 @@ type DataProvider struct {
|
||||
|
||||
type DataProviderStatusType struct {
|
||||
Id string `json:"id"`
|
||||
IsProviderEnabled bool `json:"isProviderEnabled"`
|
||||
IsProviderEnabled bool `json:"is_provider_enabled"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type Operator struct {
|
||||
Comments string `json:"comments"`
|
||||
ContactEmail string `json:"contactEmail"`
|
||||
FaultReportEmail string `json:"faultReportEmail"`
|
||||
ContactEmail string `json:"contact_email"`
|
||||
FaultReportEmail string `json:"fault_report_email"`
|
||||
Id string `json:"id"`
|
||||
// Is this operator a private individual vs a company
|
||||
IsPrivateIndividual bool `json:"isPrivateIndividual"`
|
||||
PhonePrimary string `json:"phonePrimary"`
|
||||
PhoneSecondary string `json:"phoneSecondary"`
|
||||
IsPrivateIndividual bool `json:"is_private_individual"`
|
||||
PhonePrimary string `json:"phone_primary"`
|
||||
PhoneSecondary string `json:"phone_secondary"`
|
||||
Title string `json:"title"`
|
||||
Website string `json:"website"`
|
||||
}
|
||||
@ -144,19 +148,19 @@ type Poi struct {
|
||||
// The cost of charging
|
||||
Cost string `json:"cost"`
|
||||
// The ID of the data provider
|
||||
DataProviderId string `json:"dataProviderId"`
|
||||
DataProviderId string `json:"data_provider_id"`
|
||||
// The ID of the charger
|
||||
Id string `json:"id"`
|
||||
// The number of charging points
|
||||
NumPoints int64 `json:"numPoints,string"`
|
||||
NumPoints int64 `json:"num_points,string"`
|
||||
// The operator
|
||||
Operator *Operator `json:"operator"`
|
||||
// The ID of the operator of the charger
|
||||
OperatorId string `json:"operatorId"`
|
||||
OperatorId string `json:"operator_id"`
|
||||
// The type of usage
|
||||
UsageType *UsageType `json:"usageType"`
|
||||
UsageType *UsageType `json:"usage_type"`
|
||||
// The type of usage for this charger point (is it public, membership required, etc)
|
||||
UsageTypeId string `json:"usageTypeId"`
|
||||
UsageTypeId string `json:"usage_type_id"`
|
||||
}
|
||||
|
||||
type ReferenceDataRequest struct {
|
||||
@ -164,36 +168,36 @@ type ReferenceDataRequest struct {
|
||||
|
||||
type ReferenceDataResponse struct {
|
||||
// The types of charger
|
||||
ChargerTypes *ChargerType `json:"chargerTypes"`
|
||||
ChargerTypes *ChargerType `json:"charger_types"`
|
||||
// The types of checkin status
|
||||
CheckinStatusTypes *CheckinStatusType `json:"checkinStatusTypes"`
|
||||
CheckinStatusTypes *CheckinStatusType `json:"checkin_status_types"`
|
||||
// The types of connection
|
||||
ConnectionTypes *ConnectionType `json:"connectionTypes"`
|
||||
ConnectionTypes *ConnectionType `json:"connection_types"`
|
||||
// The countries
|
||||
Countries []Country `json:"countries"`
|
||||
// The types of current
|
||||
CurrentTypes *CurrentType `json:"currentTypes"`
|
||||
CurrentTypes *CurrentType `json:"current_types"`
|
||||
// The providers of the charger data
|
||||
DataProviders *DataProvider `json:"dataProviders"`
|
||||
DataProviders *DataProvider `json:"data_providers"`
|
||||
// The companies operating the chargers
|
||||
Operators []Operator `json:"operators"`
|
||||
// The status of the charger
|
||||
StatusTypes *StatusType `json:"statusTypes"`
|
||||
StatusTypes *StatusType `json:"status_types"`
|
||||
// The status of a submission
|
||||
SubmissionStatusTypes *SubmissionStatusType `json:"submissionStatusTypes"`
|
||||
SubmissionStatusTypes *SubmissionStatusType `json:"submission_status_types"`
|
||||
// The different types of usage
|
||||
UsageTypes *UsageType `json:"usageTypes"`
|
||||
UsageTypes *UsageType `json:"usage_types"`
|
||||
// The types of user comment
|
||||
UserCommentTypes *UserCommentType `json:"userCommentTypes"`
|
||||
UserCommentTypes *UserCommentType `json:"user_comment_types"`
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
// Bounding box to search within (top left and bottom right coordinates)
|
||||
Box *BoundingBox `json:"box"`
|
||||
// IDs of the connection type
|
||||
ConnectionTypes string `json:"connectionTypes"`
|
||||
ConnectionTypes string `json:"connection_types"`
|
||||
// Country ID
|
||||
CountryId string `json:"countryId"`
|
||||
CountryId string `json:"country_id"`
|
||||
// Search distance from point in metres, defaults to 5000m
|
||||
Distance int64 `json:"distance,string"`
|
||||
// Supported charging levels
|
||||
@ -201,13 +205,13 @@ type SearchRequest struct {
|
||||
// Coordinates from which to begin search
|
||||
Location *Coordinates `json:"location"`
|
||||
// Maximum number of results to return, defaults to 100
|
||||
MaxResults int64 `json:"maxResults,string"`
|
||||
MaxResults int64 `json:"max_results,string"`
|
||||
// Minimum power in KW. Note: data not available for many chargers
|
||||
MinPower int64 `json:"minPower,string"`
|
||||
MinPower int64 `json:"min_power,string"`
|
||||
// IDs of the the EV charger operator
|
||||
Operators []string `json:"operators"`
|
||||
// Usage of the charge point (is it public, membership required, etc)
|
||||
UsageTypes string `json:"usageTypes"`
|
||||
UsageTypes string `json:"usage_types"`
|
||||
}
|
||||
|
||||
type SearchResponse struct {
|
||||
@ -216,21 +220,21 @@ type SearchResponse struct {
|
||||
|
||||
type StatusType struct {
|
||||
Id string `json:"id"`
|
||||
IsOperational bool `json:"isOperational"`
|
||||
IsOperational bool `json:"is_operational"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type SubmissionStatusType struct {
|
||||
Id string `json:"id"`
|
||||
IsLive bool `json:"isLive"`
|
||||
IsLive bool `json:"is_live"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type UsageType struct {
|
||||
Id string `json:"id"`
|
||||
IsAccessKeyRequired bool `json:"isAccessKeyRequired"`
|
||||
IsMembershipRequired bool `json:"isMembershipRequired"`
|
||||
IsPayAtLocation bool `json:"isPayAtLocation"`
|
||||
IsAccessKeyRequired bool `json:"is_access_key_required"`
|
||||
IsMembershipRequired bool `json:"is_membership_required"`
|
||||
IsPayAtLocation bool `json:"is_pay_at_location"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
|
110
services/event/event.go
Executable file
110
services/event/event.go
Executable file
@ -0,0 +1,110 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewEventService(token string) *EventService {
|
||||
return &EventService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type EventService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Consume events from a given topic.
|
||||
func (t *EventService) Consume(request *ConsumeRequest) (*ConsumeResponseStream, error) {
|
||||
stream, err := t.client.Stream("event", "Consume", request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ConsumeResponseStream{
|
||||
stream: stream,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
type ConsumeResponseStream struct {
|
||||
stream *client.Stream
|
||||
}
|
||||
|
||||
func (t *ConsumeResponseStream) Recv() (*ConsumeResponse, error) {
|
||||
var rsp ConsumeResponse
|
||||
if err := t.stream.Recv(&rsp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rsp, nil
|
||||
}
|
||||
|
||||
// Publish a event to the event stream.
|
||||
func (t *EventService) Publish(request *PublishRequest) (*PublishResponse, error) {
|
||||
|
||||
rsp := &PublishResponse{}
|
||||
return rsp, t.client.Call("event", "Publish", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read stored events
|
||||
func (t *EventService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("event", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type ConsumeRequest struct {
|
||||
// Optional group for the subscription
|
||||
Group string `json:"group"`
|
||||
// Optional offset to read from e.g "2006-01-02T15:04:05.999Z07:00"
|
||||
Offset string `json:"offset"`
|
||||
// The topic to subscribe to
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type ConsumeResponse struct {
|
||||
// Unique message id
|
||||
Id string `json:"id"`
|
||||
// The next json message on the topic
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// Timestamp of publishing
|
||||
Timestamp string `json:"timestamp"`
|
||||
// The topic subscribed to
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type Ev struct {
|
||||
// event id
|
||||
Id string `json:"id"`
|
||||
// event message
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// event timestamp
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
type PublishRequest struct {
|
||||
// The json message to publish
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// The topic to publish to
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type PublishResponse struct {
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
// number of events to read; default 25
|
||||
Limit int32 `json:"limit"`
|
||||
// offset for the events; default 0
|
||||
Offset int32 `json:"offset"`
|
||||
// topic to read from
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type ReadResponse struct {
|
||||
// the events
|
||||
Events []Ev `json:"events"`
|
||||
}
|
@ -18,33 +18,34 @@ type FileService struct {
|
||||
|
||||
// Delete a file by project name/path
|
||||
func (t *FileService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("file", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List files by their project and optionally a path.
|
||||
func (t *FileService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("file", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read a file by path
|
||||
func (t *FileService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("file", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Save a file
|
||||
func (t *FileService) Save(request *SaveRequest) (*SaveResponse, error) {
|
||||
|
||||
rsp := &SaveResponse{}
|
||||
return rsp, t.client.Call("file", "Save", request, rsp)
|
||||
}
|
||||
|
||||
type BatchSaveRequest struct {
|
||||
Files []Record `json:"files"`
|
||||
}
|
||||
|
||||
type BatchSaveResponse struct {
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
|
@ -18,20 +18,26 @@ type ForexService struct {
|
||||
|
||||
// Returns the data for the previous close
|
||||
func (t *ForexService) History(request *HistoryRequest) (*HistoryResponse, error) {
|
||||
|
||||
rsp := &HistoryResponse{}
|
||||
return rsp, t.client.Call("forex", "History", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the latest price for a given forex ticker
|
||||
func (t *ForexService) Price(request *PriceRequest) (*PriceResponse, error) {
|
||||
|
||||
rsp := &PriceResponse{}
|
||||
return rsp, t.client.Call("forex", "Price", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the latest quote for the forex
|
||||
func (t *ForexService) Quote(request *QuoteRequest) (*QuoteResponse, error) {
|
||||
|
||||
rsp := &QuoteResponse{}
|
||||
return rsp, t.client.Call("forex", "Quote", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type HistoryRequest struct {
|
||||
@ -75,9 +81,9 @@ type QuoteRequest struct {
|
||||
|
||||
type QuoteResponse struct {
|
||||
// the asking price
|
||||
AskPrice float64 `json:"askPrice"`
|
||||
AskPrice float64 `json:"ask_price"`
|
||||
// the bidding price
|
||||
BidPrice float64 `json:"bidPrice"`
|
||||
BidPrice float64 `json:"bid_price"`
|
||||
// the forex symbol
|
||||
Symbol string `json:"symbol"`
|
||||
// the UTC timestamp of the quote
|
||||
|
@ -18,32 +18,74 @@ type FunctionService struct {
|
||||
|
||||
// Call a function by name
|
||||
func (t *FunctionService) Call(request *CallRequest) (*CallResponse, error) {
|
||||
|
||||
rsp := &CallResponse{}
|
||||
return rsp, t.client.Call("function", "Call", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete a function by name
|
||||
func (t *FunctionService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("function", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Deploy a group of functions
|
||||
func (t *FunctionService) Deploy(request *DeployRequest) (*DeployResponse, error) {
|
||||
|
||||
rsp := &DeployResponse{}
|
||||
return rsp, t.client.Call("function", "Deploy", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the info for a deployed function
|
||||
func (t *FunctionService) Describe(request *DescribeRequest) (*DescribeResponse, error) {
|
||||
|
||||
rsp := &DescribeResponse{}
|
||||
return rsp, t.client.Call("function", "Describe", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List all the deployed functions
|
||||
func (t *FunctionService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("function", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Return the backend url for proxying
|
||||
func (t *FunctionService) Proxy(request *ProxyRequest) (*ProxyResponse, error) {
|
||||
|
||||
rsp := &ProxyResponse{}
|
||||
return rsp, t.client.Call("function", "Proxy", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Return a list of supported regions
|
||||
func (t *FunctionService) Regions(request *RegionsRequest) (*RegionsResponse, error) {
|
||||
|
||||
rsp := &RegionsResponse{}
|
||||
return rsp, t.client.Call("function", "Regions", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Reserve function names and resources beyond free quota
|
||||
func (t *FunctionService) Reserve(request *ReserveRequest) (*ReserveResponse, error) {
|
||||
|
||||
rsp := &ReserveResponse{}
|
||||
return rsp, t.client.Call("function", "Reserve", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update a function. Downloads the source, builds and redeploys
|
||||
func (t *FunctionService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("function", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type CallRequest struct {
|
||||
@ -61,33 +103,28 @@ type CallResponse struct {
|
||||
type DeleteRequest struct {
|
||||
// The name of the function
|
||||
Name string `json:"name"`
|
||||
// Optional project name
|
||||
Project string `json:"project"`
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type DeployRequest struct {
|
||||
// branch to deploy. defaults to master
|
||||
Branch string `json:"branch"`
|
||||
// entry point, ie. handler name in the source code
|
||||
// if not provided, defaults to the name parameter
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
// environment variables to pass in at runtime
|
||||
EnvVars map[string]string `json:"envVars"`
|
||||
EnvVars map[string]string `json:"env_vars"`
|
||||
// function name
|
||||
Name string `json:"name"`
|
||||
// project is used for namespacing your functions
|
||||
// optional. defaults to "default".
|
||||
Project string `json:"project"`
|
||||
// region to deploy in. defaults to europe-west1
|
||||
Region string `json:"region"`
|
||||
// github url to repo
|
||||
Repo string `json:"repo"`
|
||||
// runtime/language of the function
|
||||
// eg: php74,
|
||||
// nodejs6, nodejs8, nodejs10, nodejs12, nodejs14, nodejs16
|
||||
// dotnet3
|
||||
// java11
|
||||
// ruby26, ruby27
|
||||
// go111, go113, go116
|
||||
// runtime/lanaguage of the function e.g php74,
|
||||
// nodejs6, nodejs8, nodejs10, nodejs12, nodejs14, nodejs16,
|
||||
// dotnet3, java11, ruby26, ruby27, go111, go113, go116,
|
||||
// python37, python38, python39
|
||||
Runtime string `json:"runtime"`
|
||||
// optional subfolder path
|
||||
@ -95,57 +132,104 @@ type DeployRequest struct {
|
||||
}
|
||||
|
||||
type DeployResponse struct {
|
||||
Function *Func `json:"function"`
|
||||
}
|
||||
|
||||
type DescribeRequest struct {
|
||||
// The name of the function
|
||||
Name string `json:"name"`
|
||||
// Optional project name
|
||||
Project string `json:"project"`
|
||||
}
|
||||
|
||||
type DescribeResponse struct {
|
||||
// The function requested
|
||||
Function *Func `json:"function"`
|
||||
// The timeout for requests to the function
|
||||
Timeout string `json:"timeout"`
|
||||
// The time at which the function was updated
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type Func struct {
|
||||
// branch to deploy. defaults to master
|
||||
Branch string `json:"branch"`
|
||||
// time of creation
|
||||
Created string `json:"created"`
|
||||
// name of handler in source code
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
// associated env vars
|
||||
EnvVars map[string]string `json:"env_vars"`
|
||||
// id of the function
|
||||
Id string `json:"id"`
|
||||
// function name
|
||||
// limitation: must be unique across projects
|
||||
Name string `json:"name"`
|
||||
// project of function, optional
|
||||
// defaults to literal "default"
|
||||
// used to namespace functions
|
||||
Project string `json:"project"`
|
||||
// region to deploy in. defaults to europe-west1
|
||||
Region string `json:"region"`
|
||||
// git repo address
|
||||
Repo string `json:"repo"`
|
||||
// runtime/language of the function
|
||||
// eg: php74,
|
||||
// nodejs6, nodejs8, nodejs10, nodejs12, nodejs14, nodejs16
|
||||
// dotnet3
|
||||
// java11
|
||||
// ruby26, ruby27
|
||||
// go111, go113, go116
|
||||
// runtime/language of the function e.g php74,
|
||||
// nodejs6, nodejs8, nodejs10, nodejs12, nodejs14, nodejs16,
|
||||
// dotnet3, java11, ruby26, ruby27, go111, go113, go116,
|
||||
// python37, python38, python39
|
||||
Runtime string `json:"runtime"`
|
||||
// eg. ACTIVE, DEPLOY_IN_PROGRESS, OFFLINE etc
|
||||
Status string `json:"status"`
|
||||
// subfolder path to entrypoint
|
||||
Subfolder string `json:"subfolder"`
|
||||
// time it was updated
|
||||
Updated string `json:"updated"`
|
||||
// unique url of the function
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
// optional project name
|
||||
Project string `json:"project"`
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
// List of functions deployed
|
||||
Functions []Func `json:"functions"`
|
||||
}
|
||||
|
||||
type ProxyRequest struct {
|
||||
// id of the function
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type ProxyResponse struct {
|
||||
// backend url
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type RegionsRequest struct {
|
||||
}
|
||||
|
||||
type RegionsResponse struct {
|
||||
Regions []string `json:"regions"`
|
||||
}
|
||||
|
||||
type Reservation struct {
|
||||
// time of reservation
|
||||
Created string `json:"created"`
|
||||
// time reservation expires
|
||||
Expires string `json:"expires"`
|
||||
// name of the app
|
||||
Name string `json:"name"`
|
||||
// owner id
|
||||
Owner string `json:"owner"`
|
||||
// associated token
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type ReserveRequest struct {
|
||||
// name of your app e.g helloworld
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ReserveResponse struct {
|
||||
// The app reservation
|
||||
Reservation *Reservation `json:"reservation"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
// function name
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type UpdateResponse struct {
|
||||
}
|
||||
|
@ -18,21 +18,25 @@ type GeocodingService struct {
|
||||
|
||||
// Lookup returns a geocoded address including normalized address and gps coordinates. All fields are optional, provide more to get more accurate results
|
||||
func (t *GeocodingService) Lookup(request *LookupRequest) (*LookupResponse, error) {
|
||||
|
||||
rsp := &LookupResponse{}
|
||||
return rsp, t.client.Call("geocoding", "Lookup", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Reverse lookup an address from gps coordinates
|
||||
func (t *GeocodingService) Reverse(request *ReverseRequest) (*ReverseResponse, error) {
|
||||
|
||||
rsp := &ReverseResponse{}
|
||||
return rsp, t.client.Call("geocoding", "Reverse", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
City string `json:"city"`
|
||||
Country string `json:"country"`
|
||||
LineOne string `json:"lineOne"`
|
||||
LineTwo string `json:"lineTwo"`
|
||||
LineOne string `json:"line_one"`
|
||||
LineTwo string `json:"line_two"`
|
||||
Postcode string `json:"postcode"`
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,15 @@ type GifsService struct {
|
||||
|
||||
// Search for a GIF
|
||||
func (t *GifsService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("gifs", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Gif struct {
|
||||
// URL used for embedding the GIF
|
||||
EmbedUrl string `json:"embedUrl"`
|
||||
EmbedUrl string `json:"embed_url"`
|
||||
// The ID of the GIF
|
||||
Id string `json:"id"`
|
||||
// The different formats available for this GIF
|
||||
@ -32,7 +34,7 @@ type Gif struct {
|
||||
// The content rating for the GIF
|
||||
Rating string `json:"rating"`
|
||||
// A short URL for this GIF
|
||||
ShortUrl string `json:"shortUrl"`
|
||||
ShortUrl string `json:"short_url"`
|
||||
// The slug used in the GIF's URL
|
||||
Slug string `json:"slug"`
|
||||
// The page on which this GIF was found
|
||||
@ -47,17 +49,17 @@ type ImageFormat struct {
|
||||
// height
|
||||
Height int32 `json:"height"`
|
||||
// size of the MP4 version
|
||||
Mp4size int32 `json:"mp4size"`
|
||||
Mp4Size int32 `json:"mp4_size"`
|
||||
// URL to an MP4 version of the gif
|
||||
Mp4url string `json:"mp4url"`
|
||||
Mp4Url string `json:"mp4_url"`
|
||||
// size in bytes
|
||||
Size int32 `json:"size"`
|
||||
// URL of the gif
|
||||
Url string `json:"url"`
|
||||
// size of the webp version
|
||||
WebpSize int32 `json:"webpSize"`
|
||||
WebpSize int32 `json:"webp_size"`
|
||||
// URL to a webp version of the gif
|
||||
WebpUrl string `json:"webpUrl"`
|
||||
WebpUrl string `json:"webp_url"`
|
||||
// width
|
||||
Width int32 `json:"width"`
|
||||
}
|
||||
@ -66,43 +68,43 @@ type ImageFormats struct {
|
||||
// A downsized version of the GIF < 2MB
|
||||
Downsized *ImageFormat `json:"downsized"`
|
||||
// A downsized version of the GIF < 8MB
|
||||
DownsizedLarge *ImageFormat `json:"downsizedLarge"`
|
||||
DownsizedLarge *ImageFormat `json:"downsized_large"`
|
||||
// A downsized version of the GIF < 5MB
|
||||
DownsizedMedium *ImageFormat `json:"downsizedMedium"`
|
||||
DownsizedMedium *ImageFormat `json:"downsized_medium"`
|
||||
// A downsized version of the GIF < 200kb
|
||||
DownsizedSmall *ImageFormat `json:"downsizedSmall"`
|
||||
DownsizedSmall *ImageFormat `json:"downsized_small"`
|
||||
// Static image of the downsized version of the GIF
|
||||
DownsizedStill *ImageFormat `json:"downsizedStill"`
|
||||
DownsizedStill *ImageFormat `json:"downsized_still"`
|
||||
// Version of the GIF with fixed height of 200 pixels. Good for mobile use
|
||||
FixedHeight *ImageFormat `json:"fixedHeight"`
|
||||
FixedHeight *ImageFormat `json:"fixed_height"`
|
||||
// Version of the GIF with fixed height of 200 pixels and number of frames reduced to 6
|
||||
FixedHeightDownsampled *ImageFormat `json:"fixedHeightDownsampled"`
|
||||
FixedHeightDownsampled *ImageFormat `json:"fixed_height_downsampled"`
|
||||
// Version of the GIF with fixed height of 100 pixels. Good for mobile keyboards
|
||||
FixedHeightSmall *ImageFormat `json:"fixedHeightSmall"`
|
||||
FixedHeightSmall *ImageFormat `json:"fixed_height_small"`
|
||||
// Static image of the GIF with fixed height of 100 pixels
|
||||
FixedHeightSmallStill *ImageFormat `json:"fixedHeightSmallStill"`
|
||||
FixedHeightSmallStill *ImageFormat `json:"fixed_height_small_still"`
|
||||
// Static image of the GIF with fixed height of 200 pixels
|
||||
FixedHeightStill *ImageFormat `json:"fixedHeightStill"`
|
||||
FixedHeightStill *ImageFormat `json:"fixed_height_still"`
|
||||
// Version of the GIF with fixed width of 200 pixels. Good for mobile use
|
||||
FixedWidth *ImageFormat `json:"fixedWidth"`
|
||||
FixedWidth *ImageFormat `json:"fixed_width"`
|
||||
// Version of the GIF with fixed width of 200 pixels and number of frames reduced to 6
|
||||
FixedWidthDownsampled *ImageFormat `json:"fixedWidthDownsampled"`
|
||||
FixedWidthDownsampled *ImageFormat `json:"fixed_width_downsampled"`
|
||||
// Version of the GIF with fixed width of 100 pixels. Good for mobile keyboards
|
||||
FixedWidthSmall *ImageFormat `json:"fixedWidthSmall"`
|
||||
FixedWidthSmall *ImageFormat `json:"fixed_width_small"`
|
||||
// Static image of the GIF with fixed width of 100 pixels
|
||||
FixedWidthSmallStill *ImageFormat `json:"fixedWidthSmallStill"`
|
||||
FixedWidthSmallStill *ImageFormat `json:"fixed_width_small_still"`
|
||||
// Static image of the GIF with fixed width of 200 pixels
|
||||
FixedWidthStill *ImageFormat `json:"fixedWidthStill"`
|
||||
FixedWidthStill *ImageFormat `json:"fixed_width_still"`
|
||||
// 15 second version of the GIF looping
|
||||
Looping *ImageFormat `json:"looping"`
|
||||
// The original GIF. Good for desktop use
|
||||
Original *ImageFormat `json:"original"`
|
||||
// Static image of the original version of the GIF
|
||||
OriginalStill *ImageFormat `json:"originalStill"`
|
||||
OriginalStill *ImageFormat `json:"original_still"`
|
||||
// mp4 version of the GIF <50kb displaying first 1-2 secs
|
||||
Preview *ImageFormat `json:"preview"`
|
||||
// Version of the GIF <50kb displaying first 1-2 secs
|
||||
PreviewGif *ImageFormat `json:"previewGif"`
|
||||
PreviewGif *ImageFormat `json:"preview_gif"`
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
@ -111,7 +113,7 @@ type Pagination struct {
|
||||
// position in pagination
|
||||
Offset int32 `json:"offset"`
|
||||
// total number of results available
|
||||
TotalCount int32 `json:"totalCount"`
|
||||
TotalCount int32 `json:"total_count"`
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
|
5
services/go.mod
Normal file
5
services/go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module go.m3o.com
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/gorilla/websocket v1.4.2
|
2
services/go.sum
Normal file
2
services/go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
@ -18,8 +18,10 @@ type GoogleService struct {
|
||||
|
||||
// Search for videos on Google
|
||||
func (t *GoogleService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("google", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
@ -34,7 +36,7 @@ type SearchResponse struct {
|
||||
|
||||
type SearchResult struct {
|
||||
// abridged version of this search result’s URL, e.g. www.exampe.com
|
||||
DisplayUrl string `json:"displayUrl"`
|
||||
DisplayUrl string `json:"display_url"`
|
||||
// id of the result
|
||||
Id string `json:"id"`
|
||||
// kind of result; "search"
|
||||
|
@ -18,14 +18,34 @@ type HelloworldService struct {
|
||||
|
||||
// Call returns a personalised "Hello $name" response
|
||||
func (t *HelloworldService) Call(request *CallRequest) (*CallResponse, error) {
|
||||
|
||||
rsp := &CallResponse{}
|
||||
return rsp, t.client.Call("helloworld", "Call", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Stream returns a stream of "Hello $name" responses
|
||||
func (t *HelloworldService) Stream(request *StreamRequest) (*StreamResponse, error) {
|
||||
rsp := &StreamResponse{}
|
||||
return rsp, t.client.Call("helloworld", "Stream", request, rsp)
|
||||
func (t *HelloworldService) Stream(request *StreamRequest) (*StreamResponseStream, error) {
|
||||
stream, err := t.client.Stream("helloworld", "Stream", request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &StreamResponseStream{
|
||||
stream: stream,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
type StreamResponseStream struct {
|
||||
stream *client.Stream
|
||||
}
|
||||
|
||||
func (t *StreamResponseStream) Recv() (*StreamResponse, error) {
|
||||
var rsp StreamResponse
|
||||
if err := t.stream.Recv(&rsp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rsp, nil
|
||||
}
|
||||
|
||||
type CallRequest struct {
|
||||
|
@ -18,14 +18,18 @@ type HolidaysService struct {
|
||||
|
||||
// Get the list of countries that are supported by this API
|
||||
func (t *HolidaysService) Countries(request *CountriesRequest) (*CountriesResponse, error) {
|
||||
|
||||
rsp := &CountriesResponse{}
|
||||
return rsp, t.client.Call("holidays", "Countries", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List the holiday dates for a given country and year
|
||||
func (t *HolidaysService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("holidays", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type CountriesRequest struct {
|
||||
@ -44,11 +48,11 @@ type Country struct {
|
||||
|
||||
type Holiday struct {
|
||||
// the country this holiday occurs in
|
||||
CountryCode string `json:"countryCode"`
|
||||
CountryCode string `json:"country_code"`
|
||||
// date of the holiday in yyyy-mm-dd format
|
||||
Date string `json:"date"`
|
||||
// the local name of the holiday
|
||||
LocalName string `json:"localName"`
|
||||
LocalName string `json:"local_name"`
|
||||
// the name of the holiday in English
|
||||
Name string `json:"name"`
|
||||
// the regions within the country that observe this holiday (if not all of them)
|
||||
@ -59,7 +63,7 @@ type Holiday struct {
|
||||
|
||||
type ListRequest struct {
|
||||
// The 2 letter country code (as defined in ISO 3166-1 alpha-2)
|
||||
CountryCode string `json:"countryCode"`
|
||||
CountryCode string `json:"country_code"`
|
||||
// The year to list holidays for
|
||||
Year int64 `json:"year,string"`
|
||||
}
|
||||
|
@ -18,14 +18,18 @@ type IdService struct {
|
||||
|
||||
// Generate a unique ID. Defaults to uuid.
|
||||
func (t *IdService) Generate(request *GenerateRequest) (*GenerateResponse, error) {
|
||||
|
||||
rsp := &GenerateResponse{}
|
||||
return rsp, t.client.Call("id", "Generate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List the types of IDs available. No query params needed.
|
||||
func (t *IdService) Types(request *TypesRequest) (*TypesResponse, error) {
|
||||
|
||||
rsp := &TypesResponse{}
|
||||
return rsp, t.client.Call("id", "Types", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type GenerateRequest struct {
|
||||
|
@ -18,33 +18,55 @@ type ImageService struct {
|
||||
|
||||
// Convert an image from one format (jpeg, png etc.) to an other either on the fly (from base64 to base64),
|
||||
// or by uploading the conversion result.
|
||||
// To use the file parameter you need to send the request as a multipart/form-data rather than the usual application/json
|
||||
// with each parameter as a form field.
|
||||
func (t *ImageService) Convert(request *ConvertRequest) (*ConvertResponse, error) {
|
||||
|
||||
rsp := &ConvertResponse{}
|
||||
return rsp, t.client.Call("image", "Convert", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete an image previously uploaded.
|
||||
func (t *ImageService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("image", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Resize an image on the fly without storing it (by sending and receiving a base64 encoded image), or resize and upload depending on parameters.
|
||||
// If one of width or height is 0, the image aspect ratio is preserved.
|
||||
// Optional cropping.
|
||||
// To use the file parameter you need to send the request as a multipart/form-data rather than the usual application/json
|
||||
// with each parameter as a form field.
|
||||
func (t *ImageService) Resize(request *ResizeRequest) (*ResizeResponse, error) {
|
||||
|
||||
rsp := &ResizeResponse{}
|
||||
return rsp, t.client.Call("image", "Resize", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Upload an image by either sending a base64 encoded image to this endpoint or a URL.
|
||||
// To resize an image before uploading, see the Resize endpoint.
|
||||
// To use the file parameter you need to send the request as a multipart/form-data rather than the usual application/json
|
||||
// with each parameter as a form field.
|
||||
func (t *ImageService) Upload(request *UploadRequest) (*UploadResponse, error) {
|
||||
|
||||
rsp := &UploadResponse{}
|
||||
return rsp, t.client.Call("image", "Upload", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type ConvertRequest struct {
|
||||
// base64 encoded image to resize,
|
||||
Base64 string `json:"base64"`
|
||||
// The image file to convert
|
||||
File string `json:"file"`
|
||||
// output name of the image including extension, ie. "cat.png"
|
||||
Name string `json:"name"`
|
||||
// make output a URL and not a base64 response
|
||||
OutputUrl bool `json:"outputUrl"`
|
||||
OutputUrl bool `json:"outputURL"`
|
||||
// url of the image to resize
|
||||
Url string `json:"url"`
|
||||
}
|
||||
@ -66,6 +88,14 @@ type CropOptions struct {
|
||||
Width int32 `json:"width"`
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
// url of the image to delete e.g. https://cdn.m3ocontent.com/micro/images/micro/41e23b39-48dd-42b6-9738-79a313414bb8/cat.jpeg
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
X int32 `json:"x"`
|
||||
Y int32 `json:"y"`
|
||||
@ -83,11 +113,13 @@ type ResizeRequest struct {
|
||||
// if provided, after resize, the image
|
||||
// will be cropped
|
||||
CropOptions *CropOptions `json:"cropOptions"`
|
||||
Height int64 `json:"height,string"`
|
||||
// The image file to resize
|
||||
File string `json:"file"`
|
||||
Height int64 `json:"height,string"`
|
||||
// output name of the image including extension, ie. "cat.png"
|
||||
Name string `json:"name"`
|
||||
// make output a URL and not a base64 response
|
||||
OutputUrl bool `json:"outputUrl"`
|
||||
OutputUrl bool `json:"outputURL"`
|
||||
// url of the image to resize
|
||||
Url string `json:"url"`
|
||||
Width int64 `json:"width,string"`
|
||||
@ -101,6 +133,8 @@ type ResizeResponse struct {
|
||||
type UploadRequest struct {
|
||||
// Base64 encoded image to upload,
|
||||
Base64 string `json:"base64"`
|
||||
// The image file to upload
|
||||
File string `json:"file"`
|
||||
// Output name of the image including extension, ie. "cat.png"
|
||||
Name string `json:"name"`
|
||||
// URL of the image to upload
|
||||
|
@ -18,8 +18,10 @@ type IpService struct {
|
||||
|
||||
// Lookup the geolocation information for an IP address
|
||||
func (t *IpService) Lookup(request *LookupRequest) (*LookupResponse, error) {
|
||||
|
||||
rsp := &LookupResponse{}
|
||||
return rsp, t.client.Call("ip", "Lookup", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type LookupRequest struct {
|
||||
|
42
services/joke/joke.go
Executable file
42
services/joke/joke.go
Executable file
@ -0,0 +1,42 @@
|
||||
package joke
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewJokeService(token string) *JokeService {
|
||||
return &JokeService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type JokeService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Get a random joke
|
||||
func (t *JokeService) Random(request *RandomRequest) (*RandomResponse, error) {
|
||||
|
||||
rsp := &RandomResponse{}
|
||||
return rsp, t.client.Call("joke", "Random", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type JokeInfo struct {
|
||||
Body string `json:"body"`
|
||||
Category string `json:"category"`
|
||||
Id string `json:"id"`
|
||||
Source string `json:"source"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type RandomRequest struct {
|
||||
// the count of random jokes want, maximum: 10
|
||||
Count int32 `json:"count"`
|
||||
}
|
||||
|
||||
type RandomResponse struct {
|
||||
Jokes []JokeInfo `json:"jokes"`
|
||||
}
|
@ -18,20 +18,26 @@ type LocationService struct {
|
||||
|
||||
// Read an entity by its ID
|
||||
func (t *LocationService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("location", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Save an entity's current position
|
||||
func (t *LocationService) Save(request *SaveRequest) (*SaveResponse, error) {
|
||||
|
||||
rsp := &SaveResponse{}
|
||||
return rsp, t.client.Call("location", "Save", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Search for entities in a given radius
|
||||
func (t *LocationService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("location", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Entity struct {
|
||||
|
181
services/m3o.go
Executable file
181
services/m3o.go
Executable file
@ -0,0 +1,181 @@
|
||||
package m3o
|
||||
|
||||
import (
|
||||
"go.m3o.com/address"
|
||||
"go.m3o.com/answer"
|
||||
"go.m3o.com/app"
|
||||
"go.m3o.com/avatar"
|
||||
"go.m3o.com/cache"
|
||||
"go.m3o.com/contact"
|
||||
"go.m3o.com/crypto"
|
||||
"go.m3o.com/currency"
|
||||
"go.m3o.com/db"
|
||||
"go.m3o.com/email"
|
||||
"go.m3o.com/emoji"
|
||||
"go.m3o.com/evchargers"
|
||||
"go.m3o.com/event"
|
||||
"go.m3o.com/file"
|
||||
"go.m3o.com/forex"
|
||||
"go.m3o.com/function"
|
||||
"go.m3o.com/geocoding"
|
||||
"go.m3o.com/gifs"
|
||||
"go.m3o.com/google"
|
||||
"go.m3o.com/helloworld"
|
||||
"go.m3o.com/holidays"
|
||||
"go.m3o.com/id"
|
||||
"go.m3o.com/image"
|
||||
"go.m3o.com/ip"
|
||||
"go.m3o.com/joke"
|
||||
"go.m3o.com/location"
|
||||
"go.m3o.com/movie"
|
||||
"go.m3o.com/mq"
|
||||
"go.m3o.com/news"
|
||||
"go.m3o.com/nft"
|
||||
"go.m3o.com/notes"
|
||||
"go.m3o.com/otp"
|
||||
"go.m3o.com/postcode"
|
||||
"go.m3o.com/prayer"
|
||||
"go.m3o.com/qr"
|
||||
"go.m3o.com/quran"
|
||||
"go.m3o.com/routing"
|
||||
"go.m3o.com/rss"
|
||||
"go.m3o.com/search"
|
||||
"go.m3o.com/sentiment"
|
||||
"go.m3o.com/sms"
|
||||
"go.m3o.com/space"
|
||||
"go.m3o.com/spam"
|
||||
"go.m3o.com/stock"
|
||||
"go.m3o.com/stream"
|
||||
"go.m3o.com/sunnah"
|
||||
"go.m3o.com/thumbnail"
|
||||
"go.m3o.com/time"
|
||||
"go.m3o.com/translate"
|
||||
"go.m3o.com/twitter"
|
||||
"go.m3o.com/url"
|
||||
"go.m3o.com/user"
|
||||
"go.m3o.com/vehicle"
|
||||
"go.m3o.com/weather"
|
||||
"go.m3o.com/youtube"
|
||||
)
|
||||
|
||||
func NewClient(token string) *Client {
|
||||
return &Client{
|
||||
token: token,
|
||||
|
||||
AddressService: address.NewAddressService(token),
|
||||
AnswerService: answer.NewAnswerService(token),
|
||||
AppService: app.NewAppService(token),
|
||||
AvatarService: avatar.NewAvatarService(token),
|
||||
CacheService: cache.NewCacheService(token),
|
||||
ContactService: contact.NewContactService(token),
|
||||
CryptoService: crypto.NewCryptoService(token),
|
||||
CurrencyService: currency.NewCurrencyService(token),
|
||||
DbService: db.NewDbService(token),
|
||||
EmailService: email.NewEmailService(token),
|
||||
EmojiService: emoji.NewEmojiService(token),
|
||||
EvchargersService: evchargers.NewEvchargersService(token),
|
||||
EventService: event.NewEventService(token),
|
||||
FileService: file.NewFileService(token),
|
||||
ForexService: forex.NewForexService(token),
|
||||
FunctionService: function.NewFunctionService(token),
|
||||
GeocodingService: geocoding.NewGeocodingService(token),
|
||||
GifsService: gifs.NewGifsService(token),
|
||||
GoogleService: google.NewGoogleService(token),
|
||||
HelloworldService: helloworld.NewHelloworldService(token),
|
||||
HolidaysService: holidays.NewHolidaysService(token),
|
||||
IdService: id.NewIdService(token),
|
||||
ImageService: image.NewImageService(token),
|
||||
IpService: ip.NewIpService(token),
|
||||
JokeService: joke.NewJokeService(token),
|
||||
LocationService: location.NewLocationService(token),
|
||||
MovieService: movie.NewMovieService(token),
|
||||
MqService: mq.NewMqService(token),
|
||||
NewsService: news.NewNewsService(token),
|
||||
NftService: nft.NewNftService(token),
|
||||
NotesService: notes.NewNotesService(token),
|
||||
OtpService: otp.NewOtpService(token),
|
||||
PostcodeService: postcode.NewPostcodeService(token),
|
||||
PrayerService: prayer.NewPrayerService(token),
|
||||
QrService: qr.NewQrService(token),
|
||||
QuranService: quran.NewQuranService(token),
|
||||
RoutingService: routing.NewRoutingService(token),
|
||||
RssService: rss.NewRssService(token),
|
||||
SearchService: search.NewSearchService(token),
|
||||
SentimentService: sentiment.NewSentimentService(token),
|
||||
SmsService: sms.NewSmsService(token),
|
||||
SpaceService: space.NewSpaceService(token),
|
||||
SpamService: spam.NewSpamService(token),
|
||||
StockService: stock.NewStockService(token),
|
||||
StreamService: stream.NewStreamService(token),
|
||||
SunnahService: sunnah.NewSunnahService(token),
|
||||
ThumbnailService: thumbnail.NewThumbnailService(token),
|
||||
TimeService: time.NewTimeService(token),
|
||||
TranslateService: translate.NewTranslateService(token),
|
||||
TwitterService: twitter.NewTwitterService(token),
|
||||
UrlService: url.NewUrlService(token),
|
||||
UserService: user.NewUserService(token),
|
||||
VehicleService: vehicle.NewVehicleService(token),
|
||||
WeatherService: weather.NewWeatherService(token),
|
||||
YoutubeService: youtube.NewYoutubeService(token),
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
token string
|
||||
|
||||
AddressService *address.AddressService
|
||||
AnswerService *answer.AnswerService
|
||||
AppService *app.AppService
|
||||
AvatarService *avatar.AvatarService
|
||||
CacheService *cache.CacheService
|
||||
ContactService *contact.ContactService
|
||||
CryptoService *crypto.CryptoService
|
||||
CurrencyService *currency.CurrencyService
|
||||
DbService *db.DbService
|
||||
EmailService *email.EmailService
|
||||
EmojiService *emoji.EmojiService
|
||||
EvchargersService *evchargers.EvchargersService
|
||||
EventService *event.EventService
|
||||
FileService *file.FileService
|
||||
ForexService *forex.ForexService
|
||||
FunctionService *function.FunctionService
|
||||
GeocodingService *geocoding.GeocodingService
|
||||
GifsService *gifs.GifsService
|
||||
GoogleService *google.GoogleService
|
||||
HelloworldService *helloworld.HelloworldService
|
||||
HolidaysService *holidays.HolidaysService
|
||||
IdService *id.IdService
|
||||
ImageService *image.ImageService
|
||||
IpService *ip.IpService
|
||||
JokeService *joke.JokeService
|
||||
LocationService *location.LocationService
|
||||
MovieService *movie.MovieService
|
||||
MqService *mq.MqService
|
||||
NewsService *news.NewsService
|
||||
NftService *nft.NftService
|
||||
NotesService *notes.NotesService
|
||||
OtpService *otp.OtpService
|
||||
PostcodeService *postcode.PostcodeService
|
||||
PrayerService *prayer.PrayerService
|
||||
QrService *qr.QrService
|
||||
QuranService *quran.QuranService
|
||||
RoutingService *routing.RoutingService
|
||||
RssService *rss.RssService
|
||||
SearchService *search.SearchService
|
||||
SentimentService *sentiment.SentimentService
|
||||
SmsService *sms.SmsService
|
||||
SpaceService *space.SpaceService
|
||||
SpamService *spam.SpamService
|
||||
StockService *stock.StockService
|
||||
StreamService *stream.StreamService
|
||||
SunnahService *sunnah.SunnahService
|
||||
ThumbnailService *thumbnail.ThumbnailService
|
||||
TimeService *time.TimeService
|
||||
TranslateService *translate.TranslateService
|
||||
TwitterService *twitter.TwitterService
|
||||
UrlService *url.UrlService
|
||||
UserService *user.UserService
|
||||
VehicleService *vehicle.VehicleService
|
||||
WeatherService *weather.WeatherService
|
||||
YoutubeService *youtube.YoutubeService
|
||||
}
|
64
services/movie/movie.go
Executable file
64
services/movie/movie.go
Executable file
@ -0,0 +1,64 @@
|
||||
package movie
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewMovieService(token string) *MovieService {
|
||||
return &MovieService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type MovieService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Search for movies by simple text search
|
||||
func (t *MovieService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("movie", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type MovieInfo struct {
|
||||
Adult bool `json:"adult"`
|
||||
BackdropPath string `json:"backdrop_path"`
|
||||
GenreIds int32 `json:"genre_ids"`
|
||||
Id int32 `json:"id"`
|
||||
OriginalLanguage string `json:"original_language"`
|
||||
OriginalTitle string `json:"original_title"`
|
||||
Overview string `json:"overview"`
|
||||
Popularity float64 `json:"popularity"`
|
||||
PosterPath string `json:"poster_path"`
|
||||
ReleaseDate string `json:"release_date"`
|
||||
Title string `json:"title"`
|
||||
Video bool `json:"video"`
|
||||
VoteAverage float64 `json:"vote_average"`
|
||||
VoteCount int32 `json:"vote_count"`
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
// a ISO 639-1 value to display translated data
|
||||
Language string `json:"language"`
|
||||
// page to query
|
||||
Page int32 `json:"page"`
|
||||
// year of release
|
||||
PrimaryReleaseYear int32 `json:"primary_release_year"`
|
||||
// a text query to search
|
||||
Query string `json:"query"`
|
||||
// a ISO 3166-1 code to filter release dates.
|
||||
Region string `json:"region"`
|
||||
// year of making
|
||||
Year int32 `json:"year"`
|
||||
}
|
||||
|
||||
type SearchResponse struct {
|
||||
Page int32 `json:"page"`
|
||||
Results []MovieInfo `json:"results"`
|
||||
TotalPages int32 `json:"total_pages"`
|
||||
TotalResults int32 `json:"total_results"`
|
||||
}
|
71
services/mq/mq.go
Executable file
71
services/mq/mq.go
Executable file
@ -0,0 +1,71 @@
|
||||
package mq
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewMqService(token string) *MqService {
|
||||
return &MqService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type MqService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Publish a message. Specify a topic to group messages for a specific topic.
|
||||
func (t *MqService) Publish(request *PublishRequest) (*PublishResponse, error) {
|
||||
|
||||
rsp := &PublishResponse{}
|
||||
return rsp, t.client.Call("mq", "Publish", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Subscribe to messages for a given topic.
|
||||
func (t *MqService) Subscribe(request *SubscribeRequest) (*SubscribeResponseStream, error) {
|
||||
stream, err := t.client.Stream("mq", "Subscribe", request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SubscribeResponseStream{
|
||||
stream: stream,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
type SubscribeResponseStream struct {
|
||||
stream *client.Stream
|
||||
}
|
||||
|
||||
func (t *SubscribeResponseStream) Recv() (*SubscribeResponse, error) {
|
||||
var rsp SubscribeResponse
|
||||
if err := t.stream.Recv(&rsp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rsp, nil
|
||||
}
|
||||
|
||||
type PublishRequest struct {
|
||||
// The json message to publish
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// The topic to publish to
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type PublishResponse struct {
|
||||
}
|
||||
|
||||
type SubscribeRequest struct {
|
||||
// The topic to subscribe to
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
type SubscribeResponse struct {
|
||||
// The next json message on the topic
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// The topic subscribed to
|
||||
Topic string `json:"topic"`
|
||||
}
|
65
services/news/news.go
Executable file
65
services/news/news.go
Executable file
@ -0,0 +1,65 @@
|
||||
package news
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewNewsService(token string) *NewsService {
|
||||
return &NewsService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type NewsService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Get the latest news headlines
|
||||
func (t *NewsService) Headlines(request *HeadlinesRequest) (*HeadlinesResponse, error) {
|
||||
|
||||
rsp := &HeadlinesResponse{}
|
||||
return rsp, t.client.Call("news", "Headlines", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Article struct {
|
||||
// categories
|
||||
Categories []string `json:"categories"`
|
||||
// article description
|
||||
Description string `json:"description"`
|
||||
// article id
|
||||
Id string `json:"id"`
|
||||
// image url
|
||||
ImageUrl string `json:"image_url"`
|
||||
// related keywords
|
||||
Keywords string `json:"keywords"`
|
||||
// the article language
|
||||
Language string `json:"language"`
|
||||
// the locale
|
||||
Locale string `json:"locale"`
|
||||
// time it was published
|
||||
PublishedAt string `json:"published_at"`
|
||||
// first 60 characters of article body
|
||||
Snippet string `json:"snippet"`
|
||||
// source of news
|
||||
Source string `json:"source"`
|
||||
// article title
|
||||
Title string `json:"title"`
|
||||
// url of the article
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type HeadlinesRequest struct {
|
||||
// date published on in YYYY-MM-DD format
|
||||
Date string `json:"date"`
|
||||
// comma separated list of languages to retrieve in e.g en,es
|
||||
Language string `json:"language"`
|
||||
// comma separated list of countries to include e.g us,ca
|
||||
Locale string `json:"locale"`
|
||||
}
|
||||
|
||||
type HeadlinesResponse struct {
|
||||
Articles []Article `json:"articles"`
|
||||
}
|
186
services/nft/nft.go
Executable file
186
services/nft/nft.go
Executable file
@ -0,0 +1,186 @@
|
||||
package nft
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewNftService(token string) *NftService {
|
||||
return &NftService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type NftService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Return a list of assets
|
||||
func (t *NftService) Assets(request *AssetsRequest) (*AssetsResponse, error) {
|
||||
|
||||
rsp := &AssetsResponse{}
|
||||
return rsp, t.client.Call("nft", "Assets", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get a list of collections
|
||||
func (t *NftService) Collections(request *CollectionsRequest) (*CollectionsResponse, error) {
|
||||
|
||||
rsp := &CollectionsResponse{}
|
||||
return rsp, t.client.Call("nft", "Collections", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Create your own NFT (coming soon)
|
||||
func (t *NftService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("nft", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Asset struct {
|
||||
// associated collection
|
||||
Collection *Collection `json:"collection"`
|
||||
// asset contract
|
||||
Contract *Contract `json:"contract"`
|
||||
// Creator of the NFT
|
||||
Creator *User `json:"creator"`
|
||||
// related description
|
||||
Description string `json:"description"`
|
||||
// id of the asset
|
||||
Id int32 `json:"id"`
|
||||
// the image url
|
||||
ImageUrl string `json:"image_url"`
|
||||
// last time sold
|
||||
LastSale *Sale `json:"last_sale"`
|
||||
// listing date
|
||||
ListingDate string `json:"listing_date"`
|
||||
// name of the asset
|
||||
Name string `json:"name"`
|
||||
// Owner of the NFT
|
||||
Owner *User `json:"owner"`
|
||||
// the permalink
|
||||
Permalink string `json:"permalink"`
|
||||
// is it a presale
|
||||
Presale bool `json:"presale"`
|
||||
// number of sales
|
||||
Sales int32 `json:"sales"`
|
||||
// the token id
|
||||
TokenId string `json:"token_id"`
|
||||
}
|
||||
|
||||
type AssetsRequest struct {
|
||||
// limit to members of a collection by slug name (case sensitive)
|
||||
Collection string `json:"collection"`
|
||||
// limit returned assets
|
||||
Limit int32 `json:"limit"`
|
||||
// offset for pagination
|
||||
Offset int32 `json:"offset"`
|
||||
// order "asc" or "desc"
|
||||
Order string `json:"order"`
|
||||
// order by "sale_date", "sale_count", "sale_price", "total_price"
|
||||
OrderBy string `json:"order_by"`
|
||||
}
|
||||
|
||||
type AssetsResponse struct {
|
||||
// list of assets
|
||||
Assets []Asset `json:"assets"`
|
||||
}
|
||||
|
||||
type Collection struct {
|
||||
CreatedAt string `json:"created_at"`
|
||||
Description string `json:"description"`
|
||||
ImageUrl string `json:"image_url"`
|
||||
Name string `json:"name"`
|
||||
PayoutAddress string `json:"payout_address"`
|
||||
Slug string `json:"slug"`
|
||||
}
|
||||
|
||||
type CollectionsRequest struct {
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
type CollectionsResponse struct {
|
||||
Collections []Collection `json:"collections"`
|
||||
}
|
||||
|
||||
type Contract struct {
|
||||
// ethereum address
|
||||
Address string `json:"address"`
|
||||
// timestamp of creation
|
||||
CreatedAt string `json:"created_at"`
|
||||
// description of contract
|
||||
Description string `json:"description"`
|
||||
// name of contract
|
||||
Name string `json:"name"`
|
||||
// owner id
|
||||
Owner int32 `json:"owner"`
|
||||
// payout address
|
||||
PayoutAddress string `json:"payout_address"`
|
||||
// aka "ERC1155"
|
||||
Schema string `json:"schema"`
|
||||
// seller fees
|
||||
SellerFees string `json:"seller_fees"`
|
||||
// related symbol
|
||||
Symbol string `json:"symbol"`
|
||||
// type of contract e.g "semi-fungible"
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
// data if not image
|
||||
Data string `json:"data"`
|
||||
// description
|
||||
Description string `json:"description"`
|
||||
// image data
|
||||
Image string `json:"image"`
|
||||
// name of the NFT
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
Asset *Asset `json:"asset"`
|
||||
}
|
||||
|
||||
type Sale struct {
|
||||
AssetDecimals int32 `json:"asset_decimals"`
|
||||
AssetTokenId string `json:"asset_token_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
EventTimestamp string `json:"event_timestamp"`
|
||||
EventType string `json:"event_type"`
|
||||
PaymentToken *Token `json:"payment_token"`
|
||||
Quantity string `json:"quantity"`
|
||||
TotalPrice string `json:"total_price"`
|
||||
Transaction *Transaction `json:"transaction"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
Address string `json:"address"`
|
||||
Decimals int32 `json:"decimals"`
|
||||
EthPrice string `json:"eth_price"`
|
||||
Id int32 `json:"id"`
|
||||
ImageUrl string `json:"image_url"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
UsdPrice string `json:"usd_price"`
|
||||
}
|
||||
|
||||
type Transaction struct {
|
||||
BlockHash string `json:"block_hash"`
|
||||
BlockNumber string `json:"block_number"`
|
||||
FromAccount *User `json:"from_account"`
|
||||
Id int32 `json:"id"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
ToAccount *User `json:"to_account"`
|
||||
TransactionHash string `json:"transaction_hash"`
|
||||
TransactionIndex string `json:"transaction_index"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Address string `json:"address"`
|
||||
ProfileUrl string `json:"profile_url"`
|
||||
Username string `json:"username"`
|
||||
}
|
@ -18,38 +18,66 @@ type NotesService struct {
|
||||
|
||||
// Create a new note
|
||||
func (t *NotesService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("notes", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete a note
|
||||
func (t *NotesService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("notes", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Subscribe to notes events
|
||||
func (t *NotesService) Events(request *EventsRequest) (*EventsResponseStream, error) {
|
||||
stream, err := t.client.Stream("notes", "Events", request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &EventsResponseStream{
|
||||
stream: stream,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
type EventsResponseStream struct {
|
||||
stream *client.Stream
|
||||
}
|
||||
|
||||
func (t *EventsResponseStream) Recv() (*EventsResponse, error) {
|
||||
var rsp EventsResponse
|
||||
if err := t.stream.Recv(&rsp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rsp, nil
|
||||
}
|
||||
|
||||
// List all the notes
|
||||
func (t *NotesService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("notes", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read a note
|
||||
func (t *NotesService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("notes", "Read", request, rsp)
|
||||
}
|
||||
|
||||
// Specify the note to events
|
||||
func (t *NotesService) Subscribe(request *SubscribeRequest) (*SubscribeResponse, error) {
|
||||
rsp := &SubscribeResponse{}
|
||||
return rsp, t.client.Call("notes", "Subscribe", request, rsp)
|
||||
}
|
||||
|
||||
// Update a note
|
||||
func (t *NotesService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("notes", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
@ -73,6 +101,18 @@ type DeleteResponse struct {
|
||||
Note *Note `json:"note"`
|
||||
}
|
||||
|
||||
type EventsRequest struct {
|
||||
// optionally specify a note id
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type EventsResponse struct {
|
||||
// the event which occured; create, delete, update
|
||||
Event string `json:"event"`
|
||||
// the note which the operation occured on
|
||||
Note *Note `json:"note"`
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
}
|
||||
|
||||
@ -104,18 +144,6 @@ type ReadResponse struct {
|
||||
Note *Note `json:"note"`
|
||||
}
|
||||
|
||||
type SubscribeRequest struct {
|
||||
// optionally specify a note id
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
type SubscribeResponse struct {
|
||||
// the event which occured; created, deleted, updated
|
||||
Event string `json:"event"`
|
||||
// the note which the operation occured on
|
||||
Note *Note `json:"note"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
Note *Note `json:"note"`
|
||||
}
|
||||
|
@ -18,14 +18,18 @@ type OtpService struct {
|
||||
|
||||
// Generate an OTP (one time pass) code
|
||||
func (t *OtpService) Generate(request *GenerateRequest) (*GenerateResponse, error) {
|
||||
|
||||
rsp := &GenerateResponse{}
|
||||
return rsp, t.client.Call("otp", "Generate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Validate the OTP code
|
||||
func (t *OtpService) Validate(request *ValidateRequest) (*ValidateResponse, error) {
|
||||
|
||||
rsp := &ValidateResponse{}
|
||||
return rsp, t.client.Call("otp", "Validate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type GenerateRequest struct {
|
||||
|
@ -18,20 +18,26 @@ type PostcodeService struct {
|
||||
|
||||
// Lookup a postcode to retrieve the related region, county, etc
|
||||
func (t *PostcodeService) Lookup(request *LookupRequest) (*LookupResponse, error) {
|
||||
|
||||
rsp := &LookupResponse{}
|
||||
return rsp, t.client.Call("postcode", "Lookup", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Return a random postcode and its related info
|
||||
func (t *PostcodeService) Random(request *RandomRequest) (*RandomResponse, error) {
|
||||
|
||||
rsp := &RandomResponse{}
|
||||
return rsp, t.client.Call("postcode", "Random", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Validate a postcode.
|
||||
func (t *PostcodeService) Validate(request *ValidateRequest) (*ValidateResponse, error) {
|
||||
|
||||
rsp := &ValidateResponse{}
|
||||
return rsp, t.client.Call("postcode", "Validate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type LookupRequest struct {
|
||||
|
@ -18,8 +18,10 @@ type PrayerService struct {
|
||||
|
||||
// Get the prayer (salah) times for a location on a given date
|
||||
func (t *PrayerService) Times(request *TimesRequest) (*TimesResponse, error) {
|
||||
|
||||
rsp := &TimesResponse{}
|
||||
return rsp, t.client.Call("prayer", "Times", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type PrayerTime struct {
|
||||
|
@ -18,8 +18,10 @@ type QrService struct {
|
||||
|
||||
// Generate a QR code with a specific text and size
|
||||
func (t *QrService) Generate(request *GenerateRequest) (*GenerateResponse, error) {
|
||||
|
||||
rsp := &GenerateResponse{}
|
||||
return rsp, t.client.Call("qr", "Generate", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type GenerateRequest struct {
|
||||
|
@ -18,35 +18,43 @@ type QuranService struct {
|
||||
|
||||
// List the Chapters (surahs) of the Quran
|
||||
func (t *QuranService) Chapters(request *ChaptersRequest) (*ChaptersResponse, error) {
|
||||
|
||||
rsp := &ChaptersResponse{}
|
||||
return rsp, t.client.Call("quran", "Chapters", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Search the Quran for any form of query or questions
|
||||
func (t *QuranService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("quran", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get a summary for a given chapter (surah)
|
||||
func (t *QuranService) Summary(request *SummaryRequest) (*SummaryResponse, error) {
|
||||
|
||||
rsp := &SummaryResponse{}
|
||||
return rsp, t.client.Call("quran", "Summary", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Lookup the verses (ayahs) for a chapter including
|
||||
// translation, interpretation and breakdown by individual
|
||||
// words.
|
||||
func (t *QuranService) Verses(request *VersesRequest) (*VersesResponse, error) {
|
||||
|
||||
rsp := &VersesResponse{}
|
||||
return rsp, t.client.Call("quran", "Verses", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Chapter struct {
|
||||
// The arabic name of the chapter
|
||||
ArabicName string `json:"arabicName"`
|
||||
ArabicName string `json:"arabic_name"`
|
||||
// The complex name of the chapter
|
||||
ComplexName string `json:"complexName"`
|
||||
ComplexName string `json:"complex_name"`
|
||||
// The id of the chapter as a number e.g 1
|
||||
Id int32 `json:"id"`
|
||||
// The simple name of the chapter
|
||||
@ -54,13 +62,13 @@ type Chapter struct {
|
||||
// The pages from and to e.g 1, 1
|
||||
Pages []int32 `json:"pages"`
|
||||
// Should the chapter start with bismillah
|
||||
PrefixBismillah bool `json:"prefixBismillah"`
|
||||
PrefixBismillah bool `json:"prefix_bismillah"`
|
||||
// The order in which it was revealed
|
||||
RevelationOrder int32 `json:"revelationOrder"`
|
||||
RevelationOrder int32 `json:"revelation_order"`
|
||||
// The place of revelation
|
||||
RevelationPlace string `json:"revelationPlace"`
|
||||
RevelationPlace string `json:"revelation_place"`
|
||||
// The translated name
|
||||
TranslatedName string `json:"translatedName"`
|
||||
TranslatedName string `json:"translated_name"`
|
||||
// The number of verses in the chapter
|
||||
Verses int32 `json:"verses"`
|
||||
}
|
||||
@ -89,9 +97,9 @@ type Result struct {
|
||||
// The related translations to the text
|
||||
Translations []Translation `json:"translations"`
|
||||
// The unique verse id across the Quran
|
||||
VerseId int32 `json:"verseId"`
|
||||
VerseId int32 `json:"verse_id"`
|
||||
// The verse key e.g 1:1
|
||||
VerseKey string `json:"verseKey"`
|
||||
VerseKey string `json:"verse_key"`
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
@ -113,9 +121,9 @@ type SearchResponse struct {
|
||||
// The results for the query
|
||||
Results []Result `json:"results"`
|
||||
// The total pages
|
||||
TotalPages int32 `json:"totalPages"`
|
||||
TotalPages int32 `json:"total_pages"`
|
||||
// The total results returned
|
||||
TotalResults int32 `json:"totalResults"`
|
||||
TotalResults int32 `json:"total_results"`
|
||||
}
|
||||
|
||||
type SummaryRequest struct {
|
||||
@ -159,7 +167,7 @@ type Verse struct {
|
||||
// The arabic text for this verse
|
||||
Text string `json:"text"`
|
||||
// The basic translation of the verse
|
||||
TranslatedText string `json:"translatedText"`
|
||||
TranslatedText string `json:"translated_text"`
|
||||
// The alternative translations for the verse
|
||||
Translations []Translation `json:"translations"`
|
||||
// The phonetic transliteration from arabic
|
||||
@ -191,14 +199,14 @@ type VersesResponse struct {
|
||||
// The page requested
|
||||
Page int32 `json:"page"`
|
||||
// The total pages
|
||||
TotalPages int32 `json:"totalPages"`
|
||||
TotalPages int32 `json:"total_pages"`
|
||||
// The verses on the page
|
||||
Verses []Verse `json:"verses"`
|
||||
}
|
||||
|
||||
type Word struct {
|
||||
// The character type e.g word, end
|
||||
CharType string `json:"charType"`
|
||||
CharType string `json:"char_type"`
|
||||
// The QCF v2 font code
|
||||
Code string `json:"code"`
|
||||
// The id of the word within the verse
|
||||
|
@ -18,20 +18,26 @@ type RoutingService struct {
|
||||
|
||||
// Turn by turn directions from a start point to an end point including maneuvers and bearings
|
||||
func (t *RoutingService) Directions(request *DirectionsRequest) (*DirectionsResponse, error) {
|
||||
|
||||
rsp := &DirectionsResponse{}
|
||||
return rsp, t.client.Call("routing", "Directions", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the eta for a route from origin to destination. The eta is an estimated time based on car routes
|
||||
func (t *RoutingService) Eta(request *EtaRequest) (*EtaResponse, error) {
|
||||
|
||||
rsp := &EtaResponse{}
|
||||
return rsp, t.client.Call("routing", "Eta", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Retrieve a route as a simple list of gps points along with total distance and estimated duration
|
||||
func (t *RoutingService) Route(request *RouteRequest) (*RouteResponse, error) {
|
||||
|
||||
rsp := &RouteResponse{}
|
||||
return rsp, t.client.Call("routing", "Route", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Direction struct {
|
||||
@ -92,8 +98,8 @@ type Intersection struct {
|
||||
|
||||
type Maneuver struct {
|
||||
Action string `json:"action"`
|
||||
BearingAfter float64 `json:"bearingAfter"`
|
||||
BearingBefore float64 `json:"bearingBefore"`
|
||||
BearingAfter float64 `json:"bearing_after"`
|
||||
BearingBefore float64 `json:"bearing_before"`
|
||||
Direction string `json:"direction"`
|
||||
Location *Point `json:"location"`
|
||||
}
|
||||
|
@ -18,26 +18,34 @@ type RssService struct {
|
||||
|
||||
// Add a new RSS feed with a name, url, and category
|
||||
func (t *RssService) Add(request *AddRequest) (*AddResponse, error) {
|
||||
|
||||
rsp := &AddResponse{}
|
||||
return rsp, t.client.Call("rss", "Add", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get an RSS feed by name. If no name is given, all feeds are returned. Default limit is 25 entries.
|
||||
func (t *RssService) Feed(request *FeedRequest) (*FeedResponse, error) {
|
||||
|
||||
rsp := &FeedResponse{}
|
||||
return rsp, t.client.Call("rss", "Feed", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List the saved RSS fields
|
||||
func (t *RssService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("rss", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Remove an RSS feed by name
|
||||
func (t *RssService) Remove(request *RemoveRequest) (*RemoveResponse, error) {
|
||||
|
||||
rsp := &RemoveResponse{}
|
||||
return rsp, t.client.Call("rss", "Remove", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type AddRequest struct {
|
||||
|
35
services/search/search.go
Executable file
35
services/search/search.go
Executable file
@ -0,0 +1,35 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewSearchService(token string) *SearchService {
|
||||
return &SearchService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type SearchService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Vote to have the Search api launched faster!
|
||||
func (t *SearchService) Vote(request *VoteRequest) (*VoteResponse, error) {
|
||||
|
||||
rsp := &VoteResponse{}
|
||||
return rsp, t.client.Call("search", "Vote", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type VoteRequest struct {
|
||||
// optional message
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type VoteResponse struct {
|
||||
// response message
|
||||
Message string `json:"message"`
|
||||
}
|
@ -18,8 +18,10 @@ type SentimentService struct {
|
||||
|
||||
// Analyze and score a piece of text
|
||||
func (t *SentimentService) Analyze(request *AnalyzeRequest) (*AnalyzeResponse, error) {
|
||||
|
||||
rsp := &AnalyzeResponse{}
|
||||
return rsp, t.client.Call("sentiment", "Analyze", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type AnalyzeRequest struct {
|
||||
|
@ -18,8 +18,10 @@ type SmsService struct {
|
||||
|
||||
// Send an SMS.
|
||||
func (t *SmsService) Send(request *SendRequest) (*SendResponse, error) {
|
||||
|
||||
rsp := &SendResponse{}
|
||||
return rsp, t.client.Call("sms", "Send", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type SendRequest struct {
|
||||
|
202
services/space/space.go
Executable file
202
services/space/space.go
Executable file
@ -0,0 +1,202 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewSpaceService(token string) *SpaceService {
|
||||
return &SpaceService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type SpaceService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Create an object. Returns error if object with this name already exists. Max object size of 10MB, see Upload endpoint for larger objects. If you want to update an existing object use the `Update` endpoint
|
||||
func (t *SpaceService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("space", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete an object from space
|
||||
func (t *SpaceService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("space", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Download an object via a presigned url
|
||||
func (t *SpaceService) Download(request *DownloadRequest) (*DownloadResponse, error) {
|
||||
|
||||
rsp := &DownloadResponse{}
|
||||
return rsp, t.client.Call("space", "Download", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Retrieve meta information about an object
|
||||
func (t *SpaceService) Head(request *HeadRequest) (*HeadResponse, error) {
|
||||
|
||||
rsp := &HeadResponse{}
|
||||
return rsp, t.client.Call("space", "Head", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List the objects in space
|
||||
func (t *SpaceService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("space", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read an object in space
|
||||
func (t *SpaceService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("space", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update an object. If an object with this name does not exist, creates a new one.
|
||||
func (t *SpaceService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("space", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Upload a large object (> 10MB). Returns a time limited presigned URL to be used for uploading the object
|
||||
func (t *SpaceService) Upload(request *UploadRequest) (*UploadResponse, error) {
|
||||
|
||||
rsp := &UploadResponse{}
|
||||
return rsp, t.client.Call("space", "Upload", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
// The name of the object. Use forward slash delimiter to implement a nested directory-like structure e.g. images/foo.jpg
|
||||
Name string `json:"name"`
|
||||
// The contents of the object. Either base64 encoded if sending request as application/json or raw bytes if using multipart/form-data format
|
||||
Object string `json:"object"`
|
||||
// Who can see this object? "public" or "private", defaults to "private"
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
// A public URL to access the object if visibility is "public"
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
// Name of the object
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type DownloadRequest struct {
|
||||
// name of object
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DownloadResponse struct {
|
||||
// presigned url
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type HeadObject struct {
|
||||
// when was this created
|
||||
Created string `json:"created"`
|
||||
// when was this last modified
|
||||
Modified string `json:"modified"`
|
||||
Name string `json:"name"`
|
||||
// URL to access the object if it is public
|
||||
Url string `json:"url"`
|
||||
// is this public or private
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type HeadRequest struct {
|
||||
// name of the object
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type HeadResponse struct {
|
||||
Object *HeadObject `json:"object"`
|
||||
}
|
||||
|
||||
type ListObject struct {
|
||||
Created string `json:"created"`
|
||||
// when was this last modified
|
||||
Modified string `json:"modified"`
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
// optional prefix for the name e.g. to return all the objects in the images directory pass images/
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
Objects []ListObject `json:"objects"`
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
// when was this created
|
||||
Created string `json:"created"`
|
||||
// the data within the object
|
||||
Data string `json:"data"`
|
||||
// when was this last modified
|
||||
Modified string `json:"modified"`
|
||||
// name of object
|
||||
Name string `json:"name"`
|
||||
// URL to access the object if it is public
|
||||
Url string `json:"url"`
|
||||
// is this public or private
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
// name of the object
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ReadResponse struct {
|
||||
// The object itself
|
||||
Object *Object `json:"object"`
|
||||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
// The name of the object. Use forward slash delimiter to implement a nested directory-like structure e.g. images/foo.jpg
|
||||
Name string `json:"name"`
|
||||
// The contents of the object. Either base64 encoded if sending request as application/json or raw bytes if using multipart/form-data format
|
||||
Object string `json:"object"`
|
||||
// Who can see this object? "public" or "private", defaults to "private"
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type UpdateResponse struct {
|
||||
// A public URL to access the object if visibility is "public"
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type UploadRequest struct {
|
||||
Name string `json:"name"`
|
||||
// is this object public or private
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
|
||||
type UploadResponse struct {
|
||||
// a presigned url to be used for uploading. To use the URL call it with HTTP PUT and pass the object as the request data
|
||||
Url string `json:"url"`
|
||||
}
|
49
services/spam/spam.go
Executable file
49
services/spam/spam.go
Executable file
@ -0,0 +1,49 @@
|
||||
package spam
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewSpamService(token string) *SpamService {
|
||||
return &SpamService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type SpamService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Check whether an email is likely to be spam based on its attributes
|
||||
func (t *SpamService) Classify(request *ClassifyRequest) (*ClassifyResponse, error) {
|
||||
|
||||
rsp := &ClassifyResponse{}
|
||||
return rsp, t.client.Call("spam", "Classify", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type ClassifyRequest struct {
|
||||
// The raw body of the email including headers etc per RFC 822. Alternatively, use the other parameters to correctly format the message
|
||||
EmailBody string `json:"email_body"`
|
||||
// The email address it has been sent from
|
||||
From string `json:"from"`
|
||||
// the HTML version of the email body
|
||||
HtmlBody string `json:"html_body"`
|
||||
// The subject of the email
|
||||
Subject string `json:"subject"`
|
||||
// the plain text version of the email body
|
||||
TextBody string `json:"text_body"`
|
||||
// The email address it is being sent to
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
type ClassifyResponse struct {
|
||||
// The rules that have contributed to this score
|
||||
Details []string `json:"details"`
|
||||
// Is it spam? Returns true if its score is > 5
|
||||
IsSpam bool `json:"is_spam"`
|
||||
// The score evaluated for this email. A higher number means it is more likely to be spam
|
||||
Score float64 `json:"score"`
|
||||
}
|
@ -18,26 +18,34 @@ type StockService struct {
|
||||
|
||||
// Get the historic open-close for a given day
|
||||
func (t *StockService) History(request *HistoryRequest) (*HistoryResponse, error) {
|
||||
|
||||
rsp := &HistoryResponse{}
|
||||
return rsp, t.client.Call("stock", "History", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the historic order book and each trade by timestamp
|
||||
func (t *StockService) OrderBook(request *OrderBookRequest) (*OrderBookResponse, error) {
|
||||
|
||||
rsp := &OrderBookResponse{}
|
||||
return rsp, t.client.Call("stock", "OrderBook", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the last price for a given stock ticker
|
||||
func (t *StockService) Price(request *PriceRequest) (*PriceResponse, error) {
|
||||
|
||||
rsp := &PriceResponse{}
|
||||
return rsp, t.client.Call("stock", "Price", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the last quote for the stock
|
||||
func (t *StockService) Quote(request *QuoteRequest) (*QuoteResponse, error) {
|
||||
|
||||
rsp := &QuoteResponse{}
|
||||
return rsp, t.client.Call("stock", "Quote", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type HistoryRequest struct {
|
||||
@ -66,13 +74,13 @@ type HistoryResponse struct {
|
||||
|
||||
type Order struct {
|
||||
// the asking price
|
||||
AskPrice float64 `json:"askPrice"`
|
||||
AskPrice float64 `json:"ask_price"`
|
||||
// the ask size
|
||||
AskSize int32 `json:"askSize"`
|
||||
AskSize int32 `json:"ask_size"`
|
||||
// the bidding price
|
||||
BidPrice float64 `json:"bidPrice"`
|
||||
BidPrice float64 `json:"bid_price"`
|
||||
// the bid size
|
||||
BidSize int32 `json:"bidSize"`
|
||||
BidSize int32 `json:"bid_size"`
|
||||
// the UTC timestamp of the quote
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
@ -118,13 +126,13 @@ type QuoteRequest struct {
|
||||
|
||||
type QuoteResponse struct {
|
||||
// the asking price
|
||||
AskPrice float64 `json:"askPrice"`
|
||||
AskPrice float64 `json:"ask_price"`
|
||||
// the ask size
|
||||
AskSize int32 `json:"askSize"`
|
||||
AskSize int32 `json:"ask_size"`
|
||||
// the bidding price
|
||||
BidPrice float64 `json:"bidPrice"`
|
||||
BidPrice float64 `json:"bid_price"`
|
||||
// the bid size
|
||||
BidSize int32 `json:"bidSize"`
|
||||
BidSize int32 `json:"bid_size"`
|
||||
// the stock symbol
|
||||
Symbol string `json:"symbol"`
|
||||
// the UTC timestamp of the quote
|
||||
|
@ -16,36 +16,98 @@ type StreamService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Publish a message to the stream. Specify a topic to group messages for a specific topic.
|
||||
func (t *StreamService) Publish(request *PublishRequest) (*PublishResponse, error) {
|
||||
rsp := &PublishResponse{}
|
||||
return rsp, t.client.Call("stream", "Publish", request, rsp)
|
||||
// Create a channel with a given name and description. Channels are created automatically but
|
||||
// this allows you to specify a description that's persisted for the lifetime of the channel.
|
||||
func (t *StreamService) CreateChannel(request *CreateChannelRequest) (*CreateChannelResponse, error) {
|
||||
|
||||
rsp := &CreateChannelResponse{}
|
||||
return rsp, t.client.Call("stream", "CreateChannel", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Subscribe to messages for a given topic.
|
||||
func (t *StreamService) Subscribe(request *SubscribeRequest) (*SubscribeResponse, error) {
|
||||
rsp := &SubscribeResponse{}
|
||||
return rsp, t.client.Call("stream", "Subscribe", request, rsp)
|
||||
// List all the active channels
|
||||
func (t *StreamService) ListChannels(request *ListChannelsRequest) (*ListChannelsResponse, error) {
|
||||
|
||||
rsp := &ListChannelsResponse{}
|
||||
return rsp, t.client.Call("stream", "ListChannels", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type PublishRequest struct {
|
||||
// The json message to publish
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// The topic to publish to
|
||||
Topic string `json:"topic"`
|
||||
// List messages for a given channel
|
||||
func (t *StreamService) ListMessages(request *ListMessagesRequest) (*ListMessagesResponse, error) {
|
||||
|
||||
rsp := &ListMessagesResponse{}
|
||||
return rsp, t.client.Call("stream", "ListMessages", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type PublishResponse struct {
|
||||
// Send a message to the stream.
|
||||
func (t *StreamService) SendMessage(request *SendMessageRequest) (*SendMessageResponse, error) {
|
||||
|
||||
rsp := &SendMessageResponse{}
|
||||
return rsp, t.client.Call("stream", "SendMessage", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type SubscribeRequest struct {
|
||||
// The topic to subscribe to
|
||||
Topic string `json:"topic"`
|
||||
type Channel struct {
|
||||
// description for the channel
|
||||
Description string `json:"description"`
|
||||
// last activity time
|
||||
LastActive string `json:"last_active"`
|
||||
// name of the channel
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type SubscribeResponse struct {
|
||||
// The next json message on the topic
|
||||
Message map[string]interface{} `json:"message"`
|
||||
// The topic subscribed to
|
||||
Topic string `json:"topic"`
|
||||
type CreateChannelRequest struct {
|
||||
// description for the channel
|
||||
Description string `json:"description"`
|
||||
// name of the channel
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CreateChannelResponse struct {
|
||||
}
|
||||
|
||||
type ListChannelsRequest struct {
|
||||
}
|
||||
|
||||
type ListChannelsResponse struct {
|
||||
Channels []Channel `json:"channels"`
|
||||
}
|
||||
|
||||
type ListMessagesRequest struct {
|
||||
// The channel to subscribe to
|
||||
Channel string `json:"channel"`
|
||||
// number of message to return
|
||||
Limit int32 `json:"limit"`
|
||||
}
|
||||
|
||||
type ListMessagesResponse struct {
|
||||
// The channel subscribed to
|
||||
Channel string `json:"channel"`
|
||||
// Messages are chronological order
|
||||
Messages []Message `json:"messages"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
// the channel name
|
||||
Channel string `json:"channel"`
|
||||
// id of the message
|
||||
Id string `json:"id"`
|
||||
// the associated metadata
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
// text of the message
|
||||
Text string `json:"text"`
|
||||
// time of message creation
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
type SendMessageRequest struct {
|
||||
// The channel to send to
|
||||
Channel string `json:"channel"`
|
||||
// The message text to send
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type SendMessageResponse struct {
|
||||
}
|
||||
|
@ -19,33 +19,41 @@ type SunnahService struct {
|
||||
// Get a list of books from within a collection. A book can contain many chapters
|
||||
// each with its own hadiths.
|
||||
func (t *SunnahService) Books(request *BooksRequest) (*BooksResponse, error) {
|
||||
|
||||
rsp := &BooksResponse{}
|
||||
return rsp, t.client.Call("sunnah", "Books", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get all the chapters of a given book within a collection.
|
||||
func (t *SunnahService) Chapters(request *ChaptersRequest) (*ChaptersResponse, error) {
|
||||
|
||||
rsp := &ChaptersResponse{}
|
||||
return rsp, t.client.Call("sunnah", "Chapters", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get a list of available collections. A collection is
|
||||
// a compilation of hadiths collected and written by an author.
|
||||
func (t *SunnahService) Collections(request *CollectionsRequest) (*CollectionsResponse, error) {
|
||||
|
||||
rsp := &CollectionsResponse{}
|
||||
return rsp, t.client.Call("sunnah", "Collections", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Hadiths returns a list of hadiths and their corresponding text for a
|
||||
// given book within a collection.
|
||||
func (t *SunnahService) Hadiths(request *HadithsRequest) (*HadithsResponse, error) {
|
||||
|
||||
rsp := &HadithsResponse{}
|
||||
return rsp, t.client.Call("sunnah", "Hadiths", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Book struct {
|
||||
// arabic name of the book
|
||||
ArabicName string `json:"arabicName"`
|
||||
ArabicName string `json:"arabic_name"`
|
||||
// number of hadiths in the book
|
||||
Hadiths int32 `json:"hadiths"`
|
||||
// number of the book e.g 1
|
||||
@ -78,7 +86,7 @@ type BooksResponse struct {
|
||||
|
||||
type Chapter struct {
|
||||
// arabic title
|
||||
ArabicTitle string `json:"arabicTitle"`
|
||||
ArabicTitle string `json:"arabic_title"`
|
||||
// the book number
|
||||
Book int32 `json:"book"`
|
||||
// the chapter id e.g 1
|
||||
@ -117,7 +125,7 @@ type ChaptersResponse struct {
|
||||
|
||||
type Collection struct {
|
||||
// Arabic title if available
|
||||
ArabicTitle string `json:"arabicTitle"`
|
||||
ArabicTitle string `json:"arabic_title"`
|
||||
// Total hadiths in the collection
|
||||
Hadiths int32 `json:"hadiths"`
|
||||
// Name of the collection e.g bukhari
|
||||
@ -141,15 +149,15 @@ type CollectionsResponse struct {
|
||||
|
||||
type Hadith struct {
|
||||
// the arabic chapter title
|
||||
ArabicChapterTitle string `json:"arabicChapterTitle"`
|
||||
ArabicChapterTitle string `json:"arabic_chapter_title"`
|
||||
// the arabic text
|
||||
ArabicText string `json:"arabicText"`
|
||||
ArabicText string `json:"arabic_text"`
|
||||
// the chapter id
|
||||
Chapter int32 `json:"chapter"`
|
||||
// the chapter key
|
||||
ChapterKey string `json:"chapterKey"`
|
||||
ChapterKey string `json:"chapter_key"`
|
||||
// the chapter title
|
||||
ChapterTitle string `json:"chapterTitle"`
|
||||
ChapterTitle string `json:"chapter_title"`
|
||||
// hadith id
|
||||
Id int32 `json:"id"`
|
||||
// hadith text
|
||||
|
@ -18,8 +18,10 @@ type ThumbnailService struct {
|
||||
|
||||
// Create a thumbnail screenshot by passing in a url, height and width
|
||||
func (t *ThumbnailService) Screenshot(request *ScreenshotRequest) (*ScreenshotResponse, error) {
|
||||
|
||||
rsp := &ScreenshotResponse{}
|
||||
return rsp, t.client.Call("thumbnail", "Screenshot", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type ScreenshotRequest struct {
|
||||
@ -31,5 +33,5 @@ type ScreenshotRequest struct {
|
||||
}
|
||||
|
||||
type ScreenshotResponse struct {
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
ImageUrl string `json:"imageURL"`
|
||||
}
|
||||
|
@ -18,14 +18,18 @@ type TimeService struct {
|
||||
|
||||
// Get the current time
|
||||
func (t *TimeService) Now(request *NowRequest) (*NowResponse, error) {
|
||||
|
||||
rsp := &NowResponse{}
|
||||
return rsp, t.client.Call("time", "Now", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the timezone info for a specific location
|
||||
func (t *TimeService) Zone(request *ZoneRequest) (*ZoneResponse, error) {
|
||||
|
||||
rsp := &ZoneResponse{}
|
||||
return rsp, t.client.Call("time", "Zone", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type NowRequest struct {
|
||||
|
55
services/translate/translate.go
Executable file
55
services/translate/translate.go
Executable file
@ -0,0 +1,55 @@
|
||||
package translate
|
||||
|
||||
import (
|
||||
"go.m3o.com/client"
|
||||
)
|
||||
|
||||
func NewTranslateService(token string) *TranslateService {
|
||||
return &TranslateService{
|
||||
client: client.NewClient(&client.Options{
|
||||
Token: token,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
type TranslateService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Basic text translation
|
||||
func (t *TranslateService) Text(request *TextRequest) (*TextResponse, error) {
|
||||
|
||||
rsp := &TextResponse{}
|
||||
return rsp, t.client.Call("translate", "Text", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type TextRequest struct {
|
||||
// The contents to be translated
|
||||
Content string `json:"content"`
|
||||
// The string format, `text` or `html`
|
||||
Format string `json:"format"`
|
||||
// The model to use for translation, `nmt` or `base`,
|
||||
// See https://cloud.google.com/translate/docs/advanced/translating-text-v3#comparing-models for more information
|
||||
Model string `json:"model"`
|
||||
// Source language, format in ISO-639-1 codes
|
||||
// See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for more information
|
||||
Source string `json:"source"`
|
||||
// Target language, format in ISO-639-1 codes
|
||||
// See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for more information
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
type TextResponse struct {
|
||||
// The translated text
|
||||
Translation *Translation `json:"translation"`
|
||||
}
|
||||
|
||||
type Translation struct {
|
||||
// The model used in translation
|
||||
Model string `json:"model"`
|
||||
// The source of the query string
|
||||
Source string `json:"source"`
|
||||
// The translation result
|
||||
Text string `json:"text"`
|
||||
}
|
@ -18,31 +18,39 @@ type TwitterService struct {
|
||||
|
||||
// Search for tweets with a simple query
|
||||
func (t *TwitterService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("twitter", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the timeline for a given user
|
||||
func (t *TwitterService) Timeline(request *TimelineRequest) (*TimelineResponse, error) {
|
||||
|
||||
rsp := &TimelineResponse{}
|
||||
return rsp, t.client.Call("twitter", "Timeline", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the current global trending topics
|
||||
func (t *TwitterService) Trends(request *TrendsRequest) (*TrendsResponse, error) {
|
||||
|
||||
rsp := &TrendsResponse{}
|
||||
return rsp, t.client.Call("twitter", "Trends", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get a user's twitter profile
|
||||
func (t *TwitterService) User(request *UserRequest) (*UserResponse, error) {
|
||||
|
||||
rsp := &UserResponse{}
|
||||
return rsp, t.client.Call("twitter", "User", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
// the account creation date
|
||||
CreatedAt string `json:"createdAt"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
// the user description
|
||||
Description string `json:"description"`
|
||||
// the follower count
|
||||
@ -50,7 +58,7 @@ type Profile struct {
|
||||
// the user id
|
||||
Id int64 `json:"id,string"`
|
||||
// The user's profile picture
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
ImageUrl string `json:"image_url"`
|
||||
// the user's location
|
||||
Location string `json:"location"`
|
||||
// display name of the user
|
||||
@ -91,7 +99,7 @@ type Trend struct {
|
||||
// name of the trend
|
||||
Name string `json:"name"`
|
||||
// the volume of tweets in last 24 hours
|
||||
TweetVolume int64 `json:"tweetVolume,string"`
|
||||
TweetVolume int64 `json:"tweet_volume,string"`
|
||||
// the twitter url
|
||||
Url string `json:"url"`
|
||||
}
|
||||
@ -106,13 +114,13 @@ type TrendsResponse struct {
|
||||
|
||||
type Tweet struct {
|
||||
// time of tweet
|
||||
CreatedAt string `json:"createdAt"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
// number of times favourited
|
||||
FavouritedCount int64 `json:"favouritedCount,string"`
|
||||
FavouritedCount int64 `json:"favourited_count,string"`
|
||||
// id of the tweet
|
||||
Id int64 `json:"id,string"`
|
||||
// number of times retweeted
|
||||
RetweetedCount int64 `json:"retweetedCount,string"`
|
||||
RetweetedCount int64 `json:"retweeted_count,string"`
|
||||
// text of the tweet
|
||||
Text string `json:"text"`
|
||||
// username of the person who tweeted
|
||||
|
@ -16,27 +16,33 @@ type UrlService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// List information on all the shortened URLs that you have created
|
||||
// List all the shortened URLs
|
||||
func (t *UrlService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("url", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Proxy returns the destination URL of a short URL.
|
||||
func (t *UrlService) Proxy(request *ProxyRequest) (*ProxyResponse, error) {
|
||||
|
||||
rsp := &ProxyResponse{}
|
||||
return rsp, t.client.Call("url", "Proxy", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Shortens a destination URL and returns a full short URL.
|
||||
// Shorten a long URL
|
||||
func (t *UrlService) Shorten(request *ShortenRequest) (*ShortenResponse, error) {
|
||||
|
||||
rsp := &ShortenResponse{}
|
||||
return rsp, t.client.Call("url", "Shorten", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
// filter by short URL, optional
|
||||
ShortUrl string `json:"shortUrl"`
|
||||
ShortUrl string `json:"shortURL"`
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
@ -46,28 +52,28 @@ type ListResponse struct {
|
||||
type ProxyRequest struct {
|
||||
// short url ID, without the domain, eg. if your short URL is
|
||||
// `m3o.one/u/someshorturlid` then pass in `someshorturlid`
|
||||
ShortUrl string `json:"shortUrl"`
|
||||
ShortUrl string `json:"shortURL"`
|
||||
}
|
||||
|
||||
type ProxyResponse struct {
|
||||
DestinationUrl string `json:"destinationUrl"`
|
||||
DestinationUrl string `json:"destinationURL"`
|
||||
}
|
||||
|
||||
type ShortenRequest struct {
|
||||
DestinationUrl string `json:"destinationUrl"`
|
||||
// the url to shorten
|
||||
DestinationUrl string `json:"destinationURL"`
|
||||
}
|
||||
|
||||
type ShortenResponse struct {
|
||||
ShortUrl string `json:"shortUrl"`
|
||||
// the shortened url
|
||||
ShortUrl string `json:"shortURL"`
|
||||
}
|
||||
|
||||
type URLPair struct {
|
||||
Created int64 `json:"created,string"`
|
||||
DestinationUrl string `json:"destinationUrl"`
|
||||
// HitCount keeps track many times the short URL has been resolved.
|
||||
// Hitcount only gets saved to disk (database) after every 10th hit, so
|
||||
// its not intended to be 100% accurate, more like an almost correct estimate.
|
||||
HitCount int64 `json:"hitCount,string"`
|
||||
Owner string `json:"owner"`
|
||||
ShortUrl string `json:"shortUrl"`
|
||||
// time of creation
|
||||
Created string `json:"created"`
|
||||
// destination url
|
||||
DestinationUrl string `json:"destinationURL"`
|
||||
// shortened url
|
||||
ShortUrl string `json:"shortURL"`
|
||||
}
|
||||
|
@ -18,69 +18,133 @@ type UserService struct {
|
||||
|
||||
// Create a new user account. The email address and username for the account must be unique.
|
||||
func (t *UserService) Create(request *CreateRequest) (*CreateResponse, error) {
|
||||
|
||||
rsp := &CreateResponse{}
|
||||
return rsp, t.client.Call("user", "Create", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Delete an account by id
|
||||
func (t *UserService) Delete(request *DeleteRequest) (*DeleteResponse, error) {
|
||||
|
||||
rsp := &DeleteResponse{}
|
||||
return rsp, t.client.Call("user", "Delete", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// List all users. Returns a paged list of results
|
||||
func (t *UserService) List(request *ListRequest) (*ListResponse, error) {
|
||||
|
||||
rsp := &ListResponse{}
|
||||
return rsp, t.client.Call("user", "List", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Login using username or email. The response will return a new session for successful login,
|
||||
// 401 in the case of login failure and 500 for any other error
|
||||
func (t *UserService) Login(request *LoginRequest) (*LoginResponse, error) {
|
||||
|
||||
rsp := &LoginResponse{}
|
||||
return rsp, t.client.Call("user", "Login", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Logout a user account
|
||||
func (t *UserService) Logout(request *LogoutRequest) (*LogoutResponse, error) {
|
||||
|
||||
rsp := &LogoutResponse{}
|
||||
return rsp, t.client.Call("user", "Logout", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read an account by id, username or email. Only one need to be specified.
|
||||
func (t *UserService) Read(request *ReadRequest) (*ReadResponse, error) {
|
||||
|
||||
rsp := &ReadResponse{}
|
||||
return rsp, t.client.Call("user", "Read", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Read a session by the session id. In the event it has expired or is not found and error is returned.
|
||||
func (t *UserService) ReadSession(request *ReadSessionRequest) (*ReadSessionResponse, error) {
|
||||
|
||||
rsp := &ReadSessionResponse{}
|
||||
return rsp, t.client.Call("user", "ReadSession", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Reset password with the code sent by the "SendPasswordResetEmail" endoint.
|
||||
func (t *UserService) ResetPassword(request *ResetPasswordRequest) (*ResetPasswordResponse, error) {
|
||||
|
||||
rsp := &ResetPasswordResponse{}
|
||||
return rsp, t.client.Call("user", "ResetPassword", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Login using email only - Passwordless
|
||||
func (t *UserService) SendMagicLink(request *SendMagicLinkRequest) (*SendMagicLinkResponse, error) {
|
||||
|
||||
rsp := &SendMagicLinkResponse{}
|
||||
return rsp, t.client.Call("user", "SendMagicLink", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Send an email with a verification code to reset password.
|
||||
// Call "ResetPassword" endpoint once user provides the code.
|
||||
func (t *UserService) SendPasswordResetEmail(request *SendPasswordResetEmailRequest) (*SendPasswordResetEmailResponse, error) {
|
||||
|
||||
rsp := &SendPasswordResetEmailResponse{}
|
||||
return rsp, t.client.Call("user", "SendPasswordResetEmail", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Send a verification email
|
||||
// to the user being signed up. Email from will be from 'support@m3o.com',
|
||||
// to the user being signed up. Email from will be from 'noreply@email.m3ocontent.com',
|
||||
// but you can provide the title and contents.
|
||||
// The verification link will be injected in to the email as a template variable, $micro_verification_link.
|
||||
// Example: 'Hi there, welcome onboard! Use the link below to verify your email: $micro_verification_link'
|
||||
// The variable will be replaced with an actual url that will look similar to this:
|
||||
// 'https://user.m3o.com/user/verify?token=a-verification-token&redirectUrl=your-redir-url'
|
||||
func (t *UserService) SendVerificationEmail(request *SendVerificationEmailRequest) (*SendVerificationEmailResponse, error) {
|
||||
|
||||
rsp := &SendVerificationEmailResponse{}
|
||||
return rsp, t.client.Call("user", "SendVerificationEmail", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update the account password
|
||||
func (t *UserService) UpdatePassword(request *UpdatePasswordRequest) (*UpdatePasswordResponse, error) {
|
||||
|
||||
rsp := &UpdatePasswordResponse{}
|
||||
return rsp, t.client.Call("user", "UpdatePassword", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Update the account username or email
|
||||
func (t *UserService) Update(request *UpdateRequest) (*UpdateResponse, error) {
|
||||
|
||||
rsp := &UpdateResponse{}
|
||||
return rsp, t.client.Call("user", "Update", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Verify the email address of an account from a token sent in an email to the user.
|
||||
func (t *UserService) VerifyEmail(request *VerifyEmailRequest) (*VerifyEmailResponse, error) {
|
||||
|
||||
rsp := &VerifyEmailResponse{}
|
||||
return rsp, t.client.Call("user", "VerifyEmail", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Check whether the token attached to MagicLink is valid or not.
|
||||
// Ideally, you need to call this endpoint from your http request
|
||||
// handler that handles the endpoint which is specified in the
|
||||
// SendMagicLink request.
|
||||
func (t *UserService) VerifyToken(request *VerifyTokenRequest) (*VerifyTokenResponse, error) {
|
||||
|
||||
rsp := &VerifyTokenResponse{}
|
||||
return rsp, t.client.Call("user", "VerifyToken", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
@ -127,6 +191,17 @@ type DeleteRequest struct {
|
||||
type DeleteResponse struct {
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
// Maximum number of records to return. Default limit is 25.
|
||||
// Maximum limit is 1000. Anything higher will return an error.
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
Users []Account `json:"users"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
// The email address of the user
|
||||
Email string `json:"email"`
|
||||
@ -142,6 +217,7 @@ type LoginResponse struct {
|
||||
}
|
||||
|
||||
type LogoutRequest struct {
|
||||
// the session id for the user to logout
|
||||
SessionId string `json:"sessionId"`
|
||||
}
|
||||
|
||||
@ -167,16 +243,68 @@ type ReadSessionRequest struct {
|
||||
}
|
||||
|
||||
type ReadSessionResponse struct {
|
||||
// the session for the user
|
||||
Session *Session `json:"session"`
|
||||
}
|
||||
|
||||
type ResetPasswordRequest struct {
|
||||
// The code from the verification email
|
||||
Code string `json:"code"`
|
||||
// confirm new password
|
||||
ConfirmPassword string `json:"confirmPassword"`
|
||||
// the email to reset the password for
|
||||
Email string `json:"email"`
|
||||
// the new password
|
||||
NewPassword string `json:"newPassword"`
|
||||
}
|
||||
|
||||
type ResetPasswordResponse struct {
|
||||
}
|
||||
|
||||
type SendMagicLinkRequest struct {
|
||||
// Your web site address, example www.example.com or user.example.com
|
||||
Address string `json:"address"`
|
||||
// the email address of the user
|
||||
Email string `json:"email"`
|
||||
// Endpoint name where your http request handler handles MagicLink by
|
||||
// calling M3O VerifyToken endpoint. You can return as a result a success,
|
||||
// failed or redirect to another page.
|
||||
Endpoint string `json:"endpoint"`
|
||||
// Display name of the sender for the email. Note: the email address will still be 'support@m3o.com'
|
||||
FromName string `json:"fromName"`
|
||||
Subject string `json:"subject"`
|
||||
// Text content of the email. Don't forget to include the string '$micro_verification_link' which will be replaced by the real verification link
|
||||
// HTML emails are not available currently.
|
||||
TextContent string `json:"textContent"`
|
||||
}
|
||||
|
||||
type SendMagicLinkResponse struct {
|
||||
}
|
||||
|
||||
type SendPasswordResetEmailRequest struct {
|
||||
// email address to send reset for
|
||||
Email string `json:"email"`
|
||||
// Display name of the sender for the email. Note: the email address will still be 'noreply@email.m3ocontent.com'
|
||||
FromName string `json:"fromName"`
|
||||
// subject of the email
|
||||
Subject string `json:"subject"`
|
||||
// Text content of the email. Don't forget to include the string '$code' which will be replaced by the real verification link
|
||||
// HTML emails are not available currently.
|
||||
TextContent string `json:"textContent"`
|
||||
}
|
||||
|
||||
type SendPasswordResetEmailResponse struct {
|
||||
}
|
||||
|
||||
type SendVerificationEmailRequest struct {
|
||||
// email address to send the verification code
|
||||
Email string `json:"email"`
|
||||
FailureRedirectUrl string `json:"failureRedirectUrl"`
|
||||
// Display name of the sender for the email. Note: the email address will still be 'support@m3o.com'
|
||||
// Display name of the sender for the email. Note: the email address will still be 'noreply@email.m3ocontent.com'
|
||||
FromName string `json:"fromName"`
|
||||
RedirectUrl string `json:"redirectUrl"`
|
||||
Subject string `json:"subject"`
|
||||
// subject of the email
|
||||
Subject string `json:"subject"`
|
||||
// Text content of the email. Don't forget to include the string '$micro_verification_link' which will be replaced by the real verification link
|
||||
// HTML emails are not available currently.
|
||||
TextContent string `json:"textContent"`
|
||||
@ -198,7 +326,7 @@ type Session struct {
|
||||
|
||||
type UpdatePasswordRequest struct {
|
||||
// confirm new password
|
||||
ConfirmPassword string `json:"confirmPassword"`
|
||||
ConfirmPassword string `json:"confirm_password"`
|
||||
// the new password
|
||||
NewPassword string `json:"newPassword"`
|
||||
// the old password
|
||||
@ -225,9 +353,21 @@ type UpdateResponse struct {
|
||||
}
|
||||
|
||||
type VerifyEmailRequest struct {
|
||||
// the email address to verify
|
||||
Email string `json:"email"`
|
||||
// The token from the verification email
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type VerifyEmailResponse struct {
|
||||
}
|
||||
|
||||
type VerifyTokenRequest struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
type VerifyTokenResponse struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
Message string `json:"message"`
|
||||
Session *Session `json:"session"`
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ type VehicleService struct {
|
||||
|
||||
// Lookup a UK vehicle by it's registration number
|
||||
func (t *VehicleService) Lookup(request *LookupRequest) (*LookupResponse, error) {
|
||||
|
||||
rsp := &LookupResponse{}
|
||||
return rsp, t.client.Call("vehicle", "Lookup", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type LookupRequest struct {
|
||||
@ -29,33 +31,33 @@ type LookupRequest struct {
|
||||
|
||||
type LookupResponse struct {
|
||||
// co2 emmissions
|
||||
Co2emissions float64 `json:"co2emissions"`
|
||||
Co2Emissions float64 `json:"co2_emissions"`
|
||||
// colour of vehicle
|
||||
Colour string `json:"colour"`
|
||||
// engine capacity
|
||||
EngineCapacity int32 `json:"engineCapacity"`
|
||||
EngineCapacity int32 `json:"engine_capacity"`
|
||||
// fuel type e.g petrol, diesel
|
||||
FuelType string `json:"fuelType"`
|
||||
FuelType string `json:"fuel_type"`
|
||||
// date of last v5 issue
|
||||
LastV5issued string `json:"lastV5issued"`
|
||||
LastV5Issued string `json:"last_v5_issued"`
|
||||
// make of vehicle
|
||||
Make string `json:"make"`
|
||||
// month of first registration
|
||||
MonthOfFirstRegistration string `json:"monthOfFirstRegistration"`
|
||||
MonthOfFirstRegistration string `json:"month_of_first_registration"`
|
||||
// mot expiry
|
||||
MotExpiry string `json:"motExpiry"`
|
||||
MotExpiry string `json:"mot_expiry"`
|
||||
// mot status
|
||||
MotStatus string `json:"motStatus"`
|
||||
MotStatus string `json:"mot_status"`
|
||||
// registration number
|
||||
Registration string `json:"registration"`
|
||||
// tax due data
|
||||
TaxDueDate string `json:"taxDueDate"`
|
||||
TaxDueDate string `json:"tax_due_date"`
|
||||
// tax status
|
||||
TaxStatus string `json:"taxStatus"`
|
||||
TaxStatus string `json:"tax_status"`
|
||||
// type approvale
|
||||
TypeApproval string `json:"typeApproval"`
|
||||
TypeApproval string `json:"type_approval"`
|
||||
// wheel plan
|
||||
Wheelplan string `json:"wheelplan"`
|
||||
// year of manufacture
|
||||
YearOfManufacture int32 `json:"yearOfManufacture"`
|
||||
YearOfManufacture int32 `json:"year_of_manufacture"`
|
||||
}
|
||||
|
@ -18,43 +18,47 @@ type WeatherService struct {
|
||||
|
||||
// Get the weather forecast for the next 1-10 days
|
||||
func (t *WeatherService) Forecast(request *ForecastRequest) (*ForecastResponse, error) {
|
||||
|
||||
rsp := &ForecastResponse{}
|
||||
return rsp, t.client.Call("weather", "Forecast", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Get the current weather report for a location by postcode, city, zip code, ip address
|
||||
func (t *WeatherService) Now(request *NowRequest) (*NowResponse, error) {
|
||||
|
||||
rsp := &NowResponse{}
|
||||
return rsp, t.client.Call("weather", "Now", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type Forecast struct {
|
||||
// the average temp in celsius
|
||||
AvgTempC float64 `json:"avgTempC"`
|
||||
AvgTempC float64 `json:"avg_temp_c"`
|
||||
// the average temp in fahrenheit
|
||||
AvgTempF float64 `json:"avgTempF"`
|
||||
AvgTempF float64 `json:"avg_temp_f"`
|
||||
// chance of rain (percentage)
|
||||
ChanceOfRain int32 `json:"chanceOfRain"`
|
||||
ChanceOfRain int32 `json:"chance_of_rain"`
|
||||
// forecast condition
|
||||
Condition string `json:"condition"`
|
||||
// date of the forecast
|
||||
Date string `json:"date"`
|
||||
// the URL of forecast condition icon. Simply prefix with either http or https to use it
|
||||
IconUrl string `json:"iconUrl"`
|
||||
IconUrl string `json:"icon_url"`
|
||||
// max temp in celsius
|
||||
MaxTempC float64 `json:"maxTempC"`
|
||||
MaxTempC float64 `json:"max_temp_c"`
|
||||
// max temp in fahrenheit
|
||||
MaxTempF float64 `json:"maxTempF"`
|
||||
MaxTempF float64 `json:"max_temp_f"`
|
||||
// minimum temp in celsius
|
||||
MinTempC float64 `json:"minTempC"`
|
||||
MinTempC float64 `json:"min_temp_c"`
|
||||
// minimum temp in fahrenheit
|
||||
MinTempF float64 `json:"minTempF"`
|
||||
MinTempF float64 `json:"min_temp_f"`
|
||||
// time of sunrise
|
||||
Sunrise string `json:"sunrise"`
|
||||
// time of sunset
|
||||
Sunset string `json:"sunset"`
|
||||
// will it rain
|
||||
WillItRain bool `json:"willItRain"`
|
||||
WillItRain bool `json:"will_it_rain"`
|
||||
}
|
||||
|
||||
type ForecastRequest struct {
|
||||
@ -72,7 +76,7 @@ type ForecastResponse struct {
|
||||
// e.g 37.55
|
||||
Latitude float64 `json:"latitude"`
|
||||
// the local time
|
||||
LocalTime string `json:"localTime"`
|
||||
LocalTime string `json:"local_time"`
|
||||
// location of the request
|
||||
Location string `json:"location"`
|
||||
// e.g -77.46
|
||||
@ -98,17 +102,17 @@ type NowResponse struct {
|
||||
// whether its daytime
|
||||
Daytime bool `json:"daytime"`
|
||||
// feels like in celsius
|
||||
FeelsLikeC float64 `json:"feelsLikeC"`
|
||||
FeelsLikeC float64 `json:"feels_like_c"`
|
||||
// feels like in fahrenheit
|
||||
FeelsLikeF float64 `json:"feelsLikeF"`
|
||||
FeelsLikeF float64 `json:"feels_like_f"`
|
||||
// the humidity percentage
|
||||
Humidity int32 `json:"humidity"`
|
||||
// the URL of the related icon. Simply prefix with either http or https to use it
|
||||
IconUrl string `json:"iconUrl"`
|
||||
IconUrl string `json:"icon_url"`
|
||||
// e.g 37.55
|
||||
Latitude float64 `json:"latitude"`
|
||||
// the local time
|
||||
LocalTime string `json:"localTime"`
|
||||
LocalTime string `json:"local_time"`
|
||||
// location of the request
|
||||
Location string `json:"location"`
|
||||
// e.g -77.46
|
||||
@ -116,17 +120,17 @@ type NowResponse struct {
|
||||
// region related to the location
|
||||
Region string `json:"region"`
|
||||
// temperature in celsius
|
||||
TempC float64 `json:"tempC"`
|
||||
TempC float64 `json:"temp_c"`
|
||||
// temperature in fahrenheit
|
||||
TempF float64 `json:"tempF"`
|
||||
TempF float64 `json:"temp_f"`
|
||||
// timezone of the location
|
||||
Timezone string `json:"timezone"`
|
||||
// wind degree
|
||||
WindDegree int32 `json:"windDegree"`
|
||||
WindDegree int32 `json:"wind_degree"`
|
||||
// wind direction
|
||||
WindDirection string `json:"windDirection"`
|
||||
WindDirection string `json:"wind_direction"`
|
||||
// wind in kph
|
||||
WindKph float64 `json:"windKph"`
|
||||
WindKph float64 `json:"wind_kph"`
|
||||
// wind in mph
|
||||
WindMph float64 `json:"windMph"`
|
||||
WindMph float64 `json:"wind_mph"`
|
||||
}
|
||||
|
@ -16,10 +16,36 @@ type YoutubeService struct {
|
||||
client *client.Client
|
||||
}
|
||||
|
||||
// Embed a YouTube video
|
||||
func (t *YoutubeService) Embed(request *EmbedRequest) (*EmbedResponse, error) {
|
||||
|
||||
rsp := &EmbedResponse{}
|
||||
return rsp, t.client.Call("youtube", "Embed", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
// Search for videos on YouTube
|
||||
func (t *YoutubeService) Search(request *SearchRequest) (*SearchResponse, error) {
|
||||
|
||||
rsp := &SearchResponse{}
|
||||
return rsp, t.client.Call("youtube", "Search", request, rsp)
|
||||
|
||||
}
|
||||
|
||||
type EmbedRequest struct {
|
||||
// provide the youtube url e.g https://www.youtube.com/watch?v=GWRWZu7XsJ0
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type EmbedResponse struct {
|
||||
// the embeddable link e.g https://www.youtube.com/watch?v=GWRWZu7XsJ0
|
||||
EmbedUrl string `json:"embed_url"`
|
||||
// the script code
|
||||
HtmlScript string `json:"html_script"`
|
||||
// the full url
|
||||
LongUrl string `json:"long_url"`
|
||||
// the short url
|
||||
ShortUrl string `json:"short_url"`
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
@ -37,9 +63,9 @@ type SearchResult struct {
|
||||
// none, upcoming, live, completed
|
||||
Broadcasting string `json:"broadcasting"`
|
||||
// the channel id
|
||||
ChannelId string `json:"channelId"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
// the channel title
|
||||
ChannelTitle string `json:"channelTitle"`
|
||||
ChannelTitle string `json:"channel_title"`
|
||||
// the result description
|
||||
Description string `json:"description"`
|
||||
// id of the result
|
||||
@ -47,7 +73,7 @@ type SearchResult struct {
|
||||
// kind of result; "video", "channel", "playlist"
|
||||
Kind string `json:"kind"`
|
||||
// published at time
|
||||
PublishedAt string `json:"publishedAt"`
|
||||
PublishedAt string `json:"published_at"`
|
||||
// title of the result
|
||||
Title string `json:"title"`
|
||||
// the associated url
|
||||
|
Reference in New Issue
Block a user