emersion/go-imap - Mark message as seen - go

I'm trying to mark messages as seen using this IMAP protocol implementation but It's not working as intended.
I have a function that prints unseen messages and my intention is that by the end, it mark each message as seen.
package main
import (
"emailmonitor/util"
"fmt"
)
func main() {
serverGmail := util.NewServerGmail()
serverGmail.Connect()
serverGmail.Login()
serverGmail.ListUnseenMessages()
}
//-----------------------------------------
package util
import (
"io/ioutil"
"log"
"net/mail"
"net/smtp"
imap "github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
)
type ServerGmail struct {
user string
pass string
erro string
cliente *client.Client
}
func NewServerGmail() *ServerGmail {
serverGmail := &ServerGmail{}
serverGmail.user = "xxxxxx#gmail.com"
serverGmail.pass = "xxxxx"
serverGmail.erro = ""
return serverGmail
}
func (serverGmail *ServerGmail) Connect() {
// Connect to server
cliente, erro := client.DialTLS("smtp.gmail.com:993", nil)
if erro != nil {
serverGmail.erro = erro.Error()
}
log.Println("Connected")
serverGmail.cliente = cliente
}
func (serverGmail *ServerGmail) Login() {
// Login
if erro := serverGmail.cliente.Login(serverGmail.user, serverGmail.pass); erro != nil {
serverGmail.erro = erro.Error()
}
log.Println("Logged")
}
func (serverGmail *ServerGmail) setLabelBox(label string) *imap.MailboxStatus {
mailbox, erro := serverGmail.cliente.Select(label, true)
if erro != nil {
serverGmail.erro = erro.Error()
}
return mailbox
}
func (serverGmail *ServerGmail) ListUnseenMessages() {
// set mailbox to INBOX
serverGmail.setLabelBox("INBOX")
// criteria to search for unseen messages
criteria := imap.NewSearchCriteria()
criteria.WithoutFlags = []string{"\\Seen"}
uids, err := serverGmail.cliente.UidSearch(criteria)
if err != nil {
log.Println(err)
}
seqSet := new(imap.SeqSet)
seqSet.AddNum(uids...)
section := &imap.BodySectionName{}
items := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchInternalDate, section.FetchItem()}
messages := make(chan *imap.Message)
go func() {
if err := serverGmail.cliente.UidFetch(seqSet, items, messages); err != nil {
log.Fatal(err)
}
}()
for message := range messages {
log.Println(message.Uid)
if message == nil {
log.Fatal("Server didn't returned message")
}
r := message.GetBody(section)
if r == nil {
log.Fatal("Server didn't returned message body")
}
// Create a new mail reader
mr, err := mail.CreateReader(r)
if err != nil {
log.Fatal(err)
}
// Print some info about the message
header := mr.Header
if date, err := header.Date(); err == nil {
log.Println("Date:", date)
}
if from, err := header.AddressList("From"); err == nil {
log.Println("From:", from)
}
if to, err := header.AddressList("To"); err == nil {
log.Println("To:", to)
}
if subject, err := header.Subject(); err == nil {
log.Println("Subject:", subject)
}
// MARK "SEEN" ------- STARTS HERE ---------
seqSet.Clear()
seqSet.AddNum(message.Uid)
item := imap.FormatFlagsOp(imap.AddFlags, true)
flags := []interface{}{imap.SeenFlag}
erro := serverGmail.cliente.UidStore(seqSet, item, flags, nil)
if erro != nil {
panic("error!")
}
}
}
Link from Documentation: https://godoc.org/github.com/emersion/go-imap/client#Client.UidStore
Tried to do something similar to Store example.
What can be done to fix it?

modify the following line by changing true to false
mailbox, erro := serverGmail.cliente.Select(label, true)
once you've done this, when the message is fetched (using the UidFetch), it will be automatically marked to "Seen"

Related

Ethereum error {"code":-32000,"message":"unknown account"}

I am trying to send a raw transaction with eth.sendTransaction but I am getting an error that says {"code":-32000,"message":"unknown account"}. I am not sure what is causing this and I cant seem to find an answer on the internet. Can anyone help me figure it out? Here is my code:
func ExecuteSignedTransaction(rawTransaction string) {
var hash web3.Hash
data := make(map[string]interface{})
data["data"] = rawTransaction
err := Web3HTTPClient.Call("eth_sendTransaction", &hash, data)
if err != nil{
fmt.Println(err)
Os.Exit(1)
}
fmt.Println("Sent tx hash:", hash)
}
So, what I might do here:
import (
"strings"
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
)
var chainId = big.NewInt(1) // chain id for the ethereum mainnet, change according to needs
func ecdsaPrivateKeyFromHex(privKeyHex string) *ecdsa.PrivateKey {
ecdsaKey, err := crypto.HexToECDSA(privKeyHex)
if err != nil { panic(err) }
return ecdsaKey
}
func newTransactOpts(privKey *ecdsa.PrivateKey) *bind.TransactOpts {
transactOpts, err := bind.NewKeyedTransactorWithChainID(privKey, chainId)
if err != nil { panic(err) }
return transactOpts
}
func newRpcClient() *ethclient.Client {
c, err := ethclient.Dial("insert rpc url here")
if err != nil { panic(err) }
return c
}
// note: constructing the *types.Transaction object left as
// an exercise to the reader
func ExecuteTransaction(rawTransaction *types.Transaction) {
privKeyHex := "0xblahblahblahblahblah" // use your own account's private key
transactOpts := newTransactOpts(ecdsaPrivateKeyFromHex(privKeyHex))
signedTxn, err := transactOpts.Signer(transactOpts.From, rawTransaction)
if err != nil { panic(err) }
rpcClient := newRpcClient()
if err := rpcClient.SendTransaction(context.Background(), signedTxn); err != nil { panic(err) }
// do whatever
}

Redirect from one page to another not working

I am trying to Insert the scan results using the Scan func and once done I want to redirect to show results which are nothing but a select query to the inserts done ever. Both functions are working properly when tested separately. Is this not the correct way to redirect from the first page to the next?
package main
import (
"bytes"
"database/sql"
"fmt"
"html/template"
"log"
"net/http"
"os/exec"
"regexp"
"strconv"
"strings"
"time"
_ "github.com/go-sql-driver/mysql"
)
func dbConn() (db *sql.DB) {
dbDriver := "mysql"
dbUser := "root"
dbPass := "root"
dbName := "test"
db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"#/"+dbName+"?parseTime=true")
if err != nil {
log.Fatal(err)
}
return db
}
var tmpl = template.Must(template.ParseGlob("form/*"))
var hostnameInput string
func main() {
http.HandleFunc("/login", login)
http.HandleFunc("/show", Show)
lerr := http.ListenAndServe(":9090", nil) // setting listening port
if lerr != nil {
log.Fatal("ListenAndServe: ", lerr)
}
}
func Insert(hostname string, ports []int) {
db := dbConn()
// INSERT INTO DB
// prepare
stmt, e := db.Prepare("insert into nmap_reports(reported_at, host_address) values ( ?, ?)")
if e != nil {
log.Fatal(e)
}
//execute
res, er := stmt.Exec(time.Now(), hostname)
if er != nil {
log.Fatal(er)
}
for _, v := range ports {
insForm, err := db.Prepare("INSERT INTO nmap_report_ports(nmap_report_id,port) VALUES (?,?)")
if err != nil {
log.Fatal(err)
}
id, fail := res.LastInsertId()
if fail != nil {
log.Fatal(fail)
}
_, er := insForm.Exec(id, v)
if er != nil {
log.Fatal(er)
}
}
defer db.Close()
}
func Select(hostname string) []Result {
db := dbConn()
// query all data
stmt, err := db.Prepare("SELECT nm.nmap_report_id, nm.host_address,nm.reported_at,GROUP_CONCAT(port) AS `Ports` FROM nmap_reports nm left join nmap_report_ports nrp on nm.nmap_report_id = nrp.nmap_report_id where nm.host_address = ? group by nm.nmap_report_id order by nmap_report_id desc")
if err != nil {
log.Fatal(err)
}
rows, er := stmt.Query(hostname)
if er != nil {
log.Fatal(er)
}
// declare empty result variable
var resultI = Result{}
// iterate over rows
resultSet := make([]Result, 0)
for rows.Next() {
e := rows.Scan(&resultI.ReportId, &resultI.Hostname, &resultI.Date, &resultI.Ports)
if e != nil {
log.Fatal(er)
}
resultSet = append(resultSet, resultI)
}
defer db.Close()
return resultSet
}
type Result struct {
ReportId int `json:"reportId"`
Hostname string `json:"hostname"`
Date time.Time `json:"date"`
Ports string `json:"ports"`
}
func Show(w http.ResponseWriter, r *http.Request) {
data := Select(hostnameInput)
temp, temperr := template.ParseFiles("form/show.tmpl")
if temperr != nil {
log.Fatal(temperr)
}
temp.ExecuteTemplate(w, "show", data)
}
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //get request method
if r.Method == "GET" {
t, _ := template.ParseFiles("form/input.tmpl")
t.Execute(w, nil)
} else {
//if r.Method == "POST" {
r.ParseForm()
fmt.Println("hostname:", r.Form["hname"])
var rxHostIP = regexp.MustCompile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)+([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9])$")
hostnameInput = strings.Join(r.Form["hname"], "")
fmt.Println("hnmae is:" + hostnameInput)
if !rxHostIP.MatchString(hostnameInput) {
w.WriteHeader(400)
w.Write([]byte("Invalid Ip/hostname"))
}
command := []string{"nmap", "-p", "1-1000"}
command = append(command, r.Form["hname"]...)
finalcommand := strings.Join(command, " ")
fmt.Println(finalcommand)
cmd := exec.Command(`C:\Windows\System32\cmd.exe`, "/c", finalcommand)
cmdOutput := &bytes.Buffer{}
cmd.Stdout = cmdOutput
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
check := string(cmdOutput.Bytes())
re := regexp.MustCompile(`([0-9]+)./`)
stringArr := re.FindAllString(check, -1)
intArr := make([]int, 0)
for _, v := range stringArr {
n := strings.Replace(v, "/", "", -1)
i, cerr := strconv.Atoi(n)
if cerr != nil {
log.Fatal(cerr)
}
intArr = append(intArr, i)
}
Insert(hostnameInput, intArr)
}
http.Redirect(w, r, "/show", 301)
}
Trying to redirect from login page to show page using
http.Redirect(w, r, "/show", 301)
I think the redirect code is fine. There might be something going inside the login handler that prevents the redirect from happening.
I've annotated and modified some parts of the login handler below, if it might be helpful to you.
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //get request method
if r.Method == "GET" {
// note#1: don't ignore the error
t, err := template.ParseFiles("form/input.tmpl")
if err != nil {
log.Fatal(err)
}
// note#2: check the error
err = t.Execute(w, nil)
if err != nil {
log.Fatal(err)
}
} else {
var err error
// note#3: check the error
err = r.ParseForm()
if err != nil {
log.Fatal(err)
}
// ...
// other code, omitted for brevity
// ...
}
// note#4: this is fine if you intend to redirect all the request,
// regardless of the method, to the `/show` endpoint
http.Redirect(w, r, "/show", 301)
}

GRPC server does not release DB connection

I am working on a Go project which use gRPC as server and Voltdb as DB. I have an issue when sending many DB read/write requests to gRPC server. Request has been handled but it does not release DB connection after finishing operator. So when connection in pool run out I get this error:
Rejected connection from /127.0.0.1:63015 because the connection limit of 9940 has been reached
proto file
syntax = "proto3";
package grpc;
import "google/protobuf/struct.proto";
option java_multiple_files = true;
option java_package = "com.io.test";
service TestService {
rpc updateUser (UserRequest) returns (Status) {};
}
message UserRequest {
string userId = 1;
string name = 2;
}
message Status {
string code = 1;
}
Grpc implement in Go
package service
import (
"context"
"log"
api "testgrpc/pkg/api/grpc"
"testgrpc/pkg/db"
"testgrpc/pkg/model"
)
var voltDbClient *db.VoltDBClient
func init() {
voltDbClient = db.NewVoltDBClient()
}
type GrpcService struct {
}
func NewGrpcService() *GrpcService {
return &GrpcService{}
}
func (sv *GrpcService) UpdateUser(ctx context.Context, req *api.UserRequest) (*api.Status, error) {
user, err := voltDbClient.FindByID(req.GetUserId())
if user == nil || err != nil {
log.Print("error while reading")
} else {
log.Println(user.(*model.User).UserId)
log.Println(user.(*model.User).Name)
}
err = voltDbClient.Put(req.GetUserId(), req.GetName())
if err != nil {
log.Print("error while writing")
}
return &api.Status{Code: "0"}, nil
}
DB client
package db
import (
"database/sql"
"log"
"testgrpc/pkg/model"
_ "github.com/VoltDB/voltdb-client-go/voltdbclient"
)
var Db *sql.DB
func init() {
if Db == nil {
var err error
Db, err = sql.Open("voltdb", "localhost:21212")
if err != nil {
log.Fatal(err)
}
//limit max connection to reproduce issue
Db.SetMaxOpenConns(20)
}
}
type VoltDBClient struct {
}
func NewVoltDBClient() *VoltDBClient {
return &VoltDBClient{}
}
//Put add or update record
func (dbClient *VoltDBClient) Put(key interface{}, value interface{}) error {
res, err := Db.Exec("GROUPINFO.upsert", key, value)
if err != nil {
log.Println(err)
return err
}
rowCnt, err := res.RowsAffected()
if err != nil {
log.Println(err)
return err
}
log.Printf("affected = %d\n", rowCnt)
return nil
}
//FindByID find a record by ID
func (dbClient *VoltDBClient) FindByID(key interface{}) (interface{}, error) {
rows, err := Db.Query("GROUPSELECT", key)
if err != nil {
log.Println(err)
return nil, err
}
for rows.Next() {
user := model.User{UserId: "", Name: ""}
err := rows.Scan(&user.UserId, &user.Name)
if err != nil {
log.Println(err)
return nil, err
}
return &user, nil
}
return nil, nil
}
Note: I have tried run project without grpc, read/write operators work well.

Golang Gorilla Websocket stops receiving information at 120 seconds

I'm currently trying to connect to the CEX.IO bitcoin exchange's websocket, but have been having issues not only with CEX.IO but with others too. All of my connections drop around the 120-second mark which makes me think there is some TTL problem going on. The Process() goroutine in the main package ends up just hanging and waiting for data from the readLoop which just stops receiving data. I've included some read-only API keys in the code so you can test if you'd like.
package main
import (
"fmt"
"bitbucket.org/tradedefender/cryptocurrency/exchange-connector/cexio"
"github.com/shopspring/decimal"
"encoding/json"
"time"
)
type OrderBook struct {
Asks []Ask
Bids []Bid
}
type Ask struct {
Rate decimal.Decimal
Amount decimal.Decimal
}
type Bid struct {
Rate decimal.Decimal
Amount decimal.Decimal
}
func main() {
cexioConn := new(cexio.Connection)
err := cexioConn.Connect()
if err != nil {
fmt.Errorf("error: %s", err.Error())
}
err = cexioConn.Authenticate("TLwYkktLf7Im6nqSKt6UO1IrU", "9ImOJcR7Qj3LMIyPCzky0D7WE")
if err != nil {
fmt.Errorf("error: %s", err.Error())
}
readChannel := make(chan cexio.IntraAppMessage, 25)
go cexioConn.ReadLoop(readChannel)
processor := Processor{
WatchPairs: [][2]string{
[2]string{
"BTC", "USD",
},
},
conn: cexioConn,
}
go processor.Process(readChannel)
// LOL
for {
continue
}
}
type Processor struct {
WatchPairs [][2]string
conn *cexio.Connection
}
func (p *Processor) Process(ch <-chan cexio.IntraAppMessage) {
p.conn.SubscribeToOrderBook(p.WatchPairs[0])
pingTimer := time.Now().Unix()
for {
fmt.Printf("(%v)\n", time.Now().Unix())
if (time.Now().Unix() - pingTimer) >= 10 {
fmt.Println("sending ping")
p.conn.SendPing()
pingTimer = time.Now().Unix()
}
readMsg := <- ch
output, _ := json.Marshal(readMsg.SocketMessage)
fmt.Println(string(output))
if readMsg.SocketMessage.Event == "ping" {
fmt.Println("sending pong")
p.conn.SendPong()
pingTimer = time.Now().Unix()
}
}
}
Below is the connector to the cexio websocket. Here is a link to their API: https://cex.io/websocket-api
package cexio
import (
"github.com/gorilla/websocket"
//"github.com/shopspring/decimal"
"github.com/satori/go.uuid"
"encoding/hex"
"encoding/json"
"crypto/hmac"
"crypto/sha256"
"bytes"
"strconv"
"time"
"fmt"
)
const Url = "wss://ws.cex.io/ws/"
type Connection struct {
conn *websocket.Conn
}
type IntraAppMessage struct {
SocketMessage GenericMessage
ProgramMessage ProgramMessage
}
type GenericMessage struct {
Event string `json:"e"`
Data interface{} `json:"data"`
Auth AuthData `json:"auth,omitempty"`
Ok string `json:"ok,omitempty"`
Oid string `json:"oid,omitempty"`
Time int64 `json:"time,omitempty"`
}
type ProgramMessage struct {
Error string
}
type AuthData struct {
Key string `json:"key"`
Signature string `json:"signature"`
Timestamp int64 `json:"timestamp"`
}
type OrderBookSubscribeData struct {
Pair [2]string `json:"pair"`
Subscribe bool `json:"subscribe"`
Depth int `json:"depth"`
}
func (c *Connection) SendPong() error {
pongMsg := GenericMessage{
Event: "pong",
}
err := c.conn.WriteJSON(pongMsg)
if err != nil {
return nil
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PongMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) SendPing() error {
pingMsg := GenericMessage{
Event: "get-balance",
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(pingMsg)
if err != nil {
return err
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PingMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) Connect() error {
dialer := *websocket.DefaultDialer
wsConn, _, err := dialer.Dial(Url, nil)
if err != nil {
return err
}
c.conn = wsConn
//c.conn.SetPingHandler(c.HandlePing)
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != "connected" {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) Disconnect() error {
return c.conn.Close()
}
func (c *Connection) ReadLoop(ch chan<- IntraAppMessage) {
for {
fmt.Println("starting new read")
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
ch <- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
ch <- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
ch <- IntraAppMessage{
SocketMessage: m,
}
}
}
func CreateSignature(timestamp int64, key, secret string) string {
secretBytes := []byte(secret)
h := hmac.New(sha256.New, secretBytes)
var buffer bytes.Buffer
buffer.WriteString(strconv.FormatInt(timestamp, 10))
buffer.WriteString(key)
h.Write(buffer.Bytes())
return hex.EncodeToString(h.Sum(nil))
}
func (c *Connection) Authenticate(key, secret string) error {
timestamp := time.Now().Unix()
signature := CreateSignature(timestamp, key, secret)
var authMsg GenericMessage
authMsg.Event = "auth"
authMsg.Auth = AuthData{
Key: key,
Signature: signature,
Timestamp: timestamp,
}
err := c.conn.WriteJSON(authMsg)
if err != nil {
return err
}
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != "auth" && m.Ok != "ok" {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) SubscribeToOrderBook(pair [2]string) error {
sendMsg := GenericMessage{
Event: "order-book-subscribe",
Data: OrderBookSubscribeData{
Pair: pair,
Subscribe: true,
Depth: 0,
},
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}
func (c *Connection) GetBalance() error {
sendMsg := GenericMessage{
Event: "get-balance",
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}
Solution was to remove the
for {
continue
}
at the end of the main function

flag redefined - panic searching by key in YouTube data API 3

I am trying to search YouTube video by key like in the golang example. I modified that code a little to let it search by different keys several times.
When I search once it is ok.
func main() {
result1, err1 := SearchYoutubeByKey("hello")
if err1 != nil {
panic(err1)
}
fmt.Println(result1)
// result2, err2 := SearchYoutubeByKey("world")
// if err2 != nil {
// panic(err2)
// }
// fmt.Println(result2)
}
But if I search twice ...
func main() {
result1, err1 := SearchYoutubeByKey("hello")
if err1 != nil {
panic(err1)
}
fmt.Println(result1)
result2, err2 := SearchYoutubeByKey("world")
if err2 != nil {
panic(err2)
}
fmt.Println(result2)
}
... then it panics with error message ...
flag redefined: query
... on line ...
query := flag.String("query", str, "Search term")
Full code:
package main
import (
"code.google.com/p/google-api-go-client/googleapi/transport"
"code.google.com/p/google-api-go-client/youtube/v3"
"flag"
"fmt"
"net/http"
)
var (
maxResults = flag.Int64("max-results", 25, "Max YouTube results")
service *youtube.Service
response *youtube.SearchListResponse
)
const developerKey = "youtube developer key"
type YoutubeSearchResult struct {
Title, YoutubeId string
}
func SearchYoutubeByKey(str string) (result []*YoutubeSearchResult, err error) {
query := flag.String("query", str, "Search term")
flag.Parse()
client := &http.Client{
Transport: &transport.APIKey{Key: developerKey},
}
service, err = youtube.New(client)
if err != nil {
return
}
// Make the API call to YouTube.
call := service.Search.List("id,snippet").
Q(*query).
MaxResults(*maxResults)
response, err = call.Do()
if err != nil {
return
}
// Iterate through each item and add it to the correct list.
for _, item := range response.Items {
switch item.Id.Kind {
case "youtube#video":
result = append(result, &YoutubeSearchResult{Title: item.Snippet.Title, YoutubeId: item.Id.VideoId})
}
}
return
}
func main() {
result1, err1 := SearchYoutubeByKey("hello")
if err1 != nil {
panic(err1)
}
fmt.Println(result1)
result2, err2 := SearchYoutubeByKey("world")
if err2 != nil {
panic(err2)
}
fmt.Println(result2)
}
So it is impossible to use this code on a website. Only the first user will be able to search first time, the others will fail.
I cannot change flag during runtime but how to search by 2 different keys in one program?
Update
working solution:
package main
import (
"code.google.com/p/google-api-go-client/googleapi/transport"
"code.google.com/p/google-api-go-client/youtube/v3"
"flag"
"fmt"
"net/http"
)
var (
maxResults = flag.Int64("max-results", 25, "Max YouTube results")
service *youtube.Service
response *youtube.SearchListResponse
query = flag.String("query", "str", "Search term")
)
const developerKey = "youtube api key"
type YoutubeSearchResult struct {
Title, YoutubeId string
}
func SearchYoutubeByKey(str string) (result []*YoutubeSearchResult, err error) {
flag.Parse()
client := &http.Client{
Transport: &transport.APIKey{Key: developerKey},
}
service, err = youtube.New(client)
if err != nil {
return
}
// Make the API call to YouTube.
call := service.Search.List("id,snippet").
Q(str).
MaxResults(*maxResults)
response, err = call.Do()
if err != nil {
return
}
// Iterate through each item and add it to the correct list.
for _, item := range response.Items {
switch item.Id.Kind {
case "youtube#video":
result = append(result, &YoutubeSearchResult{Title: item.Snippet.Title, YoutubeId: item.Id.VideoId})
}
}
return
}
func main() {
result1, err1 := SearchYoutubeByKey("hello")
if err1 != nil {
panic(err1)
}
fmt.Println(result1)
result2, err2 := SearchYoutubeByKey("world")
if err2 != nil {
panic(err2)
}
fmt.Println(result2)
}
The panic message tells you exactly what's wrong. Your command line flags should be defined only once. If you try to redefine them during runtime, it panics.

Resources