1// This program is free software: you can redistribute it and/or modify2// it under the terms of the GNU Affero General Public License as3// published by the Free Software Foundation, either version 3 of the4// License, or (at your option) any later version.5//6// This program is distributed in the hope that it will be useful, but7// WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU9// Affero General Public License for more details.10//11// You should have received a copy of the GNU Affero General Public12// License along with this program. If not, see <http://www.gnu.org/licenses/>.1314package spacestatus1516import (17 "encoding/json"18 "errors"19 "github.com/nmeum/marvin/irc"20 "github.com/nmeum/marvin/modules"21 "io/ioutil"22 "net/http"23 "time"24)2526// Supported SpaceAPI version27const apiVersion = "0.13"2829type spaceapi struct {30 API string `json:"api"`31 Space string `json:"space"`32 State struct {33 Open bool `json:"open"`34 } `json:"state"`35}3637type Module struct {38 api *spaceapi39 URL string `json:"url"`40 Notify bool `json:"notify"`41 Interval string `json:"interval"`42}4344func Init(moduleSet *modules.ModuleSet) {45 moduleSet.Register(new(Module))46}4748func (m *Module) Name() string {49 return "spacestatus"50}5152func (m *Module) Help() string {53 return "USAGE: !spacestatus"54}5556func (m *Module) Defaults() {57 m.Notify = true58 m.Interval = "0h15m"59}6061func (m *Module) Load(client *irc.Client) error {62 if len(m.URL) <= 0 {63 return nil64 }6566 duration, err := time.ParseDuration(m.Interval)67 if err != nil {68 return err69 }7071 if err := m.updateHandler(client); err != nil {72 return err73 }7475 if m.api.API != apiVersion {76 return errors.New("unsupported spaceapi version")77 }7879 go func(c *irc.Client) {80 for {81 time.Sleep(duration)82 m.updateHandler(c)83 }84 }(client)8586 client.CmdHook("privmsg", m.statusCmd)87 return nil88}8990func (m *Module) updateHandler(client *irc.Client) error {91 var oldState bool92 if m.api == nil {93 oldState = false94 } else {95 oldState = m.api.State.Open96 }9798 firstPoll := m.api == nil99 if err := m.pollStatus(); err != nil {100 return err101 }102103 newState := m.api.State.Open104 if newState != oldState && m.Notify && !firstPoll {105 m.notify(client, newState)106 }107108 return nil109}110111func (m *Module) pollStatus() error {112 resp, err := http.Get(m.URL)113 if err != nil {114 return err115 }116 defer resp.Body.Close()117118 data, err := ioutil.ReadAll(resp.Body)119 if err != nil {120 return err121 }122123 if err := json.Unmarshal(data, &m.api); err != nil {124 return err125 }126127 return nil128}129130func (m *Module) statusCmd(client *irc.Client, msg irc.Message) error {131 if msg.Data != "!spacestatus" {132 return nil133 } else if m.api == nil {134 return client.Write("NOTICE %s :Status currently unknown.",135 msg.Receiver)136 }137138 var state string139 if m.api.State.Open {140 state = "open"141 } else {142 state = "closed"143 }144145 return client.Write("NOTICE %s :%s is currently %s",146 msg.Receiver, m.api.Space, state)147}148149func (m *Module) notify(client *irc.Client, open bool) {150 var oldState, newState string151 if open {152 oldState = "closed"153 newState = "open"154 } else {155 oldState = "open"156 newState = "closed"157 }158159 for _, ch := range client.Channels {160 client.Write("NOTICE %s :%s changed door status from %s to %s",161 ch, m.api.Space, oldState, newState)162 }163}