akari

package module
v0.0.0-...-546d108 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2021 License: GPL-3.0 Imports: 15 Imported by: 0

README

Akari Message Framework

License Go Walker GoDoc Go Report Card

Akari is a message framework written in Go (Golang). It follows KISS (Keep it simple, stupid) design principle, and is designed for IoT communication and notification push from *nix side to any device.

Quickstart

Download and install source
$ go get github.com/YKMeIz/akari
Create a user

Assume you have installed SQLite in your host system.

In the example below, we want to create new user Akari, and output new token for Akari:

package main

import (
	"fmt"
	"github.com/YKMeIz/akari"
)

func main() {
	// Create a database file
	akari.InitDatabase("/tmp/data.db")

	// Create a new user
	u := akari.User{Name: "Akari"}
	name, token, err := u.RegisterUser()
	if err != nil {
		panic(err)
	}
	fmt.Println("Create User: " + name)
	fmt.Println(name + "'s token is: " + token)
}

Run the Go file you just write (e.g. createUser.go). The output should look like following:

$ go run createUser.go
Create User: Akari
Akari's token is: f6283b29169cf8c1e84bf23cf86772fb
Run Akari based server

Start Akari based server is quite simple. Only having a few basic settings, it will handle all dirty works. Here is an example:

package main

import (
	"fmt"
	"github.com/YKMeIz/akari"
)

func main() {
	c := akari.New()
	c.DatabasePath = "/tmp/data.db"

	// Custom function
	c.Event["PRINT"] = eventPrint

	// Listen and serve on IPAddress:8080
	c.Run()
}

// Custom function
func eventPrint(m *akari.Message) error {
	fmt.Println(m.Data["customFunc"])
	return nil
}

Run the Go file you just write (e.g. akariServer.go). The output should look like following:

$ go run akariServer.go

Server listens on:    10.0.0.192:8080
TLS/SSL is            Disabled
POST API Address:     10.0.0.192:8080/nc
Websocket Address:    10.0.0.192:8080/ws
Database Path:        /tmp/data.db

Output above is default setting. Akari based server could detect your IP address and listen on port 8080.

Note: In order to run the server, you need to set database path at least.

Trigger your custom function
curl -H "Content-Type: application/json" \
-X POST \
-d '{"Source": "f6283b29169cf8c1e84bf23cf86772fb", "Destination": ["HANDLERFUNC", "PRINT"], "Data": {"customFunc": "This is custom function content."}}' \
http://10.0.0.192:8080/nc

If you get {"Status":"ok!"}, you will see This is custom function content. is printed in terminal:

$ go run akariServer.go

Server listens on:    10.0.0.192:8080
TLS/SSL is            Disabled
POST API Address:     10.0.0.192:8080/nc
Websocket Address:    10.0.0.192:8080/ws
Database Path:        /tmp/data.db

This is custom function content.
[GIN] 2016/12/08 - 13:22:50 | 200 |     107.267µs | 10.0.0.192 |   POST    /nc

gin-gonic/gin is currently used for handling HTTP requests because Akari's own HTTP handler is still under developing.

How it works

Akari message framework serves a HTTP POST API to receive HTTP requests, and serves a websocket service to communicate with any device suppoets websocket. It receives messages from HTTP POST request or websocket. Then pushing messages to target destination(s).

Akari message framework also supports to broadcast messages; send message to third party services, such as Pushbullet; or perform a custom behavior.

Features

Mandatory Identity Authentication

Akari message framework identifies every device by token. Each message must have correct token of Source and Destination. When a device try to connect websocket service, it needs to provide its identity in 30 second in order to register itself. Otherwise, websocket service will reject and close the connection.

However, for human readable purpose, token is stored with name:

{
   "Name":"Akari",
   "Token":"f6283b29169cf8c1e84bf23cf86772fb"
}
Unified Message Format

All messages sent to or sent by Akari message framework has an unified format. It means all messages transferred with Akari message framework must follow this Json format:

{
   "Source":"example token",
   "Destination":[
      "example token or special command",
      "example token"
   ],
   "Data":{
      "example 1":"example",
      "example 2":"example"
   }
}

Akari message framework reads and check Source and Destination to determine where the message is from and where the message is going. Data is utilized for users to exchange information.

Broadcast

If Destination set as ["BROADCAST"], Akari based server will broadcast this message to every device registered as online.

{
   "Source":"example token",
   "Destination":[
      "BROADCAST"
   ],
   "Data":{
      "example 1":"example",
      "example 2":"example"
   }
}
Custom Function

In order to run a custom function set in Event map, Destination need to be set as ["HANDLERFUNC"] with your Event name following.

For example, if your custom function (PRINT) is:

func main() {
	// (Rest of main)

	// Custom function
	// "PRINT" is the Event name
	c.Event["PRINT"] = eventPrint

	// (Rest of main)
}

// Custom function
func eventPrint(m *akari.Message) error {
	fmt.Println(m.Data["customFunc"])
	return nil
}

Your message should look like this:

{
   "Source":"example token",
   "Destination":[
      "HANDLERFUNC",
      "PRINT"
   ],
   "Data":{
      "example 1":"example",
      "example 2":"example"
   }
}
Pushbullet Support

Akari message framework supports sending notification via Pushbullet. Set "Destination":["PUSHBULLET"] to send a message to Pushbullet service.

Currently, only support sending "push" notification in type "note".

{
   "Source":"example token",
   "Destination":[
      "PUSHBULLET",
      "example token",
      "example token"
   ],
   "Data":{
      "Type":"note",
      "Title":"push a note",
      "Body":"note body",
      "AccessToken":"your Pushbullet token"
   }
}

If you set multiple destinations, Akari based server will try to send the message to the destinations following "HPUSHBULLET". If one of those destinations is offline, Akari based server will send the message to Pushbullet. This method could be seen as adding an alternative destination for receiving notification.

Note: "Data" should have same format as example above. Otherwise, Pushbullet notification would fail to send.

Documentation

Index

Constants

View Source
const (
	REGISTEROK string = `{"Status": "ok!"}`
	REGISTERER string = `Wrong user name or token.`
	REGISTEROL string = `Your device is already online.`
	REGISTERTO string = `Id authentication is required.`
	PBPUSHNERR string = `Fail to send Pushbullet notification.`
	HANDLERFER string = `An error occurred on running custom handler function.`
	MESSAGEERR string = `Missing source or destination.`
)

Constant strings for return request/message status.

Variables

This section is empty.

Functions

func GenerateToken

func GenerateToken() string

GenerateToken returns a new token.

func IPAddress

func IPAddress() (string, error)

IPAddress returns host system's IP address. It does not return loopback address (localhost). If there is not any public IP address, it will return local area network address.

func InitDatabase

func InitDatabase(databasePath string)

InitDatabase Initializes a new SQLite database file. It is only utilized for first time initialization. If you have already initialized a database file, please run OpenDatabase() instead.

func IsDatabaseConnected

func IsDatabaseConnected() bool

IsDatabaseConnected checks if database is opened.

Types

type Core

type Core struct {
	// Server's domain name.
	Domain string

	// Port number listened by Akari Message Framework.
	Port string

	// Domain's certificate chain.
	CertChain string

	// Domain's privatekey.
	CertKey string

	// Relative path for handling HTTP POST requests.
	MessageRelativePath string

	// Relative path for providing websocket service.
	WebsocketRelativePath string

	// Path to SQLite database file.
	DatabasePath string

	// Event is a map points to your custom functions.
	Event map[string]HandlerFunc
}

Core is the framework's instance, it contains all configuration settings. Create an instance of Core, by using New().

func New

func New() *Core

New returns a new blank Core instance. By default the configuration is: Domain: your host system's IP address (Not localhost). Port: "8080". MessageRelativePath: "/nc". WebsocketRelativePath: "/ws". Note: You need set DatabasePath before Run().

func (Core) OpenDatabase

func (c Core) OpenDatabase()

OpenDatabase opens an exist SQLite database file.

func (Core) Run

func (c Core) Run()

Run a Core instance. It starts listening and serving websocket & HTTP requests. If "CertChain" and "CertKey" are set, it will automatically start listening and serving secure websocket & HTTPS requests.

type HandlerFunc

type HandlerFunc func(*Message) error

HandlerFunc is the type of custom function.

type Message

type Message struct {
	// Message sender's token.
	Source string

	// Message receiver's token.
	Destination []string

	// Message content.
	Data map[string]string
}

Message defines "Unified Message Format". Examples could be found on https://github.com/nrechn/akari .

func ReadMessage

func ReadMessage(msg string) (Message, error)

ReadMessage reads a string of Message content, and returns in Message type.

type PushbulletPush

type PushbulletPush struct {
	// Type of the push, one of "note", "file", "link".
	// Akari currently only supports type "note".
	PushType string

	// Title of the push, used for all types of pushes.
	Title string

	// Body of the push, used for all types of pushes.
	Body string

	// Access Token of your account.
	AccessToken string
}

PushbulletPush defines Pushbullet's push action (notification).

func (*PushbulletPush) Push

func (p *PushbulletPush) Push() (err error)

Push sends a POST request to Pushbullet server in order to make a Pushbullet push notification.

type User

type User struct {
	// Name of a user.
	Name string

	// Token is usually generated by system.
	Token string
}

User defines user information.

func (User) IsUser

func (u User) IsUser() bool

IsUser checks if given user information is exist in database/system. It accepts one of user information, or both "Name" and "Token". Return true for exist; false for not exist.

func (User) RegisterUser

func (u User) RegisterUser() (string, string, error)

RegisterUser registers a new user to database. It only accepts username with empty "Token". Return username, user's new token, error.

func (User) RevokeUser

func (u User) RevokeUser() error

RevokeUser revokes a user from database.

func (*User) UserCompletion

func (u *User) UserCompletion() error

UserCompletion complets user information. Give one of user information, it will fill the missing value. Return error if giving both "Name" and "Token", or user is not found.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL