WS: Tiny WebSocket Library for Go

ws

RFC6455 WebSocket implementation in Go.

Features

  • Zero-copy upgrade
  • No intermediate allocations during I/O
  • Low-level API which allows to build your own logic of packet handling and buffers reuse
  • High-level wrappers and helpers around API in wsutil package, which allow to start fast without digging the protocol internals

Documentation

GoDoc.

Why

Existing WebSocket implementations do not allow users to reuse I/O buffers between connections in clear way. This library aims to export efficient low-level interface for working with the protocol without forcing only one way it could be used.

By the way, if you want get the higher-level tools, you can use wsutil package.

Status

Library is tagged as v1* so its API must not be broken during some improvements or refactoring.

This implementation of RFC6455 passes Autobahn Test Suite and currently has about 78% coverage.

Examples

Example applications using ws are developed in separate repository ws-examples.

Usage

The higher-level example of WebSocket echo server:

package main

import (
    "net/http"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsutil"
)

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        conn, _, _, err := ws.UpgradeHTTP(r, w)
        if err != nil {
            // handle error
        }
        go func() {
            defer conn.Close()

            for {
                msg, op, err := wsutil.ReadClientData(conn)
                if err != nil {
                    // handle error
                }
                err = wsutil.WriteServerMessage(conn, op, msg)
                if err != nil {
                    // handle error
                }
            }
        }()
    }))
}

Lower-level, but still high-level example:

import (
    "net/http"
    "io"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsutil"
)

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        conn, _, _, err := ws.UpgradeHTTP(r, w)
        if err != nil {
            // handle error
        }
        go func() {
            defer conn.Close()

            var (
                state  = ws.StateServerSide
                reader = wsutil.NewReader(conn, state)
                writer = wsutil.NewWriter(conn, state, ws.OpText)
            )
            for {
                header, err := reader.NextFrame()
                if err != nil {
                    // handle error
                }

                // Reset writer to write frame with right operation code.
                writer.Reset(conn, state, header.OpCode)

                if _, err = io.Copy(writer, reader); err != nil {
                    // handle error
                }
                if err = writer.Flush(); err != nil {
                    // handle error
                }
            }
        }()
    }))
}

We can apply the same pattern to read and write structured responses through a JSON encoder and decoder.:

    ...
    var (
        r = wsutil.NewReader(conn, ws.StateServerSide)
        w = wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
        decoder = json.NewDecoder(r)
        encoder = json.NewEncoder(w)
    )
    for {
        hdr, err = r.NextFrame()
        if err != nil {
            return err
        }
        if hdr.OpCode == ws.OpClose {
            return io.EOF
        }
        var req Request
        if err := decoder.Decode(&req); err != nil {
            return err
        }
        var resp Response
        if err := encoder.Encode(&resp); err != nil {
            return err
        }
        if err = w.Flush(); err != nil {
            return err
        }
    }
    ...

The lower-level example without wsutil:

package main

import (
    "net"
    "io"

    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        log.Fatal(err)
    }

    for {
        conn, err := ln.Accept()
        if err != nil {
            // handle error
        }
        _, err = ws.Upgrade(conn)
        if err != nil {
            // handle error
        }

        go func() {
            defer conn.Close()

            for {
                header, err := ws.ReadHeader(conn)
                if err != nil {
                    // handle error
                }

                payload := make([]byte, header.Length)
                _, err = io.ReadFull(conn, payload)
                if err != nil {
                    // handle error
                }
                if header.Masked {
                    ws.Cipher(payload, header.Mask, 0)
                }

                // Reset the Masked flag, server frames must not be masked as
                // RFC6455 says.
                header.Masked = false

                if err := ws.WriteHeader(conn, header); err != nil {
                    // handle error
                }
                if _, err := conn.Write(payload); err != nil {
                    // handle error
                }

                if header.OpCode == ws.OpClose {
                    return
                }
            }
        }()
    }
}

