<commit_before>package rabbithole

// Health represents response from healthchecks endpoint
type Health struct {
	Status string `json:"status"`
	Reason string `json:"reason"`
}

// HealthChecks endpoint checks if the application is running,
// channels and queues can be listed, and that no alarms are raised
func (c *Client) HealthCheck() (rec *Health, err error) {
	req, err := newGETRequest(c, "healthchecks/node")
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

// HealthChecks endpoint checks for a given node if the application is running,
// channels and queues can be listed, and that no alarms are raised
func (c *Client) HealthCheckFor(node string) (rec *Health, err error) {
	req, err := newGETRequest(c, "healthchecks/node/"+node)
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

// Aliveness represents response from aliveness-test endpoint
type Aliveness struct {
	Status string `json:"status"`
}

// Aliveness endpoint declares a test queue, then publishes a message and consumes a message
func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) {
	req, err := newGETRequest(c, "aliveness-test/"+vhost)
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}
<commit_msg>added health checks<commit_after>package rabbithole

import "strconv"

type TimeUnit string

const (
	DAYS   TimeUnit = "days"
	WEEKS  TimeUnit = "weeks"
	MONTHS TimeUnit = "months"
	YEARS  TimeUnit = "years"
)

type Protocol string

const (
	AMQP091   Protocol = "amqp091"
	AMQP10    Protocol = "amqp10"
	MQTT      Protocol = "mqtt"
	STOMP     Protocol = "stomp"
	WEB_MQTT  Protocol = "web-mqtt"
	WEB_STOMP Protocol = "web-stomp"
)

// Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckAlarms() error {
	req, err := newGETRequest(c, "health/checks/alarms")
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Responds a 200 OK if there are no local alarms in effect on the target node, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckLocalAlarms() error {
	req, err := newGETRequest(c, "health/checks/local-alarms")
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Checks the expiration date on the certificates for every listener configured to use TLS.
// Responds a 200 OK if all certificates are valid (have not expired), otherwise responds with a 503 Service Unavailable.
// Valid units: days, weeks, months, years. The value of the within argument is the number of units.
// So, when within is 2 and unit is "months", the expiration period used by the check will be the next two months.
func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (rec *Health, err error) {
	req, err := newGETRequest(c, "health/checks/certificate-expiration/"+strconv.Itoa(int(within))+"/"+string(unit))
	if err != nil {
		return nil, err
	}

	if _, err = executeRequest(c, req); err != nil {
		return nil, err
	}

	return rec, nil
}

// Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckPortListenerListener(port uint) error {
	req, err := newGETRequest(c, "health/checks/port-listener/"+strconv.Itoa(int(port)))
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable.
// Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp.
func (c *Client) HealthCheckProtocolListener(protocol Protocol) error {
	req, err := newGETRequest(c, "health/checks/protocol-listener/"+string(protocol))
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Responds a 200 OK if all virtual hosts and running on the target node, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckVirtualHosts() error {
	req, err := newGETRequest(c, "health/checks/virtual-hosts")
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Checks if there are classic mirrored queues without synchronised mirrors online (queues that would potentially lose data if the target node is shut down).
// Responds a 200 OK if there are no such classic mirrored queues, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckNodeIsMirrorSyncCritical() error {
	req, err := newGETRequest(c, "health/checks/node-is-mirror-sync-critical")
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Checks if there are quorum queues with minimum online quorum (queues that would lose their quorum and availability if the target node is shut down).
// Responds a 200 OK if there are no such quorum queues, otherwise responds with a 503 Service Unavailable.
func (c *Client) HealthCheckNodeIsQuorumCritical() error {
	req, err := newGETRequest(c, "health/checks/node-is-quorum-critical")
	if err != nil {
		return err
	}

	if _, err = executeRequest(c, req); err != nil {
		return err
	}

	return nil
}

// Deprecated health check api

// Health represents response from healthchecks endpoint
type Health struct {
	Status string `json:"status"`
	Reason string `json:"reason"`
}

// HealthChecks endpoint checks if the application is running,
// channels and queues can be listed, and that no alarms are raised
func (c *Client) HealthCheck() (rec *Health, err error) {
	req, err := newGETRequest(c, "healthchecks/node")
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

// HealthChecks endpoint checks for a given node if the application is running,
// channels and queues can be listed, and that no alarms are raised
func (c *Client) HealthCheckFor(node string) (rec *Health, err error) {
	req, err := newGETRequest(c, "healthchecks/node/"+node)
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}

// Aliveness represents response from aliveness-test endpoint
type Aliveness struct {
	Status string `json:"status"`
}

// Aliveness endpoint declares a test queue, then publishes a message and consumes a message
func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) {
	req, err := newGETRequest(c, "aliveness-test/"+vhost)
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &rec); err != nil {
		return nil, err
	}

	return rec, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-rollbar Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rollbar

import (
	"net/http"

	api "github.com/zchee/go-rollbar/api/v1"
	"golang.org/x/net/context"
)

type Call interface {
	Request(*http.Request) Call
	Custom(map[string]interface{}) Call
	UUID(string) Call
	Do(context.Context) (*api.Response, error)
}

type callOption struct {
	err    error
	req    *http.Request
	custom map[string]interface{}
	id     string
}

func joinPayload(payload *api.Payload, opt callOption) {
	if opt.req != nil {
		payload.Data.Request = errorRequest(opt.req)
	}
	if opt.custom != nil {
		payload.Data.Custom = opt.custom
	}
	if opt.id != "" {
		payload.Data.UUID = opt.id
	}
}

type DebugCall struct {
	client *httpClient
	callOption
}

// Debug sends the error to rollbar with debug level.
func (c *client) Debug(err error) Call {
	var call DebugCall
	call.client = c.debugClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *DebugCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *DebugCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *DebugCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *DebugCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(DebugLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type InfoCall struct {
	client *httpClient
	callOption
}

// Info sends the error to rollbar with info level.
func (c *client) Info(err error) Call {
	var call InfoCall
	call.client = c.infoClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *InfoCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *InfoCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *InfoCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *InfoCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(InfoLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type ErrorCall struct {
	client *httpClient
	callOption
}

// Error sends the error to rollbar with error level.
func (c *client) Error(err error) Call {
	var call ErrorCall
	call.client = c.errorClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *ErrorCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *ErrorCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *ErrorCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *ErrorCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(ErrorLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type WarnCall struct {
	client *httpClient
	callOption
}

// Warn sends the error to rollbar with warning level.
func (c *client) Warn(err error) Call {
	var call WarnCall
	call.client = c.warnClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *WarnCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *WarnCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *WarnCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *WarnCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(WarnLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type CriticalCall struct {
	client *httpClient
	callOption
}

// Critical sends the error to rollbar with critical level.
func (c *client) Critical(err error) Call {
	var call CriticalCall
	call.client = c.criticalClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *CriticalCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *CriticalCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *CriticalCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *CriticalCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(CriticalLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}
<commit_msg>call: add Person fluent method<commit_after>// Copyright 2017 The go-rollbar Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rollbar

import (
	"net/http"

	api "github.com/zchee/go-rollbar/api/v1"
	"golang.org/x/net/context"
)

type Call interface {
	Request(*http.Request) Call
	Person(string, string, string) Call
	Custom(map[string]interface{}) Call
	UUID(string) Call
	Do(context.Context) (*api.Response, error)
}

type callOption struct {
	err    error
	req    *http.Request
	person *api.Person
	custom map[string]interface{}
	id     string
}

func joinPayload(payload *api.Payload, opt callOption) {
	if opt.req != nil {
		payload.Data.Request = errorRequest(opt.req)
	}
	if opt.person != nil {
		payload.Data.Person = opt.person
	}
	if opt.custom != nil {
		payload.Data.Custom = opt.custom
	}
	if opt.id != "" {
		payload.Data.UUID = opt.id
	}
}

type DebugCall struct {
	client *httpClient
	callOption
}

// Debug sends the error to rollbar with debug level.
func (c *client) Debug(err error) Call {
	var call DebugCall
	call.client = c.debugClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *DebugCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Person is the user affected by this event. Will be indexed by ID, username, and email.
// People are stored in Rollbar keyed by ID. If you send a multiple different usernames/emails for the
// same ID, the last received values will overwrite earlier ones.
func (c *DebugCall) Person(id, username, email string) Call {
	if id == "" { // id is required
		return c
	}

	c.person = &api.Person{
		ID:       id,
		Username: username,
		Email:    email,
	}
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *DebugCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *DebugCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *DebugCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(DebugLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type InfoCall struct {
	client *httpClient
	callOption
}

// Info sends the error to rollbar with info level.
func (c *client) Info(err error) Call {
	var call InfoCall
	call.client = c.infoClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *InfoCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Person is the user affected by this event. Will be indexed by ID, username, and email.
// People are stored in Rollbar keyed by ID. If you send a multiple different usernames/emails for the
// same ID, the last received values will overwrite earlier ones.
func (c *InfoCall) Person(id, username, email string) Call {
	if id == "" { // id is required
		return c
	}

	c.person = &api.Person{
		ID:       id,
		Username: username,
		Email:    email,
	}
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *InfoCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *InfoCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *InfoCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(InfoLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type ErrorCall struct {
	client *httpClient
	callOption
}

// Error sends the error to rollbar with error level.
func (c *client) Error(err error) Call {
	var call ErrorCall
	call.client = c.errorClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *ErrorCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Person is the user affected by this event. Will be indexed by ID, username, and email.
// People are stored in Rollbar keyed by ID. If you send a multiple different usernames/emails for the
// same ID, the last received values will overwrite earlier ones.
func (c *ErrorCall) Person(id, username, email string) Call {
	if id == "" { // id is required
		return c
	}

	c.person = &api.Person{
		ID:       id,
		Username: username,
		Email:    email,
	}
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *ErrorCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *ErrorCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *ErrorCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(ErrorLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type WarnCall struct {
	client *httpClient
	callOption
}

// Warn sends the error to rollbar with warning level.
func (c *client) Warn(err error) Call {
	var call WarnCall
	call.client = c.warnClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *WarnCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Person is the user affected by this event. Will be indexed by ID, username, and email.
// People are stored in Rollbar keyed by ID. If you send a multiple different usernames/emails for the
// same ID, the last received values will overwrite earlier ones.
func (c *WarnCall) Person(id, username, email string) Call {
	if id == "" { // id is required
		return c
	}

	c.person = &api.Person{
		ID:       id,
		Username: username,
		Email:    email,
	}
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *WarnCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *WarnCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *WarnCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(WarnLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}

type CriticalCall struct {
	client *httpClient
	callOption
}

// Critical sends the error to rollbar with critical level.
func (c *client) Critical(err error) Call {
	var call CriticalCall
	call.client = c.criticalClient
	call.err = err
	return &call
}

// Request is a data about the request this event occurred in.
func (c *CriticalCall) Request(req *http.Request) Call {
	c.req = req
	return c
}

// Person is the user affected by this event. Will be indexed by ID, username, and email.
// People are stored in Rollbar keyed by ID. If you send a multiple different usernames/emails for the
// same ID, the last received values will overwrite earlier ones.
func (c *CriticalCall) Person(id, username, email string) Call {
	if id == "" { // id is required
		return c
	}

	c.person = &api.Person{
		ID:       id,
		Username: username,
		Email:    email,
	}
	return c
}

// Custom is any arbitrary metadata you want to send. "custom" itself should be an object.
func (c *CriticalCall) Custom(custom map[string]interface{}) Call {
	c.custom = custom
	return c
}

// UUID a string, up to 36 characters, that uniquely identifies this occurrence.
// While it can now be any latin1 string, this may change to be a 16 byte field in the future.
// We recommend using a UUID4 (16 random bytes).
// The UUID space is unique to each project, and can be used to look up an occurrence later.
// It is also used to detect duplicate requests. If you send the same UUID in two payloads, the second
// one will be discarded.
// While optional, it is recommended that all clients generate and provide this field.
func (c *CriticalCall) UUID(id string) Call {
	c.id = id
	return c
}

func (c *CriticalCall) Do(ctx context.Context) (*api.Response, error) {
	payload := c.client.payload(CriticalLevel, c.err)
	joinPayload(payload, c.callOption)
	return c.client.post(ctx, payload)
}
<|endoftext|>


<commit_before><commit_msg>Removing explicit conversion of relative theme path to Absolute path<commit_after><|endoftext|>


<commit_before><commit_msg>Update test coverage for nonce state in Gothic<commit_after><|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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.
 *
 */

//go:generate protoc -I ../routeguide --go_out=plugins=grpc:../routeguide ../routeguide/route_guide.proto

// Package main implements a simple gRPC server that demonstrates how to use gRPC-Go libraries
// to perform unary, client streaming, server streaming and full duplex RPCs.
//
// It implements the route guide service whose definition can be found in routeguide/route_guide.proto.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/testdata"

	"github.com/golang/protobuf/proto"

	pb "google.golang.org/grpc/examples/route_guide/routeguide"
)

var (
	tls        = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
	certFile   = flag.String("cert_file", "", "The TLS cert file")
	keyFile    = flag.String("key_file", "", "The TLS key file")
	jsonDBFile = flag.String("json_db_file", "testdata/route_guide_db.json", "A json file containing a list of features")
	port       = flag.Int("port", 10000, "The server port")
)

type routeGuideServer struct {
	savedFeatures []*pb.Feature
	routeNotes    map[string][]*pb.RouteNote
}

// GetFeature returns the feature at the given point.
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
	for _, feature := range s.savedFeatures {
		if proto.Equal(feature.Location, point) {
			return feature, nil
		}
	}
	// No feature was found, return an unnamed feature
	return &pb.Feature{Location: point}, nil
}

// ListFeatures lists all features contained within the given bounding Rectangle.
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
	for _, feature := range s.savedFeatures {
		if inRange(feature.Location, rect) {
			if err := stream.Send(feature); err != nil {
				return err
			}
		}
	}
	return nil
}

// RecordRoute records a route composited of a sequence of points.
//
// It gets a stream of points, and responds with statistics about the "trip":
// number of points,  number of known features visited, total distance traveled, and
// total time spent.
func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
	var pointCount, featureCount, distance int32
	var lastPoint *pb.Point
	startTime := time.Now()
	for {
		point, err := stream.Recv()
		if err == io.EOF {
			endTime := time.Now()
			return stream.SendAndClose(&pb.RouteSummary{
				PointCount:   pointCount,
				FeatureCount: featureCount,
				Distance:     distance,
				ElapsedTime:  int32(endTime.Sub(startTime).Seconds()),
			})
		}
		if err != nil {
			return err
		}
		pointCount++
		for _, feature := range s.savedFeatures {
			if proto.Equal(feature.Location, point) {
				featureCount++
			}
		}
		if lastPoint != nil {
			distance += calcDistance(lastPoint, point)
		}
		lastPoint = point
	}
}

// RouteChat receives a stream of message/location pairs, and responds with a stream of all
// previous messages at each of those locations.
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
	for {
		in, err := stream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		key := serialize(in.Location)
		if _, present := s.routeNotes[key]; !present {
			s.routeNotes[key] = []*pb.RouteNote{in}
		} else {
			s.routeNotes[key] = append(s.routeNotes[key], in)
		}
		for _, note := range s.routeNotes[key] {
			if err := stream.Send(note); err != nil {
				return err
			}
		}
	}
}

// loadFeatures loads features from a JSON file.
func (s *routeGuideServer) loadFeatures(filePath string) {
	file, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatalf("Failed to load default features: %v", err)
	}
	if err := json.Unmarshal(file, &s.savedFeatures); err != nil {
		log.Fatalf("Failed to load default features: %v", err)
	}
}

func toRadians(num float64) float64 {
	return num * math.Pi / float64(180)
}

// calcDistance calculates the distance between two points using the "haversine" formula.
// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
	const CordFactor float64 = 1e7
	const R float64 = float64(6371000) // metres
	lat1 := float64(p1.Latitude) / CordFactor
	lat2 := float64(p2.Latitude) / CordFactor
	lng1 := float64(p1.Longitude) / CordFactor
	lng2 := float64(p2.Longitude) / CordFactor
	φ1 := toRadians(lat1)
	φ2 := toRadians(lat2)
	Δφ := toRadians(lat2 - lat1)
	Δλ := toRadians(lng2 - lng1)

	a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +
		math.Cos(φ1)*math.Cos(φ2)*
			math.Sin(Δλ/2)*math.Sin(Δλ/2)
	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))

	distance := R * c
	return int32(distance)
}

func inRange(point *pb.Point, rect *pb.Rectangle) bool {
	left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
	right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
	top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
	bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))

	if float64(point.Longitude) >= left &&
		float64(point.Longitude) <= right &&
		float64(point.Latitude) >= bottom &&
		float64(point.Latitude) <= top {
		return true
	}
	return false
}

func serialize(point *pb.Point) string {
	return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)
}

func newServer() *routeGuideServer {
	s := new(routeGuideServer)
	s.loadFeatures(*jsonDBFile)
	s.routeNotes = make(map[string][]*pb.RouteNote)
	return s
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	var opts []grpc.ServerOption
	if *tls {
		if *certFile == "" {
			*certFile = testdata.Path("server1.pem")
		}
		if *keyFile == "" {
			*keyFile = testdata.Path("server1.key")
		}
		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
		if err != nil {
			log.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	grpcServer := grpc.NewServer(opts...)
	pb.RegisterRouteGuideServer(grpcServer, newServer())
	grpcServer.Serve(lis)
}
<commit_msg>examples: fix concurrent map accesses in route_guide server (#1752)<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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.
 *
 */

//go:generate protoc -I ../routeguide --go_out=plugins=grpc:../routeguide ../routeguide/route_guide.proto

// Package main implements a simple gRPC server that demonstrates how to use gRPC-Go libraries
// to perform unary, client streaming, server streaming and full duplex RPCs.
//
// It implements the route guide service whose definition can be found in routeguide/route_guide.proto.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"net"
	"sync"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/testdata"

	"github.com/golang/protobuf/proto"

	pb "google.golang.org/grpc/examples/route_guide/routeguide"
)

var (
	tls        = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
	certFile   = flag.String("cert_file", "", "The TLS cert file")
	keyFile    = flag.String("key_file", "", "The TLS key file")
	jsonDBFile = flag.String("json_db_file", "testdata/route_guide_db.json", "A json file containing a list of features")
	port       = flag.Int("port", 10000, "The server port")
)

type routeGuideServer struct {
	savedFeatures []*pb.Feature // read-only after initialized

	mu         sync.Mutex // protects routeNotes
	routeNotes map[string][]*pb.RouteNote
}

// GetFeature returns the feature at the given point.
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
	for _, feature := range s.savedFeatures {
		if proto.Equal(feature.Location, point) {
			return feature, nil
		}
	}
	// No feature was found, return an unnamed feature
	return &pb.Feature{Location: point}, nil
}

// ListFeatures lists all features contained within the given bounding Rectangle.
func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
	for _, feature := range s.savedFeatures {
		if inRange(feature.Location, rect) {
			if err := stream.Send(feature); err != nil {
				return err
			}
		}
	}
	return nil
}

// RecordRoute records a route composited of a sequence of points.
//
// It gets a stream of points, and responds with statistics about the "trip":
// number of points,  number of known features visited, total distance traveled, and
// total time spent.
func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
	var pointCount, featureCount, distance int32
	var lastPoint *pb.Point
	startTime := time.Now()
	for {
		point, err := stream.Recv()
		if err == io.EOF {
			endTime := time.Now()
			return stream.SendAndClose(&pb.RouteSummary{
				PointCount:   pointCount,
				FeatureCount: featureCount,
				Distance:     distance,
				ElapsedTime:  int32(endTime.Sub(startTime).Seconds()),
			})
		}
		if err != nil {
			return err
		}
		pointCount++
		for _, feature := range s.savedFeatures {
			if proto.Equal(feature.Location, point) {
				featureCount++
			}
		}
		if lastPoint != nil {
			distance += calcDistance(lastPoint, point)
		}
		lastPoint = point
	}
}

// RouteChat receives a stream of message/location pairs, and responds with a stream of all
// previous messages at each of those locations.
func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
	for {
		in, err := stream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		key := serialize(in.Location)

		s.mu.Lock()
		s.routeNotes[key] = append(s.routeNotes[key], in)
		// Note: this copy prevents blocking other clients while serving this one.
		// We don't need to do a deep copy, because elements in the slice are
		// insert-only and never modified.
		rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
		copy(rn, s.routeNotes[key])
		s.mu.Unlock()

		for _, note := range rn {
			if err := stream.Send(note); err != nil {
				return err
			}
		}
	}
}

// loadFeatures loads features from a JSON file.
func (s *routeGuideServer) loadFeatures(filePath string) {
	file, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatalf("Failed to load default features: %v", err)
	}
	if err := json.Unmarshal(file, &s.savedFeatures); err != nil {
		log.Fatalf("Failed to load default features: %v", err)
	}
}

func toRadians(num float64) float64 {
	return num * math.Pi / float64(180)
}

// calcDistance calculates the distance between two points using the "haversine" formula.
// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
	const CordFactor float64 = 1e7
	const R float64 = float64(6371000) // metres
	lat1 := float64(p1.Latitude) / CordFactor
	lat2 := float64(p2.Latitude) / CordFactor
	lng1 := float64(p1.Longitude) / CordFactor
	lng2 := float64(p2.Longitude) / CordFactor
	φ1 := toRadians(lat1)
	φ2 := toRadians(lat2)
	Δφ := toRadians(lat2 - lat1)
	Δλ := toRadians(lng2 - lng1)

	a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +
		math.Cos(φ1)*math.Cos(φ2)*
			math.Sin(Δλ/2)*math.Sin(Δλ/2)
	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))

	distance := R * c
	return int32(distance)
}

func inRange(point *pb.Point, rect *pb.Rectangle) bool {
	left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
	right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
	top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
	bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))

	if float64(point.Longitude) >= left &&
		float64(point.Longitude) <= right &&
		float64(point.Latitude) >= bottom &&
		float64(point.Latitude) <= top {
		return true
	}
	return false
}

func serialize(point *pb.Point) string {
	return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)
}

func newServer() *routeGuideServer {
	s := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
	s.loadFeatures(*jsonDBFile)
	return s
}

func main() {
	flag.Parse()
	lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	var opts []grpc.ServerOption
	if *tls {
		if *certFile == "" {
			*certFile = testdata.Path("server1.pem")
		}
		if *keyFile == "" {
			*keyFile = testdata.Path("server1.key")
		}
		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
		if err != nil {
			log.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	grpcServer := grpc.NewServer(opts...)
	pb.RegisterRouteGuideServer(grpcServer, newServer())
	grpcServer.Serve(lis)
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import "tour/pic"

func Pic(dx, dy int) [][]uint8 {
	p := make([][]uint8, dy)
	for i := range p {
		p[i] = make([]uint8, dx)
	}

	for y := range p {
		for x, row := range p[y] {
			row[x] = uint8(x * y)
		}
	}

	return p
}

func main() {
	pic.Show(Pic)
}
<commit_msg>go-tour: Fixing wrong solution for slices exercise. Fixes #50<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import "tour/pic"

func Pic(dx, dy int) [][]uint8 {
	p := make([][]uint8, dy)
	for i := range p {
		p[i] = make([]uint8, dx)
	}

	for y, row := range p {
		for x := range row {
			row[x] = uint8(x * y)
		}
	}

	return p
}

func main() {
	pic.Show(Pic)
}
<|endoftext|>


<commit_before>package publish

import (
	"encoding/json"
	"fmt"
	"os"
	"sync/atomic"
	"time"

	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/antlinker/go-cmap"
	"github.com/antlinker/mqttpersonal/config"

	"gopkg.in/alog.v1"
	"gopkg.in/mgo.v2"
)

// Pub 执行Publish操作
func Pub(cfg *Config) {
	pub := &Publish{
		cfg:             cfg,
		lg:              alog.NewALog(),
		clientIndexData: make(map[string]int),
		clients:         make(map[string]*MQTT.Client),
		disClients:      cmap.NewConcurrencyMap(),
		execComplete:    make(chan bool, 1),
		end:             make(chan bool, 1),
		startTime:       time.Now(),
	}
	pub.lg.SetLogTag("PUBLISH")
	session, err := mgo.Dial(cfg.MongoUrl)
	if err != nil {
		pub.lg.Errorf("数据库连接发生异常:%s", err.Error())
		return
	}
	pub.session = session
	pub.database = session.DB(config.DataBase)
	err = pub.Init()
	if err != nil {
		pub.lg.Error(err)
		return
	}
	pub.ExecPublish()
	<-pub.end
	pub.lg.Info("执行完成.")
	time.Sleep(time.Second * 2)
	os.Exit(0)
}

type Publish struct {
	cfg             *Config
	lg              *alog.ALog
	session         *mgo.Session
	database        *mgo.Database
	clientData      []config.ClientInfo
	clientIndexData map[string]int
	clients         map[string]*MQTT.Client
	disClients      cmap.ConcurrencyMap
	publishID       int64
	execNum         int64
	execComplete    chan bool
	publishTotalNum int64
	publishNum      int64
	prePublishNum   int64
	maxPublishNum   int64
	arrPublishNum   []int64
	receiveTotalNum int64
	receiveNum      int64
	preReceiveNum   int64
	maxReceiveNum   int64
	arrReceiveNum   []int64
	end             chan bool
	startTime       time.Time
}

func (p *Publish) Init() error {
	err := p.initData()
	if err != nil {
		return err
	}
	err = p.initConnection()
	if err != nil {
		return err
	}
	p.lg.Info("初始化操作完成.")
	calcTicker := time.NewTicker(time.Second * 1)
	go p.calcMaxAndMinPacketNum(calcTicker)
	go p.checkComplete()
	prTicker := time.NewTicker(time.Duration(p.cfg.Interval) * time.Second)
	go p.pubAndRecOutput(prTicker)
	return nil
}

func (p *Publish) initData() error {
	p.lg.Info("开始客户端数据初始化...")
	err := p.database.C(config.C_Client).Find(nil).All(&p.clientData)
	if err != nil {
		return fmt.Errorf("初始化客户端数据发生异常:%s", err.Error())
	}
	for i := 0; i < len(p.clientData); i++ {
		client := p.clientData[i]
		p.clientIndexData[client.ClientID] = i
	}
	p.lg.Info("客户端数据初始化完成.")
	return nil
}

func (p *Publish) initConnection() error {
	p.lg.Info("开始建立MQTT数据连接初始化...")
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		clientID := clientInfo.ClientID
		opts := MQTT.NewClientOptions()
		opts.AddBroker(fmt.Sprintf("%s://%s", p.cfg.Network, p.cfg.Address))
		opts.SetClientID(clientID)
		opts.SetStore(MQTT.NewMemoryStore())
		opts.SetProtocolVersion(4)
		autoReconnect := true
		if v := p.cfg.DisconnectScale; v > 0 {
			autoReconnect = false
		}
		opts.SetAutoReconnect(autoReconnect)
		if name, pwd := p.cfg.UserName, p.cfg.Password; name != "" && pwd != "" {
			opts.SetUsername(name)
			opts.SetPassword(pwd)
		}
		if v := p.cfg.KeepAlive; v > 0 {
			opts.SetKeepAlive(time.Duration(v))
		}
		if v := p.cfg.CleanSession; v {
			opts.SetCleanSession(v)
		}
		clientHandle := NewHandleConnect(clientID, p)
		opts.SetConnectionLostHandler(func(cli *MQTT.Client, err error) {
			clientHandle.ErrorHandle(err)
		})
		cli := MQTT.NewClient(opts)
		connectToken := cli.Connect()
		if connectToken.Wait() && connectToken.Error() != nil {
			return fmt.Errorf("客户端[%s]建立连接发生异常:%s", clientID, connectToken.Error().Error())
		}
		topic := "C/" + clientID
		subToken := cli.Subscribe(topic, p.cfg.Qos, func(cli *MQTT.Client, msg MQTT.Message) {
			clientHandle.Subscribe([]byte(msg.Topic()), msg.Payload())
		})
		if subToken.Wait() && subToken.Error() != nil {
			return fmt.Errorf("客户端[%s]订阅主题发生异常:%s", clientID, subToken.Error().Error())
		}
		p.clients[clientID] = cli
	}
	p.lg.Info("MQTT数据连接初始化完成.")
	return nil
}

func (p *Publish) checkComplete() {
	<-p.execComplete
	go func() {
		ticker := time.NewTicker(time.Millisecond * 500)
		for range ticker.C {
			if p.receiveNum == p.receiveTotalNum {
				ticker.Stop()
				p.end <- true
			}
		}
	}()
}

func (p *Publish) calcMaxAndMinPacketNum(ticker *time.Ticker) {
	for range ticker.C {
		pubNum := p.publishNum
		recNum := p.receiveNum
		pNum := pubNum - p.prePublishNum
		rNum := recNum - p.preReceiveNum
		if pNum > p.maxPublishNum {
			p.maxPublishNum = pNum
		}
		p.arrPublishNum = append(p.arrPublishNum, pNum)
		if rNum > p.maxReceiveNum {
			p.maxReceiveNum = rNum
		}
		p.arrReceiveNum = append(p.arrReceiveNum, rNum)
		p.prePublishNum = pubNum
		p.preReceiveNum = recNum
	}
}

func (p *Publish) pubAndRecOutput(ticker *time.Ticker) {
	for ct := range ticker.C {
		currentSecond := float64(ct.Sub(p.startTime)) / float64(time.Second)
		var psNum int64
		arrPNum := p.arrPublishNum
		for i := 0; i < len(arrPNum); i++ {
			psNum += arrPNum[i]
		}
		avgPNum := psNum / int64(len(arrPNum))
		var rsNum int64
		arrRNum := p.arrReceiveNum
		for i := 0; i < len(arrRNum); i++ {
			rsNum += arrRNum[i]
		}
		avgRNum := rsNum / int64(len(arrRNum))
		clientNum := len(p.clients) - p.disClients.Len()
		output := `
总耗时                      %.2fs
执行次数                    %d
客户端数量                  %d
应发包量                    %d
实际发包量                  %d
每秒平均的发包量            %d
每秒最大的发包量            %d
应收包量                    %d
实际收包量                  %d
每秒平均的接包量            %d
每秒最大的接包量            %d`

		fmt.Printf(output,
			currentSecond, p.execNum, clientNum, p.publishTotalNum, p.publishNum, avgPNum, p.maxPublishNum, p.receiveTotalNum, p.receiveNum, avgRNum, p.maxReceiveNum)
		fmt.Printf("\n")
	}
}

func (p *Publish) ExecPublish() {
	time.AfterFunc(time.Duration(p.cfg.Interval)*time.Second, func() {
		if p.execNum == int64(p.cfg.ExecNum) {
			p.lg.Info("发布已执行完成，等待接收订阅...")
			p.disconnect()
			p.execComplete <- true
			return
		}
		atomic.AddInt64(&p.execNum, 1)
		p.publish()
		p.ExecPublish()
	})
}

func (p *Publish) disconnect() {
	if v := p.cfg.DisconnectScale; v > 100 || v <= 0 {
		return
	}
	clientCount := len(p.clients)
	disCount := int(float32(clientCount) * (float32(p.cfg.DisconnectScale) / 100))
	for k, v := range p.clients {
		exist, _ := p.disClients.Contains(k)
		if exist {
			continue
		}
		v.Disconnect(100)
		disCount--
		if disCount == 0 {
			break
		}
	}
}

func (p *Publish) publish() {
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		v, _ := p.disClients.Contains(clientInfo.ClientID)
		if v {
			continue
		}
		pNum := len(clientInfo.Relations)
		p.publishTotalNum += int64(pNum)
		p.receiveTotalNum += int64(pNum)
		go p.userPublish(clientInfo)
	}
}

func (p *Publish) userPublish(clientInfo config.ClientInfo) {
	cli := p.clients[clientInfo.ClientID]
	for j := 0; j < len(clientInfo.Relations); j++ {
		cTime := time.Now()
		sendPacket := config.PacketInfo{
			ID:        fmt.Sprintf("%d_%d", cTime.Unix(), atomic.AddInt64(&p.publishID, 1)),
			SendID:    clientInfo.ClientID,
			ReceiveID: clientInfo.Relations[j],
			SendTime:  cTime,
		}
		if p.cfg.IsStore {
			err := p.database.C(config.C_Packet).Insert(sendPacket)
			if err != nil {
				p.lg.Errorf("Publish store error:%s", err.Error())
			}
		}
		bufData, err := json.Marshal(sendPacket)
		if err != nil {
			p.lg.Errorf("Publish json marshal error:%s", err.Error())
			continue
		}
		topic := "C/" + clientInfo.Relations[j]
		publishToken := cli.Publish(topic, p.cfg.Qos, false, bufData)
		if publishToken.Wait() && publishToken.Error() != nil {
			p.lg.Errorf("客户端[%s]发布消息出现异常:%s", clientInfo.ClientID, publishToken.Error().Error())
			continue
		}
		atomic.AddInt64(&p.publishNum, 1)
		// 好友之间的发包间隔
		if v := p.cfg.UserInterval; v > 0 {
			time.Sleep(time.Duration(v) * time.Millisecond)
		}
	}
}
<commit_msg>修复保持心跳bug<commit_after>package publish

import (
	"encoding/json"
	"fmt"
	"os"
	"sync/atomic"
	"time"

	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/antlinker/go-cmap"
	"github.com/antlinker/mqttpersonal/config"

	"gopkg.in/alog.v1"
	"gopkg.in/mgo.v2"
)

// Pub 执行Publish操作
func Pub(cfg *Config) {
	pub := &Publish{
		cfg:             cfg,
		lg:              alog.NewALog(),
		clientIndexData: make(map[string]int),
		clients:         make(map[string]*MQTT.Client),
		disClients:      cmap.NewConcurrencyMap(),
		execComplete:    make(chan bool, 1),
		end:             make(chan bool, 1),
		startTime:       time.Now(),
	}
	pub.lg.SetLogTag("PUBLISH")
	session, err := mgo.Dial(cfg.MongoUrl)
	if err != nil {
		pub.lg.Errorf("数据库连接发生异常:%s", err.Error())
		return
	}
	pub.session = session
	pub.database = session.DB(config.DataBase)
	err = pub.Init()
	if err != nil {
		pub.lg.Error(err)
		return
	}
	pub.ExecPublish()
	<-pub.end
	pub.lg.Info("执行完成.")
	time.Sleep(time.Second * 2)
	os.Exit(0)
}

type Publish struct {
	cfg             *Config
	lg              *alog.ALog
	session         *mgo.Session
	database        *mgo.Database
	clientData      []config.ClientInfo
	clientIndexData map[string]int
	clients         map[string]*MQTT.Client
	disClients      cmap.ConcurrencyMap
	publishID       int64
	execNum         int64
	execComplete    chan bool
	publishTotalNum int64
	publishNum      int64
	prePublishNum   int64
	maxPublishNum   int64
	arrPublishNum   []int64
	receiveTotalNum int64
	receiveNum      int64
	preReceiveNum   int64
	maxReceiveNum   int64
	arrReceiveNum   []int64
	end             chan bool
	startTime       time.Time
}

func (p *Publish) Init() error {
	err := p.initData()
	if err != nil {
		return err
	}
	err = p.initConnection()
	if err != nil {
		return err
	}
	p.lg.Info("初始化操作完成.")
	calcTicker := time.NewTicker(time.Second * 1)
	go p.calcMaxAndMinPacketNum(calcTicker)
	go p.checkComplete()
	prTicker := time.NewTicker(time.Duration(p.cfg.Interval) * time.Second)
	go p.pubAndRecOutput(prTicker)
	return nil
}

func (p *Publish) initData() error {
	p.lg.Info("开始客户端数据初始化...")
	err := p.database.C(config.C_Client).Find(nil).All(&p.clientData)
	if err != nil {
		return fmt.Errorf("初始化客户端数据发生异常:%s", err.Error())
	}
	for i := 0; i < len(p.clientData); i++ {
		client := p.clientData[i]
		p.clientIndexData[client.ClientID] = i
	}
	p.lg.Info("客户端数据初始化完成.")
	return nil
}

func (p *Publish) initConnection() error {
	p.lg.Info("开始建立MQTT数据连接初始化...")
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		clientID := clientInfo.ClientID
		opts := MQTT.NewClientOptions()
		opts.AddBroker(fmt.Sprintf("%s://%s", p.cfg.Network, p.cfg.Address))
		opts.SetClientID(clientID)
		opts.SetStore(MQTT.NewMemoryStore())
		opts.SetProtocolVersion(4)
		autoReconnect := true
		if v := p.cfg.DisconnectScale; v > 0 {
			autoReconnect = false
		}
		opts.SetAutoReconnect(autoReconnect)
		if name, pwd := p.cfg.UserName, p.cfg.Password; name != "" && pwd != "" {
			opts.SetUsername(name)
			opts.SetPassword(pwd)
		}
		if v := p.cfg.KeepAlive; v > 0 {
			opts.SetKeepAlive(time.Duration(v) * time.Second)
		}
		if v := p.cfg.CleanSession; v {
			opts.SetCleanSession(v)
		}
		clientHandle := NewHandleConnect(clientID, p)
		opts.SetConnectionLostHandler(func(cli *MQTT.Client, err error) {
			clientHandle.ErrorHandle(err)
		})
		cli := MQTT.NewClient(opts)
		connectToken := cli.Connect()
		if connectToken.Wait() && connectToken.Error() != nil {
			return fmt.Errorf("客户端[%s]建立连接发生异常:%s", clientID, connectToken.Error().Error())
		}
		topic := "C/" + clientID
		subToken := cli.Subscribe(topic, p.cfg.Qos, func(cli *MQTT.Client, msg MQTT.Message) {
			clientHandle.Subscribe([]byte(msg.Topic()), msg.Payload())
		})
		if subToken.Wait() && subToken.Error() != nil {
			return fmt.Errorf("客户端[%s]订阅主题发生异常:%s", clientID, subToken.Error().Error())
		}
		p.clients[clientID] = cli
	}
	p.lg.Info("MQTT数据连接初始化完成.")
	return nil
}

func (p *Publish) checkComplete() {
	<-p.execComplete
	go func() {
		ticker := time.NewTicker(time.Millisecond * 500)
		for range ticker.C {
			if p.receiveNum == p.receiveTotalNum {
				ticker.Stop()
				p.end <- true
			}
		}
	}()
}

func (p *Publish) calcMaxAndMinPacketNum(ticker *time.Ticker) {
	for range ticker.C {
		pubNum := p.publishNum
		recNum := p.receiveNum
		pNum := pubNum - p.prePublishNum
		rNum := recNum - p.preReceiveNum
		if pNum > p.maxPublishNum {
			p.maxPublishNum = pNum
		}
		p.arrPublishNum = append(p.arrPublishNum, pNum)
		if rNum > p.maxReceiveNum {
			p.maxReceiveNum = rNum
		}
		p.arrReceiveNum = append(p.arrReceiveNum, rNum)
		p.prePublishNum = pubNum
		p.preReceiveNum = recNum
	}
}

func (p *Publish) pubAndRecOutput(ticker *time.Ticker) {
	for ct := range ticker.C {
		currentSecond := float64(ct.Sub(p.startTime)) / float64(time.Second)
		var psNum int64
		arrPNum := p.arrPublishNum
		if len(arrPNum) == 0 {
			continue
		}
		for i := 0; i < len(arrPNum); i++ {
			psNum += arrPNum[i]
		}
		avgPNum := psNum / int64(len(arrPNum))
		var rsNum int64
		arrRNum := p.arrReceiveNum
		for i := 0; i < len(arrRNum); i++ {
			rsNum += arrRNum[i]
		}
		avgRNum := rsNum / int64(len(arrRNum))
		clientNum := len(p.clients) - p.disClients.Len()
		output := `
总耗时                      %.2fs
执行次数                    %d
客户端数量                  %d
应发包量                    %d
实际发包量                  %d
每秒平均的发包量            %d
每秒最大的发包量            %d
应收包量                    %d
实际收包量                  %d
每秒平均的接包量            %d
每秒最大的接包量            %d`

		fmt.Printf(output,
			currentSecond, p.execNum, clientNum, p.publishTotalNum, p.publishNum, avgPNum, p.maxPublishNum, p.receiveTotalNum, p.receiveNum, avgRNum, p.maxReceiveNum)
		fmt.Printf("\n")
	}
}

func (p *Publish) ExecPublish() {
	time.AfterFunc(time.Duration(p.cfg.Interval)*time.Second, func() {
		if p.execNum == int64(p.cfg.ExecNum) {
			p.lg.Info("发布已执行完成，等待接收订阅...")
			p.disconnect()
			p.execComplete <- true
			return
		}
		atomic.AddInt64(&p.execNum, 1)
		p.publish()
		p.ExecPublish()
	})
}

func (p *Publish) disconnect() {
	if v := p.cfg.DisconnectScale; v > 100 || v <= 0 {
		return
	}
	clientCount := len(p.clients)
	disCount := int(float32(clientCount) * (float32(p.cfg.DisconnectScale) / 100))
	for k, v := range p.clients {
		exist, _ := p.disClients.Contains(k)
		if exist {
			continue
		}
		v.Disconnect(100)
		disCount--
		if disCount == 0 {
			break
		}
	}
}

func (p *Publish) publish() {
	for i, l := 0, len(p.clientData); i < l; i++ {
		clientInfo := p.clientData[i]
		v, _ := p.disClients.Contains(clientInfo.ClientID)
		if v {
			continue
		}
		pNum := len(clientInfo.Relations)
		p.publishTotalNum += int64(pNum)
		p.receiveTotalNum += int64(pNum)
		go p.userPublish(clientInfo)
	}
}

func (p *Publish) userPublish(clientInfo config.ClientInfo) {
	cli := p.clients[clientInfo.ClientID]
	for j := 0; j < len(clientInfo.Relations); j++ {
		cTime := time.Now()
		sendPacket := config.PacketInfo{
			ID:        fmt.Sprintf("%d_%d", cTime.Unix(), atomic.AddInt64(&p.publishID, 1)),
			SendID:    clientInfo.ClientID,
			ReceiveID: clientInfo.Relations[j],
			SendTime:  cTime,
		}
		if p.cfg.IsStore {
			err := p.database.C(config.C_Packet).Insert(sendPacket)
			if err != nil {
				p.lg.Errorf("Publish store error:%s", err.Error())
			}
		}
		bufData, err := json.Marshal(sendPacket)
		if err != nil {
			p.lg.Errorf("Publish json marshal error:%s", err.Error())
			continue
		}
		topic := "C/" + clientInfo.Relations[j]
		publishToken := cli.Publish(topic, p.cfg.Qos, false, bufData)
		if publishToken.Wait() && publishToken.Error() != nil {
			p.lg.Errorf("客户端[%s]发布消息出现异常:%s", clientInfo.ClientID, publishToken.Error().Error())
			continue
		}
		atomic.AddInt64(&p.publishNum, 1)
		// 好友之间的发包间隔
		if v := p.cfg.UserInterval; v > 0 {
			time.Sleep(time.Duration(v) * time.Millisecond)
		}
	}
}
<|endoftext|>


<commit_before>package fuse

import (
	"os"

	"github.com/docker/docker/daemon/graphdriver/overlay"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/graph"

	log "github.com/Sirupsen/logrus"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

const (
	Name          = "fuse"
	Type          = api.Graph
	FuseDBKey     = "OpenStorageBuseKey"
	FuseMountPath = "/var/lib/openstorage/fuse/"
)

// FS implements the graph file system.
type FS struct{}

func (FS) Root() (fs.Node, error) {
	return Dir{}, nil
}

// Dir implements both Node and Handle for the root directory.
type Dir struct{}

func (Dir) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Inode = 1
	a.Mode = os.ModeDir | 0555
	return nil
}

func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	if name == "hello" {
		return File{}, nil
	}
	return nil, fuse.ENOENT
}

var dirDirs = []fuse.Dirent{
	{Inode: 2, Name: "hello", Type: fuse.DT_File},
}

func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	return dirDirs, nil
}

// File implements both Node and Handle for the hello file.
type File struct{}

const greeting = "hello, world\n"

func (File) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Inode = 2
	a.Mode = 0444
	a.Size = uint64(len(greeting))
	return nil
}

