让我解释一下这个想法。我想在一个文件夹中每次生成新文件时发出一条 RabbitMQ 消息。问题是,我不能修改生成文件的软件的代码。我们的想法是生成一个文件系统观察器,以发射消息。让我们开始吧。
我不是围棋专家,但围棋对于这种任务来说是很好的。你可以创建一个可执行文件,然后复制到所需的服务器中,就可以了。就可以了。
还有一个fsnotify包可以监听文件系统事件。我过去曾在PHP和Python中使用fsnotify。
func main() {
config := GetConf()
watcher, _ = fsnotify.NewWatcher()
defer watcher.Close()
if err := filepath.Walk(config.Path, watchDir); err != nil {
fmt.Println("ERROR", err)
}
done := make(chan bool)
go func() {
for {
select {
case event := <-watcher.Events:
processEvent(event, *config)
case err := <-watcher.Errors:
fmt.Println("ERROR", err)
}
}
}()
<-done
}
func processEvent(event fsnotify.Event, conf Conf) {
filePath := event.Name
fileName := filepath.Base(filePath)
switch op := event.Op.String(); op {
case "CREATE":
if strings.HasSuffix(filePath, conf.Extension) {
bytes, _ := copy(event.Name, conf.CopyTo+fileName)
if bytes > 0 {
emitEvent(fileName, conf)
}
}
default:
fmt.Println("Unhandled event: ", op, " on file: ", fileName)
}
}
基本上这就是全部。我们只需要注意文件系统的事件。Fsnotify是非常低级的,当我们使用它时,我们意识到程序是如何写文件的。有些程序会创建一个临时文件,然后写下它,最后重命名该文件。有时,程序会创建一个空文件,最后写入文件。基本上是一样的,但事件是不同的。在我的例子中,我只监听 "CREATE",这对我的测试来说就足够了。
向 RabbitMQ 发出事件也很简单。在文档中得到了很好的记录。
func emitEvent(fileName string, conf Conf) {
fmt.Println("Event on file", fileName)
message := map[string]interface{}{
"fileName": fileName,
}
bytesRepresentation, err := json.Marshal(message)
if err != nil {
log.Println(err)
} else {
emmitToRabbit(conf, bytesRepresentation)
}
}
在这个例子中,我还想使用 YAML 文件来存储配置。只是为了学习如何在 Go 中读取 YAML 文件。
type Conf struct {
Path string `yaml:"path"`
CopyTo string `yaml:"copy_to"`
Extension string `yaml:"extension"`
BrokerTopic string `yaml:"brokerTopic"`
Broker string `yaml:"broker"`
}
func readConf(filename string) (*Conf, error) {
buf, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
c := &Conf{}
err = yaml.Unmarshal(buf, c)
if err != nil {
return nil, fmt.Errorf("in file %q: %v", filename, err)
}
return c, nil
}
这就是全部。我的二进制可执行文件已经准备好了。
完整的代码在我的github上