Zero-copy upgrade

Zero-copy upgrade helps to avoid unnecessary allocations and copying while handling HTTP Upgrade request.

Processing of all non-websocket headers is made in place with use of registered user callbacks whose arguments are only valid until callback returns.

The simple example looks like this:

package main

import (
    "net"
    "log"

    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        log.Fatal(err)
    }
    u := ws.Upgrader{
        OnHeader: func(key, value []byte) (err error) {
            log.Printf("non-websocket header: %q=%q", key, value)
            return
        },
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            // handle error
        }

        _, err = u.Upgrade(conn)
        if err != nil {
            // handle error
        }
    }
}

Usage of ws.Upgrader here brings ability to control incoming connections on tcp level and simply not to accept them by some logic.

Zero-copy upgrade is for high-load services which have to control many resources such as connections buffers.

The real life example could be like this:

package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "runtime"

    "github.com/gobwas/httphead"
    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        // handle error
    }

    // Prepare handshake header writer from http.Header mapping.
    header := ws.HandshakeHeaderHTTP(http.Header{
        "X-Go-Version": []string{runtime.Version()},
    })

    u := ws.Upgrader{
        OnHost: func(host []byte) error {
            if string(host) == "github.com" {
                return nil
            }
            return ws.RejectConnectionError(
                ws.RejectionStatus(403),
                ws.RejectionHeader(ws.HandshakeHeaderString(
                    "X-Want-Host: github.com\r\n",
                )),
            )
        },
        OnHeader: func(key, value []byte) error {
            if string(key) != "Cookie" {
                return nil
            }
            ok := httphead.ScanCookie(value, func(key, value []byte) bool {
                // Check session here or do some other stuff with cookies.
                // Maybe copy some values for future use.
                return true
            })
            if ok {
                return nil
            }
            return ws.RejectConnectionError(
                ws.RejectionReason("bad cookie"),
                ws.RejectionStatus(400),
            )
        },
        OnBeforeUpgrade: func() (ws.HandshakeHeader, error) {
            return header, nil
        },
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Fatal(err)
        }
        _, err = u.Upgrade(conn)
        if err != nil {
            log.Printf("upgrade error: %s", err)
        }
    }
}

Compression

There is a ws/wsflate package to support Permessage-Deflate Compression Extension.

It provides minimalistic I/O wrappers to be used in conjunction with any deflate implementation (for example, the standard library's compress/flate).

It is also compatible with wsutil's reader and writer by providing wsflate.MessageState type, which implements wsutil.SendExtension and wsutil.RecvExtension interfaces.

package main

import (
    "bytes"
    "log"
    "net"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsflate"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        // handle error
    }
    e := wsflate.Extension{
        // We are using default parameters here since we use
        // wsflate.{Compress,Decompress}Frame helpers below in the code.
        // This assumes that we use standard compress/flate package as flate
        // implementation.
        Parameters: wsflate.DefaultParameters,
    }
    u := ws.Upgrader{
        Negotiate: e.Negotiate,
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Fatal(err)
        }

        // Reset extension after previous upgrades.
        e.Reset()

        _, err = u.Upgrade(conn)
        if err != nil {
            log.Printf("upgrade error: %s", err)
            continue
        }
        if _, ok := e.Accepted(); !ok {
            log.Printf("didn't negotiate compression for %s", conn.RemoteAddr())
            conn.Close()
            continue
        }

        go func() {
            defer conn.Close()
            for {
                frame, err := ws.ReadFrame(conn)
                if err != nil {
                    // Handle error.
                    return
                }

                frame = ws.UnmaskFrameInPlace(frame)

                if wsflate.IsCompressed(frame.Header) {
                    // Note that even after successful negotiation of
                    // compression extension, both sides are able to send
                    // non-compressed messages.
                    frame, err = wsflate.DecompressFrame(frame)
                    if err != nil {
                        // Handle error.
                        return
                    }
                }

                // Do something with frame...

                ack := ws.NewTextFrame([]byte("this is an acknowledgement"))

                // Compress response unconditionally.
                ack, err = wsflate.CompressFrame(ack)
                if err != nil {
                    // Handle error.
                    return
                }
                if err = ws.WriteFrame(conn, ack); err != nil {
                    // Handle error.
                    return
                }
            }
        }()
    }
}

You can use compression with wsutil package this way:

    // Upgrade somehow and negotiate compression to get the conn...

    // Initialize flate reader. We are using nil as a source io.Reader because
    // we will Reset() it in the message i/o loop below.
    fr := wsflate.NewReader(nil, func(r io.Reader) wsflate.Decompressor {
        return flate.NewReader(r)
    })
    // Initialize flate writer. We are using nil as a destination io.Writer
    // because we will Reset() it in the message i/o loop below.
    fw := wsflate.NewWriter(nil, func(w io.Writer) wsflate.Compressor {
        f, _ := flate.NewWriter(w, 9)
        return f
    })

    // Declare compression message state variable.
    //
    // It has two goals:
    // - Allow users to check whether received message is compressed or not.
    // - Help wsutil.Reader and wsutil.Writer to set/unset appropriate
    //   WebSocket header bits while writing next frame to the wire (it
    //   implements wsutil.RecvExtension and wsutil.SendExtension).
    var msg wsflate.MessageState

    // Initialize WebSocket reader as previously. 
    // Please note the use of Reader.Extensions field as well as
    // of ws.StateExtended flag.
    rd := &wsutil.Reader{
        Source:     conn,
        State:      ws.StateServerSide | ws.StateExtended,
        Extensions: []wsutil.RecvExtension{
            &msg, 
        },
    }

    // Initialize WebSocket writer with ws.StateExtended flag as well.
    wr := wsutil.NewWriter(conn, ws.StateServerSide|ws.StateExtended, 0)
    // Use the message state as wsutil.SendExtension.
    wr.SetExtensions(&msg)

    for {
        h, err := rd.NextFrame()
        if err != nil {
            // handle error.
        }
        if h.OpCode.IsControl() {
            // handle control frame.
        }
        if !msg.IsCompressed() {
            // handle uncompressed frame (skipped for the sake of example
            // simplicity).
        }

        // Reset the writer to echo same op code.
        wr.Reset(h.OpCode)

        // Reset both flate reader and writer to start the new round of i/o.
        fr.Reset(rd)
        fw.Reset(wr)

        // Copy whole message from reader to writer decompressing it and
        // compressing again.
        if _, err := io.Copy(fw, fr); err != nil {
            // handle error.
        }
        // Flush any remaining buffers from flate writer to WebSocket writer.
        if err := fw.Close(); err != nil {
            // handle error.
        }
        // Flush the whole WebSocket message to the wire.
        if err := wr.Flush(); err != nil {
            // handle error.
        }
    }

Download Details:

Author: Gobwas
Source Code: https://github.com/gobwas/ws 
License: MIT license

#go #golang #websocket 

What is GEEK

Buddha Community

WS: Tiny WebSocket Library for Go
Fannie  Zemlak

Fannie Zemlak

1599854400

What's new in the go 1.15

Go announced Go 1.15 version on 11 Aug 2020. Highlighted updates and features include Substantial improvements to the Go linker, Improved allocation for small objects at high core counts, X.509 CommonName deprecation, GOPROXY supports skipping proxies that return errors, New embedded tzdata package, Several Core Library improvements and more.

As Go promise for maintaining backward compatibility. After upgrading to the latest Go 1.15 version, almost all existing Golang applications or programs continue to compile and run as older Golang version.

#go #golang #go 1.15 #go features #go improvement #go package #go new features

WS: Tiny WebSocket Library for Go

ws

RFC6455 WebSocket implementation in Go.

Features

  • Zero-copy upgrade
  • No intermediate allocations during I/O
  • Low-level API which allows to build your own logic of packet handling and buffers reuse
  • High-level wrappers and helpers around API in wsutil package, which allow to start fast without digging the protocol internals

Documentation

GoDoc.

Why

Existing WebSocket implementations do not allow users to reuse I/O buffers between connections in clear way. This library aims to export efficient low-level interface for working with the protocol without forcing only one way it could be used.

By the way, if you want get the higher-level tools, you can use wsutil package.

Status

Library is tagged as v1* so its API must not be broken during some improvements or refactoring.

This implementation of RFC6455 passes Autobahn Test Suite and currently has about 78% coverage.

Examples

Example applications using ws are developed in separate repository ws-examples.

Usage

The higher-level example of WebSocket echo server:

package main

import (
    "net/http"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsutil"
)

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        conn, _, _, err := ws.UpgradeHTTP(r, w)
        if err != nil {
            // handle error
        }
        go func() {
            defer conn.Close()

            for {
                msg, op, err := wsutil.ReadClientData(conn)
                if err != nil {
                    // handle error
                }
                err = wsutil.WriteServerMessage(conn, op, msg)
                if err != nil {
                    // handle error
                }
            }
        }()
    }))
}

Lower-level, but still high-level example:

import (
    "net/http"
    "io"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsutil"
)

func main() {
    http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        conn, _, _, err := ws.UpgradeHTTP(r, w)
        if err != nil {
            // handle error
        }
        go func() {
            defer conn.Close()

            var (
                state  = ws.StateServerSide
                reader = wsutil.NewReader(conn, state)
                writer = wsutil.NewWriter(conn, state, ws.OpText)
            )
            for {
                header, err := reader.NextFrame()
                if err != nil {
                    // handle error
                }

                // Reset writer to write frame with right operation code.
                writer.Reset(conn, state, header.OpCode)

                if _, err = io.Copy(writer, reader); err != nil {
                    // handle error
                }
                if err = writer.Flush(); err != nil {
                    // handle error
                }
            }
        }()
    }))
}

We can apply the same pattern to read and write structured responses through a JSON encoder and decoder.:

    ...
    var (
        r = wsutil.NewReader(conn, ws.StateServerSide)
        w = wsutil.NewWriter(conn, ws.StateServerSide, ws.OpText)
        decoder = json.NewDecoder(r)
        encoder = json.NewEncoder(w)
    )
    for {
        hdr, err = r.NextFrame()
        if err != nil {
            return err
        }
        if hdr.OpCode == ws.OpClose {
            return io.EOF
        }
        var req Request
        if err := decoder.Decode(&req); err != nil {
            return err
        }
        var resp Response
        if err := encoder.Encode(&resp); err != nil {
            return err
        }
        if err = w.Flush(); err != nil {
            return err
        }
    }
    ...

The lower-level example without wsutil:

package main

import (
    "net"
    "io"

    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        log.Fatal(err)
    }

    for {
        conn, err := ln.Accept()
        if err != nil {
            // handle error
        }
        _, err = ws.Upgrade(conn)
        if err != nil {
            // handle error
        }

        go func() {
            defer conn.Close()

            for {
                header, err := ws.ReadHeader(conn)
                if err != nil {
                    // handle error
                }

                payload := make([]byte, header.Length)
                _, err = io.ReadFull(conn, payload)
                if err != nil {
                    // handle error
                }
                if header.Masked {
                    ws.Cipher(payload, header.Mask, 0)
                }

                // Reset the Masked flag, server frames must not be masked as
                // RFC6455 says.
                header.Masked = false

                if err := ws.WriteHeader(conn, header); err != nil {
                    // handle error
                }
                if _, err := conn.Write(payload); err != nil {
                    // handle error
                }

                if header.OpCode == ws.OpClose {
                    return
                }
            }
        }()
    }
}

Zero-copy upgrade

Zero-copy upgrade helps to avoid unnecessary allocations and copying while handling HTTP Upgrade request.

Processing of all non-websocket headers is made in place with use of registered user callbacks whose arguments are only valid until callback returns.

The simple example looks like this:

package main

import (
    "net"
    "log"

    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        log.Fatal(err)
    }
    u := ws.Upgrader{
        OnHeader: func(key, value []byte) (err error) {
            log.Printf("non-websocket header: %q=%q", key, value)
            return
        },
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            // handle error
        }

        _, err = u.Upgrade(conn)
        if err != nil {
            // handle error
        }
    }
}

Usage of ws.Upgrader here brings ability to control incoming connections on tcp level and simply not to accept them by some logic.

Zero-copy upgrade is for high-load services which have to control many resources such as connections buffers.

The real life example could be like this:

package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "runtime"

    "github.com/gobwas/httphead"
    "github.com/gobwas/ws"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        // handle error
    }

    // Prepare handshake header writer from http.Header mapping.
    header := ws.HandshakeHeaderHTTP(http.Header{
        "X-Go-Version": []string{runtime.Version()},
    })

    u := ws.Upgrader{
        OnHost: func(host []byte) error {
            if string(host) == "github.com" {
                return nil
            }
            return ws.RejectConnectionError(
                ws.RejectionStatus(403),
                ws.RejectionHeader(ws.HandshakeHeaderString(
                    "X-Want-Host: github.com\r\n",
                )),
            )
        },
        OnHeader: func(key, value []byte) error {
            if string(key) != "Cookie" {
                return nil
            }
            ok := httphead.ScanCookie(value, func(key, value []byte) bool {
                // Check session here or do some other stuff with cookies.
                // Maybe copy some values for future use.
                return true
            })
            if ok {
                return nil
            }
            return ws.RejectConnectionError(
                ws.RejectionReason("bad cookie"),
                ws.RejectionStatus(400),
            )
        },
        OnBeforeUpgrade: func() (ws.HandshakeHeader, error) {
            return header, nil
        },
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Fatal(err)
        }
        _, err = u.Upgrade(conn)
        if err != nil {
            log.Printf("upgrade error: %s", err)
        }
    }
}

Compression

There is a ws/wsflate package to support Permessage-Deflate Compression Extension.

It provides minimalistic I/O wrappers to be used in conjunction with any deflate implementation (for example, the standard library's compress/flate).

It is also compatible with wsutil's reader and writer by providing wsflate.MessageState type, which implements wsutil.SendExtension and wsutil.RecvExtension interfaces.

package main

import (
    "bytes"
    "log"
    "net"

    "github.com/gobwas/ws"
    "github.com/gobwas/ws/wsflate"
)

func main() {
    ln, err := net.Listen("tcp", "localhost:8080")
    if err != nil {
        // handle error
    }
    e := wsflate.Extension{
        // We are using default parameters here since we use
        // wsflate.{Compress,Decompress}Frame helpers below in the code.
        // This assumes that we use standard compress/flate package as flate
        // implementation.
        Parameters: wsflate.DefaultParameters,
    }
    u := ws.Upgrader{
        Negotiate: e.Negotiate,
    }
    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Fatal(err)
        }

        // Reset extension after previous upgrades.
        e.Reset()

        _, err = u.Upgrade(conn)
        if err != nil {
            log.Printf("upgrade error: %s", err)
            continue
        }
        if _, ok := e.Accepted(); !ok {
            log.Printf("didn't negotiate compression for %s", conn.RemoteAddr())
            conn.Close()
            continue
        }

        go func() {
            defer conn.Close()
            for {
                frame, err := ws.ReadFrame(conn)
                if err != nil {
                    // Handle error.
                    return
                }

                frame = ws.UnmaskFrameInPlace(frame)

                if wsflate.IsCompressed(frame.Header) {
                    // Note that even after successful negotiation of
                    // compression extension, both sides are able to send
                    // non-compressed messages.
                    frame, err = wsflate.DecompressFrame(frame)
                    if err != nil {
                        // Handle error.
                        return
                    }
                }

                // Do something with frame...

                ack := ws.NewTextFrame([]byte("this is an acknowledgement"))

                // Compress response unconditionally.
                ack, err = wsflate.CompressFrame(ack)
                if err != nil {
                    // Handle error.
                    return
                }
                if err = ws.WriteFrame(conn, ack); err != nil {
                    // Handle error.
                    return
                }
            }
        }()
    }
}

You can use compression with wsutil package this way:

    // Upgrade somehow and negotiate compression to get the conn...

    // Initialize flate reader. We are using nil as a source io.Reader because
    // we will Reset() it in the message i/o loop below.
    fr := wsflate.NewReader(nil, func(r io.Reader) wsflate.Decompressor {
        return flate.NewReader(r)
    })
    // Initialize flate writer. We are using nil as a destination io.Writer
    // because we will Reset() it in the message i/o loop below.
    fw := wsflate.NewWriter(nil, func(w io.Writer) wsflate.Compressor {
        f, _ := flate.NewWriter(w, 9)
        return f
    })

    // Declare compression message state variable.
    //
    // It has two goals:
    // - Allow users to check whether received message is compressed or not.
    // - Help wsutil.Reader and wsutil.Writer to set/unset appropriate
    //   WebSocket header bits while writing next frame to the wire (it
    //   implements wsutil.RecvExtension and wsutil.SendExtension).
    var msg wsflate.MessageState

    // Initialize WebSocket reader as previously. 
    // Please note the use of Reader.Extensions field as well as
    // of ws.StateExtended flag.
    rd := &wsutil.Reader{
        Source:     conn,
        State:      ws.StateServerSide | ws.StateExtended,
        Extensions: []wsutil.RecvExtension{
            &msg, 
        },
    }

    // Initialize WebSocket writer with ws.StateExtended flag as well.
    wr := wsutil.NewWriter(conn, ws.StateServerSide|ws.StateExtended, 0)
    // Use the message state as wsutil.SendExtension.
    wr.SetExtensions(&msg)

    for {
        h, err := rd.NextFrame()
        if err != nil {
            // handle error.
        }
        if h.OpCode.IsControl() {
            // handle control frame.
        }
        if !msg.IsCompressed() {
            // handle uncompressed frame (skipped for the sake of example
            // simplicity).
        }

        // Reset the writer to echo same op code.
        wr.Reset(h.OpCode)

        // Reset both flate reader and writer to start the new round of i/o.
        fr.Reset(rd)
        fw.Reset(wr)

        // Copy whole message from reader to writer decompressing it and
        // compressing again.
        if _, err := io.Copy(fw, fr); err != nil {
            // handle error.
        }
        // Flush any remaining buffers from flate writer to WebSocket writer.
        if err := fw.Close(); err != nil {
            // handle error.
        }
        // Flush the whole WebSocket message to the wire.
        if err := wr.Flush(); err != nil {
            // handle error.
        }
    }

Download Details:

Author: Gobwas
Source Code: https://github.com/gobwas/ws 
License: MIT license

#go #golang #websocket 

Top 8 Machine Learning Libraries In Go Language One Must Know

Created by Google researchers, Go is a popular open-source programming language. The language includes many intuitive features, including a garbage collector, cross-platform, efficient concurrency, among others.

According to the Stack Overflow Developer Survey 2020, Go language is not only the fifth most loved programming language but also fetches the programmers the third-highest salary among other languages.

Below here, we list down the top machine learning libraries in Go language.

#opinions #go language #google ml tools #machine learning libraries #ml libraries #ml libraries in go

Waylon  Bruen

Waylon Bruen

1649248680

Go-appindicator: Go Bindings for Libappindicator3 C Library

go-appindicator

Go bindings for libappindicator3 C library.

Libappindicator is a library to allow applications to export a menu into the Unity Menu bar. Based on KSNI it also works in KDE and will fallback to generic Systray support if none of those are available.

Also it works in:

This package aims to be interoperable with Go gtk3 bindings.

3 in the name means that it's GTK3 version.

Dependencies

On Debian-based distributions:

apt install libappindicator3-dev libgtk-3-dev

And of course go with cgo is required.

Building

Refer to gotk3 wiki

...or simply run build.sh script that will try to detect currently installed version of GTK, pass along given go build flags and execute it.

For example to build one of examples:

./build.sh -v examples/simple/main.go

Examples

Examples are located in examples directory

Author: Dawidd6
Source Code: https://github.com/dawidd6/go-appindicator 
License: MIT License

#go #golang #library 

Nigel  Uys

Nigel Uys

1652703480

Go-trending: Go Library for Accessing Trending Repositories

go-trending

A package to retrieve trending repositories and developers from Github written in Go.

trending package showcase

Features

  • Get trending repositories
  • Get trending developers
  • Get all programming languages known by GitHub
  • Filtering by time and (programming) language
  • Support for GitHub Enterprise

Installation

It is go gettable

$ go get github.com/andygrunwald/go-trending

or using/updating to the latest master

$ go get -u github.com/andygrunwald/go-trending@master

API

Please have a look at the package documentation for a detailed API description.

Examples

A few examples how the API can be used. More examples are available in the GoDoc examples section.

List trending repositories of today for all languages

package main

import (
    "fmt"

    "github.com/andygrunwald/go-trending"
)

func main() {
    trend := trending.NewTrending()

    // Show projects of today
    projects, err := trend.GetProjects(trending.TimeToday, "")
    if err != nil {
        panic(err)
    }

    for index, project := range projects {
        i := index + 1
        if len(project.Language) > 0 {
            fmt.Printf("%d: %s (written in %s with %d ★ )\n", i, project.Name, project.Language, project.Stars)
        } else {
            fmt.Printf("%d: %s (with %d ★ )\n", i, project.Name, project.Stars)
        }
    }
}

List trending repositories of this week for Go

package main

import (
    "fmt"

    "github.com/andygrunwald/go-trending"
)

func main() {
    trend := trending.NewTrending()

    // Show projects of today
    projects, err := trend.GetProjects(trending.TimeWeek, "go")
    if err != nil {
        panic(err)
    }

    for index, project := range projects {
        i := index + 1
        if len(project.Language) > 0 {
            fmt.Printf("%d: %s (written in %s with %d ★ )\n", i, project.Name, project.Language, project.Stars)
        } else {
            fmt.Printf("%d: %s (with %d ★ )\n", i, project.Name, project.Stars)
        }
    }
}

List trending developers of this month for Swift

package main

import (
    "fmt"

    "github.com/andygrunwald/go-trending"
)

func main() {
    trend := trending.NewTrending()

    developers, err := trend.GetDevelopers(trending.TimeMonth, "swift")
    if err != nil {
        panic(err)
    }

    for index, developer := range developers {
        i := index + 1
        fmt.Printf("%d: %s (%s)\n", i, developer.DisplayName, developer.FullName)
    }
}

List available languages

package main

import (
    "fmt"

    "github.com/andygrunwald/go-trending"
)

func main() {
    trend := trending.NewTrending()

    // Show languages
    languages, err := trend.GetLanguages()
    if err != nil {
        panic(err)
    }

    for index, language := range languages {
        i := index + 1
        fmt.Printf("%d: %s (%s)\n", i, language.Name, language.URLName)
    }
}

Inspired by

Author: Andygrunwald
Source Code: https://github.com/andygrunwald/go-trending 
License: MIT license

#go #golang #hacktoberfest #library