1
0
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:
Asim Aslam
2021-12-21 13:18:29 +00:00
committed by GitHub
parent 8e52761edb
commit 7af0eb4b7a
67 changed files with 3457 additions and 271 deletions

View File

@ -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

View File

@ -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
View 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
View 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"`
}

View File

@ -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
View 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)
}

View 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))
}
}

View 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.

View 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
)

View 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=

View 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
}

View 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)
}
}
}

View 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
}

View File

@ -0,0 +1,5 @@
host: go.m3o.com
paths:
/:
repo: https://github.com/m3o/m3o-go

192
services/contact/contact.go Executable file
View 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"`
}

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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"`
}

View File

@ -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 {

View File

@ -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
View 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"`
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {
}

View File

@ -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"`
}

View File

@ -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
View 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
View 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=

View File

@ -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"

View File

@ -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 {

View File

@ -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"`
}

View File

@ -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 {

View File

@ -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

View File

@ -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
View 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"`
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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"`
}

View File

@ -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"`
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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"`
}

View File

@ -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
View 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"`
}

View File

@ -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 {

View File

@ -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
View 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
View 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"`
}

View File

@ -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

View File

@ -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 {
}

View File

@ -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

View File

@ -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"`
}

View File

@ -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
View 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"`
}

View File

@ -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

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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