imessage

package module
v2.1.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2019 License: MIT Imports: 15 Imported by: 0

README

go-imessage

Go Library used to interact with iMessage (Messages.app) on macOS

Use this library to send and receive messages using iMessage. I personally use it for various home automation applications. You can use it to make a chat bot or something similar. You can bind either a function or a channel to any or all messages. The Send() method uses AppleScript, which is likely going to require some tinkering. You got this far, so I trust you'll figure that out. Let me know how it works out.

The library uses fsnotify to poll for db updates, then checks the database for changes. Only new messages are processed. If somehow fsnotify fails it will fall back to polling the database. Pay attention to the debug/error logs. See the example below for an easy way to log the library messages.

A working example:

package main

import (
	"log"
	"os"
	"strings"

	"golift.io/imessage"
)

func checkErr(err error) {
	if err != nil {
		log.Fatalln(err)
	}
}

func main() {
	iChatDBLocation := "/Users/<your username>/Library/Messages/chat.db"
	c := &imessage.Config{
		SQLPath:   iChatDBLocation, // Set this correctly
		QueueSize: 10,              // 10-20 is fine. If your server is super busy, tune this.
		Retries:   3,               // run the applescript up to this many times to send a message. 3 works well.
		DebugLog:  log.New(os.Stdout, "[DEBUG] ", log.LstdFlags), // Log debug messages.
		ErrorLog:  log.New(os.Stderr, "[ERROR] ", log.LstdFlags), // Log errors.
	}
	s, err := imessage.Init(c)
	checkErr(err)

	done := make(chan imessage.Incoming) // Make a channel to receive incoming messages.
	s.IncomingChan(".*", done)           // Bind to all incoming messages.
	err = s.Start()                      // Start outgoing and incoming message go routines.
	checkErr(err)
	log.Print("waiting for msgs")

	for msg := range done { // wait here for messages to come in.
		if len(msg.Text) < 60 {
			log.Println("id:", msg.RowID, "from:", msg.From, "attachment?", msg.File, "msg:", msg.Text)
		} else {
			log.Println("id:", msg.RowID, "from:", msg.From, "length:", len(msg.Text))
		}
		if strings.HasPrefix(msg.Text, "Help") {
			// Reply to any incoming message that has the word "Help" as the first word.
			s.Send(imessage.Outgoing{Text: "no help for you", To: msg.From})
		}
	}
}

Documentation

Overview

Package imessage is used to interact with iMessage (Messages.app) on macOS

Use this library to send and receive messages using iMessage. Can be used to make a chat bot or something similar. You can bind either a function or a channel to any or all messages. The Send() method uses AppleScript, which is likely going to require some tinkering. You got this far, so I trust you'll figure that out. Let me know how it works out.

The library uses `fsnotify` to poll for db updates, then checks the database for changes. Only new messages are processed. If somehow `fsnotify` fails it will fall back to polling the database. Pay attention to the debug/error logs.

Index

Constants

This section is empty.

Variables

View Source
var DefaultDuration = 200 * time.Millisecond

DefaultDuration is the minimum interval that must pass before opening the database again.

View Source
var OSAScriptPath = "/usr/bin/osascript"

OSAScriptPath is the path to the osascript binary. macOS only.

Functions

This section is empty.

Types

type Callback

type Callback func(msg Incoming)

Callback is the type used to return an incoming message to the consuming app. Create a function that matches this interface to process incoming messages using a callback (as opposed to a channel).

type Config

type Config struct {
	// ClearMsgs will cause this library to clear all iMessage conversations.
	ClearMsgs bool `xml:"clear_messages" json:"clear_messages,_omitempty" toml:"clear_messages,_omitempty" yaml:"clear_messages"`
	// This is the channel buffer size.
	QueueSize int `xml:"queue_size" json:"queue_size,_omitempty" toml:"queue_size,_omitempty" yaml:"queue_size"`
	// How many applescript retries to perform.
	Retries int `xml:"retries" json:"retries,_omitempty" toml:"retries,_omitempty" yaml:"retries"`
	// Timeout in seconds for AppleScript Exec commands.
	Timeout int `xml:"timeout" json:"timeout,_omitempty" toml:"timeout,_omitempty" yaml:"timeout"`
	// SQLPath is the location if the iMessage database.
	SQLPath string `xml:"sql_path" json:"sql_path,_omitempty" toml:"sql_path,_omitempty" yaml:"sql_path"`
	// Loggers.
	ErrorLog Logger `xml:"-" json:"-" toml:"-" yaml:"-"`
	DebugLog Logger `xml:"-" json:"-" toml:"-" yaml:"-"`
}

Config is our input data, data store, and interface to methods. Fill out this struct and pass it into imessage.Init()

type Incoming

type Incoming struct {
	RowID int64  // RowID is the unique database row id.
	From  string // From is the handle of the user who sent the message.
	Text  string // Text is the body of the message.
	File  bool   // File is true if a file is attached. (no way to access it atm)
}

Incoming is represents a message from someone. This struct is filled out and sent to incoming callback methods and/or to bound channels.

type Logger

type Logger interface {
	Print(v ...interface{})
	Printf(fmt string, v ...interface{})
	Println(v ...interface{})
}

Logger is a base interface to deal with changing log outs. Pass a matching interface (like log.Printf) to capture messages from the running background go routines.

type Messages

type Messages struct {
	*Config // Input config.
	// contains filtered or unexported fields
}

Messages is the interface into this module. Init() returns this struct. All of the important library methods are bound to this type. ErrorLog and DebugLog can be set directly, or use the included methods to set them.

func Init

func Init(config *Config) (*Messages, error)

Init is the primary function to retrieve a Message handler. Pass a Config struct in and use the returned Messages struct to send and respond to incoming messages.

func (*Messages) ClearMessages

func (m *Messages) ClearMessages() error

ClearMessages deletes all conversations in MESSAGES.APP. Use this only if Messages is behaving poorly. Or, never use it at all. This probably doesn't do anything you want to do.

func (*Messages) IncomingCall

func (m *Messages) IncomingCall(match string, callback Callback)

IncomingCall connects a callback function to a matched string in a message. This methods creates a callback that is run in a go routine any time a message containing `match` is found. Use '.*' for all messages. Supports regexp.

func (*Messages) IncomingChan

func (m *Messages) IncomingChan(match string, channel chan Incoming)

IncomingChan connects a channel to a matched string in a message. Similar to the IncomingCall method, this will send an incoming message to a channel. Any message with text matching `match` is sent. Regexp supported. Use '.*' for all messages. The channel blocks, so avoid long operations.

func (*Messages) RemoveCall

func (m *Messages) RemoveCall(match string) int

RemoveCall deletes a message match to function callback made with IncomingCall()

func (*Messages) RemoveChan

func (m *Messages) RemoveChan(match string) int

RemoveChan deletes a message match to channel made with IncomingChan()

func (*Messages) RunAppleScript

func (m *Messages) RunAppleScript(scripts []string) (success bool, errs []error)

RunAppleScript runs a script on the local system. While not directly related to iMessage and Messages.app, this library uses AppleScript to send messages using imessage. To that end, the method to run scripts is also exposed for convenience.

func (*Messages) Send

func (m *Messages) Send(msg Outgoing)

Send is the method used to send an iMessage. Thread/routine safe. The messages are queued in a channel and sent 1 at a time with a small delay between. Each message may have a callback attached that is kicked off in a go routine after the message is sent.

func (*Messages) Start

func (m *Messages) Start() error

Start starts the iMessage-sqlite3 db and outgoing message watcher routine(s). Outgoing messages wont work and incoming message are ignored until Start() runs.

func (*Messages) Stop

func (m *Messages) Stop()

Stop cancels the iMessage-sqlite3 db and outgoing message watcher routine(s). Outgoing messages stop working when the routines are stopped. Incoming messages are ignored after this runs.

type Outgoing

type Outgoing struct {
	ID   string          // ID is only used in logging and in the Response callback.
	To   string          // To represents the message recipient.
	Text string          // Text is the body of the message or file path.
	File bool            // If File is true, then Text is assume to be a filepath to send.
	Call func(*Response) // Call is the function that is run after a message is sent off.
}

Outgoing struct is used to send a message to someone. Fll it out and pass it into Messages.Send() to fire off a new iMessage.

type Response

type Response struct {
	ID   string
	To   string
	Text string
	Sent bool
	Errs []error
}

Response is the outgoing-message response provided to a callback function. An outgoing callback function will receive this type. It represents "what happeened" when trying to send a message. If `Sent` is false, `Errs` should contain error(s).

Jump to

Keyboard shortcuts

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