diff --git a/services/address/address.go b/services/address/address.go index e1332944..69c61a6d 100755 --- a/services/address/address.go +++ b/services/address/address.go @@ -1,7 +1,7 @@ package address import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Address interface { diff --git a/services/answer/answer.go b/services/answer/answer.go index 8562c9e7..b82b0aa4 100755 --- a/services/answer/answer.go +++ b/services/answer/answer.go @@ -1,7 +1,7 @@ package answer import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Answer interface { diff --git a/services/app/app.go b/services/app/app.go index c76a8268..79c0c695 100755 --- a/services/app/app.go +++ b/services/app/app.go @@ -1,7 +1,7 @@ package app import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type App interface { diff --git a/services/avatar/avatar.go b/services/avatar/avatar.go index 3395a549..e2342777 100755 --- a/services/avatar/avatar.go +++ b/services/avatar/avatar.go @@ -1,7 +1,7 @@ package avatar import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Avatar interface { diff --git a/services/cache/cache.go b/services/cache/cache.go index 5ab83b93..95869fde 100755 --- a/services/cache/cache.go +++ b/services/cache/cache.go @@ -1,7 +1,7 @@ package cache import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Cache interface { diff --git a/services/client/client.go b/services/client/client.go new file mode 100644 index 00000000..6d578641 --- /dev/null +++ b/services/client/client.go @@ -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) +} diff --git a/services/client/client_test.go b/services/client/client_test.go new file mode 100644 index 00000000..0967c74c --- /dev/null +++ b/services/client/client_test.go @@ -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)) + } +} diff --git a/services/contact/contact.go b/services/contact/contact.go index 26999f4f..47d781bd 100755 --- a/services/contact/contact.go +++ b/services/contact/contact.go @@ -1,7 +1,7 @@ package contact import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Contact interface { diff --git a/services/crypto/crypto.go b/services/crypto/crypto.go index 2859e9b8..0434b3e7 100755 --- a/services/crypto/crypto.go +++ b/services/crypto/crypto.go @@ -1,7 +1,7 @@ package crypto import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Crypto interface { diff --git a/services/currency/currency.go b/services/currency/currency.go index 1464795c..1b462d75 100755 --- a/services/currency/currency.go +++ b/services/currency/currency.go @@ -1,7 +1,7 @@ package currency import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Currency interface { diff --git a/services/db/db.go b/services/db/db.go index 02777478..5bd3ce23 100755 --- a/services/db/db.go +++ b/services/db/db.go @@ -1,7 +1,7 @@ package db import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Db interface { diff --git a/services/email/email.go b/services/email/email.go index 1e004c9c..f156408c 100755 --- a/services/email/email.go +++ b/services/email/email.go @@ -1,7 +1,7 @@ package email import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Email interface { diff --git a/services/emoji/emoji.go b/services/emoji/emoji.go index 714aabbe..a5320d1e 100755 --- a/services/emoji/emoji.go +++ b/services/emoji/emoji.go @@ -1,7 +1,7 @@ package emoji import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Emoji interface { diff --git a/services/evchargers/evchargers.go b/services/evchargers/evchargers.go index 2fc1c44c..e2c62243 100755 --- a/services/evchargers/evchargers.go +++ b/services/evchargers/evchargers.go @@ -1,7 +1,7 @@ package evchargers import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Evchargers interface { diff --git a/services/event/event.go b/services/event/event.go index 4f572457..602dc3b3 100755 --- a/services/event/event.go +++ b/services/event/event.go @@ -1,7 +1,7 @@ package event import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Event interface { diff --git a/services/file/file.go b/services/file/file.go index e001b108..b27d8e43 100755 --- a/services/file/file.go +++ b/services/file/file.go @@ -1,7 +1,7 @@ package file import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type File interface { diff --git a/services/forex/forex.go b/services/forex/forex.go index cd154bbb..d9f3f66e 100755 --- a/services/forex/forex.go +++ b/services/forex/forex.go @@ -1,7 +1,7 @@ package forex import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Forex interface { diff --git a/services/function/function.go b/services/function/function.go index 2e942609..b85b5c16 100755 --- a/services/function/function.go +++ b/services/function/function.go @@ -1,7 +1,7 @@ package function import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Function interface { diff --git a/services/geocoding/geocoding.go b/services/geocoding/geocoding.go index d66387cc..f7741f8b 100755 --- a/services/geocoding/geocoding.go +++ b/services/geocoding/geocoding.go @@ -1,7 +1,7 @@ package geocoding import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Geocoding interface { diff --git a/services/gifs/gifs.go b/services/gifs/gifs.go index 0ec89bef..8e5341b7 100755 --- a/services/gifs/gifs.go +++ b/services/gifs/gifs.go @@ -1,7 +1,7 @@ package gifs import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Gifs interface { diff --git a/services/google/google.go b/services/google/google.go index deb4a0ec..25031330 100755 --- a/services/google/google.go +++ b/services/google/google.go @@ -1,7 +1,7 @@ package google import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Google interface { diff --git a/services/helloworld/helloworld.go b/services/helloworld/helloworld.go index ceb82fdf..b259f670 100755 --- a/services/helloworld/helloworld.go +++ b/services/helloworld/helloworld.go @@ -1,7 +1,7 @@ package helloworld import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Helloworld interface { diff --git a/services/holidays/holidays.go b/services/holidays/holidays.go index 0a8eae0f..737bbcd3 100755 --- a/services/holidays/holidays.go +++ b/services/holidays/holidays.go @@ -1,7 +1,7 @@ package holidays import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Holidays interface { diff --git a/services/id/id.go b/services/id/id.go index 8a7f9b43..0eb7a986 100755 --- a/services/id/id.go +++ b/services/id/id.go @@ -1,7 +1,7 @@ package id import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Id interface { diff --git a/services/image/image.go b/services/image/image.go index d78cc9f3..a044bc6e 100755 --- a/services/image/image.go +++ b/services/image/image.go @@ -1,7 +1,7 @@ package image import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Image interface { diff --git a/services/ip/ip.go b/services/ip/ip.go index 8ebbb36c..e2f62d3d 100755 --- a/services/ip/ip.go +++ b/services/ip/ip.go @@ -1,7 +1,7 @@ package ip import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Ip interface { diff --git a/services/joke/joke.go b/services/joke/joke.go index b97803f4..3e605f84 100755 --- a/services/joke/joke.go +++ b/services/joke/joke.go @@ -1,7 +1,7 @@ package joke import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Joke interface { diff --git a/services/location/location.go b/services/location/location.go index ecd3a0a2..bc8920e8 100755 --- a/services/location/location.go +++ b/services/location/location.go @@ -1,7 +1,7 @@ package location import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Location interface { diff --git a/services/movie/movie.go b/services/movie/movie.go index 69920ae2..175fb342 100755 --- a/services/movie/movie.go +++ b/services/movie/movie.go @@ -1,7 +1,7 @@ package movie import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Movie interface { diff --git a/services/mq/mq.go b/services/mq/mq.go index 6a9f7b3b..7b54358f 100755 --- a/services/mq/mq.go +++ b/services/mq/mq.go @@ -1,7 +1,7 @@ package mq import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Mq interface { diff --git a/services/news/news.go b/services/news/news.go index 02252714..0a663d04 100755 --- a/services/news/news.go +++ b/services/news/news.go @@ -1,7 +1,7 @@ package news import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type News interface { diff --git a/services/nft/nft.go b/services/nft/nft.go index bf838526..c61d2fb4 100755 --- a/services/nft/nft.go +++ b/services/nft/nft.go @@ -1,7 +1,7 @@ package nft import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Nft interface { diff --git a/services/notes/notes.go b/services/notes/notes.go index 519a0bff..150b8d59 100755 --- a/services/notes/notes.go +++ b/services/notes/notes.go @@ -1,7 +1,7 @@ package notes import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Notes interface { diff --git a/services/otp/otp.go b/services/otp/otp.go index 088e1051..957130ed 100755 --- a/services/otp/otp.go +++ b/services/otp/otp.go @@ -1,7 +1,7 @@ package otp import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Otp interface { diff --git a/services/postcode/postcode.go b/services/postcode/postcode.go index 2a818022..f6f59c82 100755 --- a/services/postcode/postcode.go +++ b/services/postcode/postcode.go @@ -1,7 +1,7 @@ package postcode import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Postcode interface { diff --git a/services/prayer/prayer.go b/services/prayer/prayer.go index 65db5aea..9d4e1329 100755 --- a/services/prayer/prayer.go +++ b/services/prayer/prayer.go @@ -1,7 +1,7 @@ package prayer import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Prayer interface { diff --git a/services/qr/qr.go b/services/qr/qr.go index 02318056..0c67eeae 100755 --- a/services/qr/qr.go +++ b/services/qr/qr.go @@ -1,7 +1,7 @@ package qr import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Qr interface { diff --git a/services/quran/quran.go b/services/quran/quran.go index c60fe230..a8ba6525 100755 --- a/services/quran/quran.go +++ b/services/quran/quran.go @@ -1,7 +1,7 @@ package quran import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Quran interface { diff --git a/services/routing/routing.go b/services/routing/routing.go index 7d716d5f..cbb4b50a 100755 --- a/services/routing/routing.go +++ b/services/routing/routing.go @@ -1,7 +1,7 @@ package routing import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Routing interface { diff --git a/services/rss/rss.go b/services/rss/rss.go index dbbd5597..c3b385e7 100755 --- a/services/rss/rss.go +++ b/services/rss/rss.go @@ -1,7 +1,7 @@ package rss import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Rss interface { diff --git a/services/search/search.go b/services/search/search.go index 8338f959..b2e6f580 100755 --- a/services/search/search.go +++ b/services/search/search.go @@ -1,7 +1,7 @@ package search import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Search interface { diff --git a/services/sentiment/sentiment.go b/services/sentiment/sentiment.go index 3491ca1d..3b35a10e 100755 --- a/services/sentiment/sentiment.go +++ b/services/sentiment/sentiment.go @@ -1,7 +1,7 @@ package sentiment import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Sentiment interface { diff --git a/services/sms/sms.go b/services/sms/sms.go index 79505a27..91a8764c 100755 --- a/services/sms/sms.go +++ b/services/sms/sms.go @@ -1,7 +1,7 @@ package sms import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Sms interface { diff --git a/services/space/space.go b/services/space/space.go index 9f46411d..58c717cc 100755 --- a/services/space/space.go +++ b/services/space/space.go @@ -1,7 +1,7 @@ package space import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Space interface { diff --git a/services/spam/spam.go b/services/spam/spam.go index 04e85c61..5be1364c 100755 --- a/services/spam/spam.go +++ b/services/spam/spam.go @@ -1,7 +1,7 @@ package spam import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Spam interface { diff --git a/services/stock/stock.go b/services/stock/stock.go index 04f7305d..23f79c89 100755 --- a/services/stock/stock.go +++ b/services/stock/stock.go @@ -1,7 +1,7 @@ package stock import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Stock interface { diff --git a/services/stream/stream.go b/services/stream/stream.go index 4fba9841..aa8e119f 100755 --- a/services/stream/stream.go +++ b/services/stream/stream.go @@ -1,7 +1,7 @@ package stream import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Stream interface { diff --git a/services/sunnah/sunnah.go b/services/sunnah/sunnah.go index 3d77ed57..ce1f89c5 100755 --- a/services/sunnah/sunnah.go +++ b/services/sunnah/sunnah.go @@ -1,7 +1,7 @@ package sunnah import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Sunnah interface { diff --git a/services/thumbnail/thumbnail.go b/services/thumbnail/thumbnail.go index 988bbc5f..f0c5f07c 100755 --- a/services/thumbnail/thumbnail.go +++ b/services/thumbnail/thumbnail.go @@ -1,7 +1,7 @@ package thumbnail import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Thumbnail interface { diff --git a/services/time/time.go b/services/time/time.go index 98daca1c..1b5b46da 100755 --- a/services/time/time.go +++ b/services/time/time.go @@ -1,7 +1,7 @@ package time import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Time interface { diff --git a/services/translate/translate.go b/services/translate/translate.go index f680802f..fdae3638 100755 --- a/services/translate/translate.go +++ b/services/translate/translate.go @@ -1,7 +1,7 @@ package translate import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Translate interface { diff --git a/services/twitter/twitter.go b/services/twitter/twitter.go index fb9dedf8..c9f965a7 100755 --- a/services/twitter/twitter.go +++ b/services/twitter/twitter.go @@ -1,7 +1,7 @@ package twitter import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Twitter interface { diff --git a/services/url/url.go b/services/url/url.go index b57099f9..21d26e1a 100755 --- a/services/url/url.go +++ b/services/url/url.go @@ -1,7 +1,7 @@ package url import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Url interface { diff --git a/services/user/user.go b/services/user/user.go index 22153421..c061e034 100755 --- a/services/user/user.go +++ b/services/user/user.go @@ -1,7 +1,7 @@ package user import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type User interface { diff --git a/services/vehicle/vehicle.go b/services/vehicle/vehicle.go index ccb135de..6811eca3 100755 --- a/services/vehicle/vehicle.go +++ b/services/vehicle/vehicle.go @@ -1,7 +1,7 @@ package vehicle import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Vehicle interface { diff --git a/services/weather/weather.go b/services/weather/weather.go index 097e45b3..2eef52b0 100755 --- a/services/weather/weather.go +++ b/services/weather/weather.go @@ -1,7 +1,7 @@ package weather import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Weather interface { diff --git a/services/youtube/youtube.go b/services/youtube/youtube.go index 07f49c7c..943dabb7 100755 --- a/services/youtube/youtube.go +++ b/services/youtube/youtube.go @@ -1,7 +1,7 @@ package youtube import ( - "go.m3o.com/client" + "go-micro.dev/v4/services/client" ) type Youtube interface {