func (File) ReadAll(ctx context.Context) ([]byte, error) {
	return []byte(greeting), nil
}

func init() {
	log.Infof("Initializing Fuse Graph driver.")

	graph.Register("fuse", overlay.Init)

	c, err := fuse.Mount(
		FuseMountPath,
		fuse.FSName("openstorage"),
		fuse.Subtype("openstoragefs"),
		fuse.LocalVolume(),
		fuse.VolumeName("Open Storage"),
	)

	if err != nil {
		log.Warnf("Error while loading FUSE.  FUSE will not be available as a Graph driver on this system.  Error: %v", err)
		return
	}

	defer c.Close()

	err = fs.Serve(c, FS{})
	if err != nil {
		log.Fatal(err)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}
<commit_msg>create fuse path if it does not already exist<commit_after>package fuse

import (
	"os"

	"github.com/docker/docker/daemon/graphdriver/overlay"
	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/graph"

	log "github.com/Sirupsen/logrus"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)

const (
	Name          = "fuse"
	Type          = api.Graph
	fuseMountPath = "/var/lib/openstorage/fuse/"
)

// FS implements the graph file system.
type FS struct{}

func (FS) Root() (fs.Node, error) {
	return Dir{}, nil
}

// Dir implements both Node and Handle for the root directory.
type Dir struct{}

func (Dir) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Inode = 1
	a.Mode = os.ModeDir | 0555
	return nil
}

func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	if name == "hello" {
		return File{}, nil
	}
	return nil, fuse.ENOENT
}

var dirDirs = []fuse.Dirent{
	{Inode: 2, Name: "hello", Type: fuse.DT_File},
}

func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	return dirDirs, nil
}

// File implements both Node and Handle for the hello file.
type File struct{}

const greeting = "hello, world\n"

func (File) Attr(ctx context.Context, a *fuse.Attr) error {
	a.Inode = 2
	a.Mode = 0444
	a.Size = uint64(len(greeting))
	return nil
}

func (File) ReadAll(ctx context.Context) ([]byte, error) {
	return []byte(greeting), nil
}

func init() {
	log.Infof("Initializing Fuse Graph driver.")

	graph.Register("fuse", overlay.Init)

	// XXX move this to Init()

	err := os.MkdirAll(fuseMountPath, 0744)
	if err != nil {
		log.Fatal("Error while creating FUSE mount path: %v", err)
	}

	c, err := fuse.Mount(
		fuseMountPath,
		fuse.FSName("openstorage"),
		fuse.Subtype("openstoragefs"),
		fuse.LocalVolume(),
		fuse.VolumeName("Open Storage"),
	)

	if err != nil {
		log.Warnf("Error while loading FUSE.  FUSE will not be available as a Graph driver on this system.  Error: %v", err)
		return
	}

	defer c.Close()

	err = fs.Serve(c, FS{})
	if err != nil {
		log.Fatal(err)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package gotojs

// Conatins all loaded templates and references to external JS libraries.
type Templates struct {
	Binding,Interface,Method string
	Libraries []string
}

// DefaultTemplates returns the collection of internal Javascript templates for the generation of the JS engine.
func DefaultTemplates() *Templates {
	return &defaultTemplates
}

var defaultTemplates = Templates {
	Binding: `
/* #### JS/BINDING #### */
var {{.NS}} = {{.NS}} || {
	'TYPES': {
		'INTERFACES': {/* will be filled by interface templates */},
		'Proxy': function () {
			/* Attributes */
			this.callCounter = 0;
		}
	},
	'CONST': {
		'ALPHA':"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	},
	'HELPER': {
		createCHASH: function makeid() {
			var ret = "";
			for( var i=0; i < 10; i++ )
				ret += {{.NS}}.CONST.ALPHA.charAt(Math.floor(Math.random() * {{.NS}}.CONST.ALPHA.length));
			return ret.toUpperCase();
		}
	}
}

{{.NS}}.CONST.CHASH = {{.NS}}.HELPER.createCHASH()

{{.NS}}.TYPES.Proxy.prototype = {
	/*Methods */
	constructor: {{.NS}}.Proxy,
	call: function(i,m,args) {
{{if .BU}}
		var url ="{{.BU}}/"+i+"/"+m;

{{else}}
		var url ="{{.BC}}/"+i+"/"+m;
{{end}}
		var callback = undefined;
		if (this.hasCallback(args)) {
			callback = args.pop();
		}

		var crid = {{.NS}}.CONST.CHASH + "." + (this.callCounter++);
		var data = JSON.stringify({
			'Interface': i,
		    	'Method': m,
		    	'CRID': crid,
		    	'Data': args
		});
		var ret;
                $.ajax( {
                        type: 'POST',
                        url: url,
                        data: data,
                        success: function(d) {
				if (typeof(d) =='string') {
                                        ret = eval('(' + d + ')');
                                } else {
                                        ret = d;
                                }
				if (ret['Data'] && ret['CRID'] == crid) {
					ret = ret['Data']
					if (callback) {
						callback(ret);
					}
				} else {
					throw ("IFAIL["+crid+"] \"" + i + "." + m + "(" + args.join(",")+")\" @ " + url + ":\n" + data + "\n=>" + ret);
				}
                        },
			async: callback !== undefined,
                	error: function(o,estring,e) {
				throw /*console.log*/("FAIL : \"" + i + "." + m + "(" + args.join(",")+")\" @ " + url + ":\n" + data + "\n=>" + e);
			}
		});
		return ret;
	},
	hasCallback: function(args) {
		return (typeof args[args.length-1] == 'function')
	},
	argsToArray: function(ao) {
		var ret = [];
		for (var i in ao) {
			ret.push(ao[i]);
		}
		return ret;
	}{{if .MA}},
	assertArgs: function(i,m,args,as) {
		var al = args.length;
		var sl = as.length;
		/* Argument count either matchs or last argument is a callback function. */
		if (!((al == sl) ||  ((al-1 == sl) && this.hasCallback(args)))) {
			throw "Invalid argument count (" + al + ") for method \""+i+"." + m + "("+as+")";
		}

		for (var idx in as) {
			var o = args[idx];
			var mes = "Argument #" + (idx+1) + " of method \""+i+"." + m + "("+as+")\" is expected to be ";
			if (o === undefined) {
				throw mes + " not equal UNDEFINED.";
			}

			switch (as[idx]) {
				case 'a':
					if (!o instanceof Array) {
						throw mes+ "an Array.";
					}
					break;
				case 'o':
				case 'm':
					if (!o instanceof Object) {
						throw mes + "an object/struct/map.";

					}
					break;
				case 's':
					if (!o instanceof String) {
						throw mes + "a string.";
					}
					break;
				case 'i':
					if (!(typeof o === 'number' && o % 1 == 0)) {

						throw mes + "an integer.";
					}
					break;
				case 'f':
					if (!(typeof o === 'number' && !( o & 1 == 0))) {
						throw mes + "an float.";
					}
					break;
				default:
					throw "Invalid argument definition string: " + as;
			}
		}
	}{{end}}
};
`,
	Interface: `
/* #### JS/INTERFACE #### */
{{.NS}}.TYPES.INTERFACES = {
	{{.IN}}: function() {
		/* Attributes */
		this.name = "{{.IN}}";
		this.proxy = new {{.NS}}.TYPES.Proxy();
	}
}
{{.NS}}.TYPES.INTERFACES.{{.IN}}.prototype = {
	/* Methods */
	call: function(m,args) {
		return this.proxy.call(this.name,m,args);
	}
};
{{.NS}}.{{.IN}} = new {{.NS}}.TYPES.INTERFACES.{{.IN}}()
`,
	Method: `
/* #### JS/METHOD #### */
{{.NS}}.{{.IN}}.{{.MN}} = function() {
	var args = this.proxy.argsToArray(arguments);
{{if .MA}}
	this.proxy.assertArgs("{{.IN}}","{{.MN}}",args,"{{.AS}}");
{{end}}
	return this.call("{{.MN}}",args);
};
`,
	Libraries: []string{"http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"}}
<commit_msg>Fixed contructor reference for proxy engine.<commit_after>package gotojs

// Conatins all loaded templates and references to external JS libraries.
type Templates struct {
	Binding,Interface,Method string
	Libraries []string
}

// DefaultTemplates returns the collection of internal Javascript templates for the generation of the JS engine.
func DefaultTemplates() *Templates {
	return &defaultTemplates
}

var defaultTemplates = Templates {
	Binding: `
/* #### JS/BINDING #### */
var {{.NS}} = {{.NS}} || {
	'TYPES': {
		'INTERFACES': {/* will be filled by interface templates */},
		'Proxy': function () {
			/* Attributes */
			this.callCounter = 0;
		}
	},
	'CONST': {
		'ALPHA':"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	},
	'HELPER': {
		createCHASH: function makeid() {
			var ret = "";
			for( var i=0; i < 10; i++ )
				ret += {{.NS}}.CONST.ALPHA.charAt(Math.floor(Math.random() * {{.NS}}.CONST.ALPHA.length));
			return ret.toUpperCase();
		}
	}
}

{{.NS}}.CONST.CHASH = {{.NS}}.HELPER.createCHASH()

{{.NS}}.TYPES.Proxy.prototype = {
	/*Methods */
	constructor: {{.NS}}.TYPES.Proxy,
	call: function(i,m,args) {
{{if .BU}}
		var url ="{{.BU}}/"+i+"/"+m;

{{else}}
		var url ="{{.BC}}/"+i+"/"+m;
{{end}}
		var callback = undefined;
		if (this.hasCallback(args)) {
			callback = args.pop();
		}

		var crid = {{.NS}}.CONST.CHASH + "." + (this.callCounter++);
		var data = JSON.stringify({
			'Interface': i,
		    	'Method': m,
		    	'CRID': crid,
		    	'Data': args
		});
		var ret;
                $.ajax( {
                        type: 'POST',
                        url: url,
                        data: data,
                        success: function(d) {
				if (typeof(d) =='string') {
                                        ret = eval('(' + d + ')');
                                } else {
                                        ret = d;
                                }
				if (ret['Data'] && ret['CRID'] == crid) {
					ret = ret['Data']
					if (callback) {
						callback(ret);
					}
				} else {
					throw ("IFAIL["+crid+"] \"" + i + "." + m + "(" + args.join(",")+")\" @ " + url + ":\n" + data + "\n=>" + ret);
				}
                        },
			async: callback !== undefined,
                	error: function(o,estring,e) {
				throw /*console.log*/("FAIL : \"" + i + "." + m + "(" + args.join(",")+")\" @ " + url + ":\n" + data + "\n=>" + e);
			}
		});
		return ret;
	},
	hasCallback: function(args) {
		return (typeof args[args.length-1] == 'function')
	},
	argsToArray: function(ao) {
		var ret = [];
		for (var i in ao) {
			ret.push(ao[i]);
		}
		return ret;
	}{{if .MA}},
	assertArgs: function(i,m,args,as) {
		var al = args.length;
		var sl = as.length;
		/* Argument count either matchs or last argument is a callback function. */
		if (!((al == sl) ||  ((al-1 == sl) && this.hasCallback(args)))) {
			throw "Invalid argument count (" + al + ") for method \""+i+"." + m + "("+as+")";
		}

		for (var idx in as) {
			var o = args[idx];
			var mes = "Argument #" + (idx+1) + " of method \""+i+"." + m + "("+as+")\" is expected to be ";
			if (o === undefined) {
				throw mes + " not equal UNDEFINED.";
			}

			switch (as[idx]) {
				case 'a':
					if (!o instanceof Array) {
						throw mes+ "an Array.";
					}
					break;
				case 'o':
				case 'm':
					if (!o instanceof Object) {
						throw mes + "an object/struct/map.";

					}
					break;
				case 's':
					if (!o instanceof String) {
						throw mes + "a string.";
					}
					break;
				case 'i':
					if (!(typeof o === 'number' && o % 1 == 0)) {

						throw mes + "an integer.";
					}
					break;
				case 'f':
					if (!(typeof o === 'number' && !( o & 1 == 0))) {
						throw mes + "an float.";
					}
					break;
				default:
					throw "Invalid argument definition string: " + as;
			}
		}
	}{{end}}
};
`,
	Interface: `
/* #### JS/INTERFACE #### */
{{.NS}}.TYPES.INTERFACES = {
	{{.IN}}: function() {
		/* Attributes */
		this.name = "{{.IN}}";
		this.proxy = new {{.NS}}.TYPES.Proxy();
	}
}
{{.NS}}.TYPES.INTERFACES.{{.IN}}.prototype = {
	/* Methods */
	call: function(m,args) {
		return this.proxy.call(this.name,m,args);
	}
};
{{.NS}}.{{.IN}} = new {{.NS}}.TYPES.INTERFACES.{{.IN}}()
`,
	Method: `
/* #### JS/METHOD #### */
{{.NS}}.{{.IN}}.{{.MN}} = function() {
	var args = this.proxy.argsToArray(arguments);
{{if .MA}}
	this.proxy.assertArgs("{{.IN}}","{{.MN}}",args,"{{.AS}}");
{{end}}
	return this.call("{{.MN}}",args);
};
`,
	Libraries: []string{"http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"}}
<|endoftext|>


<commit_before>// Package colorize returns an ascii colorized string version of an input string
//
// Here is a table of ASCII to color values:
//
//     Intensity   0       1      2       3       4       5       6       7
//     Normal      Black   Red    Green   Yellow  Blue    Magenta Cyan    White
//     Bright      Black   Red    Green   Yellow  Blue    Magenta Cyan    White
//
// Table sourced from: http://en.wikipedia.org/wiki/ANSI_escape_code
//
package colorize

import (
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-isatty"
)

// colorToValueMap can convert the string values of an input ASCII
// color to its appropriate integer counterpart. See table above for
// mapping information
var colorToValueMap = map[string]int{
	"black":   0,
	"red":     1,
	"green":   2,
	"yellow":  3,
	"blue":    4,
	"magenta": 5,
	"cyan":    6,
	"white":   7,
}

// DisableColor sets the coloring option off. This automatically is set for
// dumb terminals, and can optionally be set at the module level for CLI
// apps that may support an option like `--no-color`.
var DisableColor = os.Getenv("TERM") == "dumb" ||
	(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))

// ColorString is a function which returns the "input" string after surrounding
// it by the appropriate ASCII escape sequence for the requested "color".
// If the "color" input is not a member of the map, we simply return
// the input without any change
func ColorString(input, color string) string {
	color = strings.ToLower(color)
	if colorIndex, valid := colorToValueMap[color]; valid {
		return fmt.Sprintf("\033[3%dm%s\033[0m", colorIndex, input)
	}
	return input
}

// Colorize is a function whichtakes in a string embedded with
// "<color>...</color>" tags. Any un-matched tags will be ignored and not
// stripped from the input string
func Colorize(input string) string {
	for color, index := range colorToValueMap {
		var (
			searchString  = fmt.Sprintf("(<%s>)(.*?)(</%s>)", color, color)
			replaceString = fmt.Sprintf("\033[3%dm$2\033[0m", index)
			match         = regexp.MustCompile(searchString)
		)
		input = match.ReplaceAllString(input, replaceString)
	}
	return input
}
<commit_msg>actually honor `DisableColor` option<commit_after>// Package colorize returns an ascii colorized string version of an input string
//
// Here is a table of ASCII to color values:
//
//     Intensity   0       1      2       3       4       5       6       7
//     Normal      Black   Red    Green   Yellow  Blue    Magenta Cyan    White
//     Bright      Black   Red    Green   Yellow  Blue    Magenta Cyan    White
//
// Table sourced from: http://en.wikipedia.org/wiki/ANSI_escape_code
//
package colorize

import (
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-isatty"
)

// colorToValueMap can convert the string values of an input ASCII
// color to its appropriate integer counterpart. See table above for
// mapping information
var colorToValueMap = map[string]int{
	"black":   0,
	"red":     1,
	"green":   2,
	"yellow":  3,
	"blue":    4,
	"magenta": 5,
	"cyan":    6,
	"white":   7,
}

// DisableColor sets the coloring option off. This automatically is set for
// dumb terminals, and can optionally be set at the module level for CLI
// apps that may support an option like `--no-color`.
var DisableColor = os.Getenv("TERM") == "dumb" ||
	(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))

// ColorString is a function which returns the "input" string after surrounding
// it by the appropriate ASCII escape sequence for the requested "color".
// If the "color" input is not a member of the map, we simply return
// the input without any change
func ColorString(input, color string) string {
	if DisableColor {
		return input
	}

	color = strings.ToLower(color)
	if colorIndex, valid := colorToValueMap[color]; valid {
		return fmt.Sprintf("\033[3%dm%s\033[0m", colorIndex, input)
	}

	return input
}

// Colorize is a function whichtakes in a string embedded with
// "<color>...</color>" tags. Any un-matched tags will be ignored and not
// stripped from the input string
func Colorize(input string) string {
	for color, index := range colorToValueMap {
		var (
			searchString  = fmt.Sprintf("(<%s>)(.*?)(</%s>)", color, color)
			replaceString = fmt.Sprintf("\033[3%dm$2\033[0m", index)
			match         = regexp.MustCompile(searchString)
		)
		if DisableColor {
			replaceString = "$2"
		}
		input = match.ReplaceAllString(input, replaceString)
	}
	return input
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"golang.org/x/oauth2"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"regexp"
	"strings"
)

var DefaultFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "data",
		Usage: "Body data",
	},
}

var Commands = []cli.Command{
	commandGet,
	commandPost,
	commandPut,
	commandDelete,
	commandHead,
	commandOptions,
	commandPatch,
	commandTrace,
}

var commandGet = cli.Command{
	Name:      "get",
	ShortName: "g",
	Usage:     "Make GET request",
	Description: `
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doGet,
}

var commandPost = cli.Command{
	Name:      "post",
	ShortName: "p",
	Usage:     "Make POST request",
	Description: `
The POST method is used to request that the origin server accept the entity enclosed in the request
as a new subordinate of the resource identified by the Request-URI in the Request-Line.
`,
	Flags:  DefaultFlags,
	Action: doPost,
}

var commandPut = cli.Command{
	Name:  "put",
	Usage: "Make PUT request",
	Description: `
The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPut,
}

var commandDelete = cli.Command{
	Name:      "delete",
	ShortName: "d",
	Usage:     "Make DELETE request",
	Description: `
The DELETE method requests that the origin server delete the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doDelete,
}

var commandHead = cli.Command{
	Name:      "head",
	ShortName: "h",
	Usage:     "Make HEAD request",
	Description: `
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
`,
	Flags:  DefaultFlags,
	Action: doHead,
}

var commandOptions = cli.Command{
	Name:      "options",
	ShortName: "o",
	Usage:     "Make OPTIONS request",
	Description: `
The OPTIONS method represents a request for information about the communication options available
on the request/response chain identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doOptions,
}

var commandPatch = cli.Command{
	Name:  "patch",
	Usage: "Make PATCH request",
	Description: `
The PATCH method requests that a set of changes described in the request entity be applied
to the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPatch,
}

var commandTrace = cli.Command{
	Name:      "trace",
	ShortName: "t",
	Usage:     "Make TRACE request",
	Description: `
The TRACE method is used to invoke a remote, application-layer loop-back of the request message.
`,
	Flags:  DefaultFlags,
	Action: doTrace,
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func doGet(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "GET")
}

func doPost(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "POST")
}

func doPut(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "POST")
}

func doDelete(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "DELETE")
}

func doHead(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "HEAD")
}

func doOptions(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "OPTIONS")
}

func doPatch(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PATCH")
}

func doTrace(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "TRACE")
}

func loadOptions(ctx *cli.Context) {
	var err error
	CurrentOptions, err = Opts(ctx)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
}

func doRequest(ctx *cli.Context, method string) {
	var tr = &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: ctx.GlobalBool("insecure"),
		},
	}
	http.DefaultClient = &http.Client{Transport: tr}

	Tracef("doRequest start")
	resp, tok, err := doRequest0(ctx, method)
	if tok != nil && resp != nil && resp.StatusCode != 401 && resp.StatusCode != 403 {
		storeToken(tok)
	}
	if err != nil {
		log.Fatal(err)
		return
	} else {
		Tracef("request done successfully")
	}

	Tracef("printing headers")
	if ctx.GlobalBool("print-headers") {
		headers, _ := json.Marshal(resp.Header)
		fmt.Println(string(headers))
	}

	if ctx.GlobalBool("no-body") {
		Tracef("printing body is disabled")
	} else {
		Tracef("printing body")
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			Tracef("error on read: %v", err)
		} else if body == nil {
			Tracef("no body")
		} else {
			Tracef("body found")
			fmt.Println(string(body))
		}
	}
	Tracef("doRequest end")
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func doRequest0(ctx *cli.Context, method string) (*http.Response, *oauth2.Token, error) {
	Tracef("profileName = %s", CurrentOptions.ProfileName)

	targetUrl, err := targetUrl(ctx)
	if err != nil {
		return nil, nil, err
	}
	Tracef("targetUrl = %s", targetUrl)
	data := ctx.String("data")
	Tracef("data = %s", data)
	body := strings.NewReader(data)
	req, err := http.NewRequest(method, targetUrl, body)
	if err != nil {
		return nil, nil, err
	}

	var lastError error
	for retrieve := false; retrieve == false; retrieve = true {
		Tracef("=== phase %s start", toString(retrieve))
		tok, r, err := AccessToken(CurrentOptions.ProfileName, retrieve)
		if err != nil {
			Tracef("phase %s failed (token retrieving failed)", toString(retrieve))
			lastError = err
			continue
		}
		retrieve = r

		req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
		for _, element := range ctx.GlobalStringSlice("header") {
			s := regexp.MustCompile(":").Split(element, 2)
			headerKey := strings.TrimSpace(s[0])
			headerValue := strings.TrimSpace(s[1])
			req.Header.Set(headerKey, headerValue)
			Tracef("custom header [%s: %s]", headerKey, headerValue)
		}
		Tracef("header end")

		dump, err := httputil.DumpRequestOut(req, true)
		if err != nil {
			Tracef("phase %s failed (request dump failed)", toString(retrieve))
			lastError = err
			continue
		}
		Tracef("request = %s", string(dump))

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: ctx.GlobalBool("insecure"),
			},
		}
		client := &http.Client{
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				Tracef("redirect to %s", req.URL.String())
				req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
				req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
				for _, element := range ctx.StringSlice("header") {
					s := regexp.MustCompile(":").Split(element, 2)
					req.Header.Set(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))
				}
				return nil
			},
			Transport: tr,
		}
		resp, err := client.Do(req)
		if err != nil {
			Tracef("phase %s failed (request failed)", toString(retrieve))
			lastError = err
			continue
		}

		dumpResp, err := httputil.DumpResponse(resp, true)
		if err != nil {
			log.Printf("%+v%n", err)
		} else {
			Tracef("response = %s", string(dumpResp))
		}

		Tracef("phase %s", toString(retrieve))
		if resp.StatusCode >= 400 && resp.StatusCode < 500 {
			if retrieve {
				Tracef("phase retrieve failed (4XX response)")
				lastError = err
				break
			} else {
				Tracef("phase stored failed (4XX response) -> final result")
			}
		}
		return resp, tok, err
	}
	return nil, nil, fmt.Errorf("%v", lastError)
}

func toString(retrieve bool) string {
	if retrieve {
		return "retrieve"
	}
	return "stored"
}

func targetUrl(ctx *cli.Context) (string, error) {
	if len(ctx.Args()) < 1 {
		return "", fmt.Errorf("target URL required")
	}
	return ctx.Args()[0], nil
}

func storeToken(tok *oauth2.Token) {
	if SaveValues(CurrentOptions.ProfileName, tokenToValues(tok)) {
		Tracef("token stored [%s]", CurrentOptions.ProfileName)
	} else {
		Tracef("fail to store token [%s]", CurrentOptions.ProfileName)
	}
}
<commit_msg>Fix HTTP method on put sub-command<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"golang.org/x/oauth2"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"regexp"
	"strings"
)

var DefaultFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "data",
		Usage: "Body data",
	},
}

var Commands = []cli.Command{
	commandGet,
	commandPost,
	commandPut,
	commandDelete,
	commandHead,
	commandOptions,
	commandPatch,
	commandTrace,
}

var commandGet = cli.Command{
	Name:      "get",
	ShortName: "g",
	Usage:     "Make GET request",
	Description: `
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doGet,
}

var commandPost = cli.Command{
	Name:      "post",
	ShortName: "p",
	Usage:     "Make POST request",
	Description: `
The POST method is used to request that the origin server accept the entity enclosed in the request
as a new subordinate of the resource identified by the Request-URI in the Request-Line.
`,
	Flags:  DefaultFlags,
	Action: doPost,
}

var commandPut = cli.Command{
	Name:  "put",
	Usage: "Make PUT request",
	Description: `
The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPut,
}

var commandDelete = cli.Command{
	Name:      "delete",
	ShortName: "d",
	Usage:     "Make DELETE request",
	Description: `
The DELETE method requests that the origin server delete the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doDelete,
}

var commandHead = cli.Command{
	Name:      "head",
	ShortName: "h",
	Usage:     "Make HEAD request",
	Description: `
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
`,
	Flags:  DefaultFlags,
	Action: doHead,
}

var commandOptions = cli.Command{
	Name:      "options",
	ShortName: "o",
	Usage:     "Make OPTIONS request",
	Description: `
The OPTIONS method represents a request for information about the communication options available
on the request/response chain identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doOptions,
}

var commandPatch = cli.Command{
	Name:  "patch",
	Usage: "Make PATCH request",
	Description: `
The PATCH method requests that a set of changes described in the request entity be applied
to the resource identified by the Request-URI.
`,
	Flags:  DefaultFlags,
	Action: doPatch,
}

var commandTrace = cli.Command{
	Name:      "trace",
	ShortName: "t",
	Usage:     "Make TRACE request",
	Description: `
The TRACE method is used to invoke a remote, application-layer loop-back of the request message.
`,
	Flags:  DefaultFlags,
	Action: doTrace,
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func doGet(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "GET")
}

func doPost(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "POST")
}

func doPut(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PUT")
}

func doDelete(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "DELETE")
}

func doHead(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "HEAD")
}

func doOptions(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "OPTIONS")
}

func doPatch(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "PATCH")
}

func doTrace(ctx *cli.Context) {
	loadOptions(ctx)
	doRequest(ctx, "TRACE")
}

func loadOptions(ctx *cli.Context) {
	var err error
	CurrentOptions, err = Opts(ctx)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
}

func doRequest(ctx *cli.Context, method string) {
	var tr = &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: ctx.GlobalBool("insecure"),
		},
	}
	http.DefaultClient = &http.Client{Transport: tr}

	Tracef("doRequest start")
	resp, tok, err := doRequest0(ctx, method)
	if tok != nil && resp != nil && resp.StatusCode != 401 && resp.StatusCode != 403 {
		storeToken(tok)
	}
	if err != nil {
		log.Fatal(err)
		return
	} else {
		Tracef("request done successfully")
	}

	Tracef("printing headers")
	if ctx.GlobalBool("print-headers") {
		headers, _ := json.Marshal(resp.Header)
		fmt.Println(string(headers))
	}

	if ctx.GlobalBool("no-body") {
		Tracef("printing body is disabled")
	} else {
		Tracef("printing body")
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			Tracef("error on read: %v", err)
		} else if body == nil {
			Tracef("no body")
		} else {
			Tracef("body found")
			fmt.Println(string(body))
		}
	}
	Tracef("doRequest end")
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func doRequest0(ctx *cli.Context, method string) (*http.Response, *oauth2.Token, error) {
	Tracef("profileName = %s", CurrentOptions.ProfileName)

	targetUrl, err := targetUrl(ctx)
	if err != nil {
		return nil, nil, err
	}
	Tracef("targetUrl = %s", targetUrl)
	data := ctx.String("data")
	Tracef("data = %s", data)
	body := strings.NewReader(data)
	req, err := http.NewRequest(method, targetUrl, body)
	if err != nil {
		return nil, nil, err
	}

	var lastError error
	for retrieve := false; retrieve == false; retrieve = true {
		Tracef("=== phase %s start", toString(retrieve))
		tok, r, err := AccessToken(CurrentOptions.ProfileName, retrieve)
		if err != nil {
			Tracef("phase %s failed (token retrieving failed)", toString(retrieve))
			lastError = err
			continue
		}
		retrieve = r

		req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
		for _, element := range ctx.GlobalStringSlice("header") {
			s := regexp.MustCompile(":").Split(element, 2)
			headerKey := strings.TrimSpace(s[0])
			headerValue := strings.TrimSpace(s[1])
			req.Header.Set(headerKey, headerValue)
			Tracef("custom header [%s: %s]", headerKey, headerValue)
		}
		Tracef("header end")

		dump, err := httputil.DumpRequestOut(req, true)
		if err != nil {
			Tracef("phase %s failed (request dump failed)", toString(retrieve))
			lastError = err
			continue
		}
		Tracef("request = %s", string(dump))

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: ctx.GlobalBool("insecure"),
			},
		}
		client := &http.Client{
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				Tracef("redirect to %s", req.URL.String())
				req.Header.Set("User-Agent", fmt.Sprintf("%s-%s", ctx.App.Name, Version))
				req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok.AccessToken))
				for _, element := range ctx.StringSlice("header") {
					s := regexp.MustCompile(":").Split(element, 2)
					req.Header.Set(strings.TrimSpace(s[0]), strings.TrimSpace(s[1]))
				}
				return nil
			},
			Transport: tr,
		}
		resp, err := client.Do(req)
		if err != nil {
			Tracef("phase %s failed (request failed)", toString(retrieve))
			lastError = err
			continue
		}

		dumpResp, err := httputil.DumpResponse(resp, true)
		if err != nil {
			log.Printf("%+v%n", err)
		} else {
			Tracef("response = %s", string(dumpResp))
		}

		Tracef("phase %s", toString(retrieve))
		if resp.StatusCode >= 400 && resp.StatusCode < 500 {
			if retrieve {
				Tracef("phase retrieve failed (4XX response)")
				lastError = err
				break
			} else {
				Tracef("phase stored failed (4XX response) -> final result")
			}
		}
		return resp, tok, err
	}
	return nil, nil, fmt.Errorf("%v", lastError)
}

func toString(retrieve bool) string {
	if retrieve {
		return "retrieve"
	}
	return "stored"
}

func targetUrl(ctx *cli.Context) (string, error) {
	if len(ctx.Args()) < 1 {
		return "", fmt.Errorf("target URL required")
	}
	return ctx.Args()[0], nil
}

func storeToken(tok *oauth2.Token) {
	if SaveValues(CurrentOptions.ProfileName, tokenToValues(tok)) {
		Tracef("token stored [%s]", CurrentOptions.ProfileName)
	} else {
		Tracef("fail to store token [%s]", CurrentOptions.ProfileName)
	}
}
<|endoftext|>