Chat in contact as a terminal

    Inspired by the post “A simple task manager with a web interface, written in the GO language for Unix systems including Android” , the Go language and the simple status utility , I decided to write a chatbot for the Vkontakte social network with similar functionality as a fun experiment.

    Why did you choose chatbot and social network? In addition to the obvious just for fun, there are practical calculations:
    • No additional gestures are needed to access the application running on a computer with a dynamic ip or located behind a router.
    • Access to VKontakte is almost everywhere - just have a telephone with Internet access.
    • The issue of implementing authentication at the end-application level almost disappears.


    The utility is a simple chat bot that responds to text commands. We write a message to VK to ourselves, the utility polls the VK API with a certain frequency and receives a list of messages. Then it remains only to compare the entered message with a list of predefined text commands.
    Nothing complicated, though there are some nuances you need to know about VK API.
    Firstly, to access personal messages, you need to register the VK application as desktop. And at the request access token, set the rights to access private messages and the “blank” page for callback.
    The address for access token will look something like this:
    https://oauth.vk.com/authorize?client_id=#####&scope=offline,messages&redirect_uri=https%3A%2F%2Foauth.vk.com%2Fblank.html&display=page&v=5.28&response_type=token

    Secondly, there is a limit on the number of requests per second, so messages are received with a timer of 2 seconds.
    	c := time.Tick(2 * time.Second)
    	lastMsgId := int64(0)
    	for _ = range c {
    		msgs, err := getMsgs(lastMsgId)
    		if err != nil {
    			fmt.Println(err)
    		} else {
    			if len(msgs.Response.Items) > 0 {
    				lastMsgId = msgs.Response.Items[0].Id
    			}
    			for _, msg := range msgs.Response.Items {
    				msgBody := strings.Trim(msg.Body, "")
    				if checkVkId(msg.UserId) && checkTime(msg.Date) && checkResultPrefix(msgBody) {
    					go doCmd(msgBody)
    				}
    			}
    		}
    	}
    

    Parsing an incoming message and sending the result of the command:

    func doSysCmd(msg string) {
    	switch true {
    	case strings.HasPrefix(msg, "@sys/host"):
    		sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetHost()))
    	case strings.HasPrefix(msg, "@sys/disk"):
    		sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetDisk("/")))
    	case strings.HasPrefix(msg, "@sys/load"):
    		sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetLoad()))
    	case strings.HasPrefix(msg, "@sys/ram"):
    		sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetRam()))
    	case strings.HasPrefix(msg, "@sys"):
    		sendMsg(*vk_id, fmt.Sprintf("\n%+v", sysstat.GetSystem("/")))
    	case strings.HasPrefix(msg, "@sh"):
    		args := strings.SplitN(msg, " ", 2)
    		if len(args) < 2 {
    			return
    		}
    		fmt.Println("exec: ", args[1])
    		sendMsg(*vk_id, fmt.Sprintf(" %+v", sysstat.ExecShell(args[1])))
    	}
    }
    

    In addition to obtaining the current status of the system as a bonus, you can save arbitrary notes with the commands:
    ! list - display the saved list with id numbers
    ! add [text] - add a new record
    ! del [number] - delete the record with the specified id

    Notes are stored exclusively in memory.
    Protection against application crash is not provided, I took for practice to run such things under a supervisor, which itself restarts the application if a critical error occurs. RAM consumption for go programs is traditionally minimal and fluctuates around 10 MB, the supervisor takes up the same amount.

    Sources on github .

    Also popular now: