decentral1se 3 months ago
commit
186eb038db
No known key found for this signature in database GPG Key ID: 3789458B3D0C410
  1. 34
      .goreleaser.yaml
  2. 34
      README.md
  3. 1
      assets/.gitignore
  4. 14
      assets/assets.go
  5. 1
      dist/artifacts.json
  6. 135
      dist/config.yaml
  7. 1
      dist/metadata.json
  8. 14
      dist/mist-connections_0.0.0-SNAPSHOT-none_checksums.txt
  9. BIN
      dist/mist-connections_darwin_amd64/mist-connections
  10. BIN
      dist/mist-connections_darwin_arm64/mist-connections
  11. BIN
      dist/mist-connections_linux_386/mist-connections
  12. BIN
      dist/mist-connections_linux_amd64/mist-connections
  13. BIN
      dist/mist-connections_linux_arm64/mist-connections
  14. BIN
      dist/mist-connections_linux_arm_5/mist-connections
  15. BIN
      dist/mist-connections_linux_arm_6/mist-connections
  16. BIN
      dist/mist-connections_linux_arm_7/mist-connections
  17. BIN
      dist/mist-connections_windows_386/mist-connections.exe
  18. BIN
      dist/mist-connections_windows_amd64/mist-connections.exe
  19. BIN
      dist/mist-connections_windows_arm64/mist-connections.exe
  20. BIN
      dist/mist-connections_windows_arm_5/mist-connections.exe
  21. BIN
      dist/mist-connections_windows_arm_6/mist-connections.exe
  22. BIN
      dist/mist-connections_windows_arm_7/mist-connections.exe
  23. 5
      go.mod
  24. 2
      go.sum
  25. 16
      makefile
  26. BIN
      mist-connections
  27. 308
      mist-connections.go
  28. 59
      public/index.html

34
.goreleaser.yaml

@ -0,0 +1,34 @@
---
project_name: mist-connections
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- 386
- amd64
- arm
- arm64
goarm:
- 5
- 6
- 7
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
format: binary

34
README.md

@ -0,0 +1,34 @@
# mist-connections
> [A missed connection is a type of personal advertisement which arises after two people meet but are too shy or otherwise unable to exchange contact details.](https://en.m.wikipedia.org/wiki/Missed_connection)
[Moar](https://git.vvvvvvaria.org/decentral1se/unnamed-project) post-calibre prototypin' :tada:
## demo
[`msc.mp4`](https://vvvvvvaria.org/~decentral1se/msc/msc.mp4)
## install
[linux](./dist/mist-connections_linux_amd64/mist-connections) | [macosx](./dist/mist-connections_darwin_amd64/mist-connections) | [windoze](./dist/mist-connections_windows_amd64/mist-connections.exe) | ["other"](./dist)
`chmod +x mist-connections && ./mist-connections`
No Idea what you do on Windoze :shrug:
## hack
`go install github.com/go-bindata/go-bindata/...`
`make`
## release
`go install github.com/goreleaser/goreleaser@latest`
`make release`
## ack
- [`@simoon`](https://git.vvvvvvaria.org/simoon)
- [`unnamed project`](https://git.vvvvvvaria.org/decentral1se/unnamed-project)

1
assets/.gitignore

@ -0,0 +1 @@
assets_gen.go

14
assets/assets.go

@ -0,0 +1,14 @@
package assets
import (
assetfs "github.com/elazarl/go-bindata-assetfs"
)
func AssetFS() *assetfs.AssetFS {
return &assetfs.AssetFS{
Asset: Asset,
AssetDir: AssetDir,
AssetInfo: AssetInfo,
Prefix: "public",
}
}

1
dist/artifacts.json

File diff suppressed because one or more lines are too long

135
dist/config.yaml

@ -0,0 +1,135 @@
project_name: mist-connections
release:
name_template: '{{.Tag}}'
scoop:
name: mist-connections
commit_author:
name: goreleaserbot
email: goreleaser@carlosbecker.com
commit_msg_template: Scoop update for {{ .ProjectName }} version {{ .Tag }}
builds:
- id: mist-connections
goos:
- linux
- windows
- darwin
goarch:
- "386"
- amd64
- arm
- arm64
goarm:
- "5"
- "6"
- "7"
gomips:
- hardfloat
targets:
- linux_386
- linux_amd64
- linux_arm_5
- linux_arm_6
- linux_arm_7
- linux_arm64
- windows_386
- windows_amd64
- windows_arm_5
- windows_arm_6
- windows_arm_7
- windows_arm64
- darwin_amd64
- darwin_arm64
dir: .
main: .
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
-X main.builtBy=goreleaser
binary: mist-connections
env:
- CGO_ENABLED=0
builder: go
gobinary: go
archives:
- id: default
builds:
- mist-connections
name_template: '{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{
.Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}'
replacements:
"386": i386
amd64: x86_64
darwin: Darwin
linux: Linux
windows: Windows
format: binary
files:
- src: license*
- src: LICENSE*
- src: readme*
- src: README*
- src: changelog*
- src: CHANGELOG*
snapshot:
name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}'
checksum:
name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt'
algorithm: sha256
dist: dist
env_files:
github_token: ~/.config/goreleaser/github_token
gitlab_token: ~/.config/goreleaser/gitlab_token
gitea_token: ~/.config/goreleaser/gitea_token
before:
hooks:
- go mod tidy
- go generate ./...
source:
name_template: '{{ .ProjectName }}-{{ .Version }}'
format: tar.gz
gomod:
gobinary: go
announce:
twitter:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
reddit:
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
url_template: '{{ .ReleaseURL }}'
slack:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
username: GoReleaser
discord:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
author: GoReleaser
color: "3888754"
icon_url: https://goreleaser.com/static/avatar.png
teams:
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
color: '#2D313E'
icon_url: https://goreleaser.com/static/avatar.png
smtp:
subject_template: '{{ .ProjectName }} {{ .Tag }} is out!'
body_template: 'You can view details from: {{ .ReleaseURL }}'
mattermost:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
username: GoReleaser
linkedin:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
telegram:
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL
}}'
webhook:
message_template: '{ "message": "{{ .ProjectName }} {{ .Tag }} is out! Check it
out at {{ .ReleaseURL }}"}'
content_type: application/json; charset=utf-8
github_urls:
download: https://github.com
gitlab_urls:
download: https://gitlab.com

1
dist/metadata.json

@ -0,0 +1 @@
{"project_name":"mist-connections","tag":"v0.0.0","previous_tag":"","version":"0.0.0-SNAPSHOT-none","commit":"none","date":"2022-05-27T01:05:14.857567458+02:00"}

14
dist/mist-connections_0.0.0-SNAPSHOT-none_checksums.txt

@ -0,0 +1,14 @@
246e636396109d15e073881000d808069f46b682c4daef80988a43bbd3674c3e mist-connections_0.0.0-SNAPSHOT-none_Windows_arm64.exe
30aee71a86c8edc3ad15b84badbcfb0934d465bfa42d6e4e7a7b9daa0117e8a4 mist-connections_0.0.0-SNAPSHOT-none_Linux_i386
38ed44866777fc2c68ca306bb029fab89ce7cf65e9834bbbfd291b112f124ea3 mist-connections_0.0.0-SNAPSHOT-none_Windows_x86_64.exe
3d11aeed197d1d729d8d982afc6fe35956c2abd8c79d474f4f687e2bb9b12842 mist-connections_0.0.0-SNAPSHOT-none_Windows_i386.exe
5834b4caff35ebe55721cecd6d5fa4fcbdac061f9cb5b46f8feaf4c948ee07c2 mist-connections_0.0.0-SNAPSHOT-none_Windows_armv5.exe
6d4188c16b5e630671ede9893c8e672e4187c685eb7fe7a83118afc74be1a8df mist-connections_0.0.0-SNAPSHOT-none_Darwin_x86_64
7680c2df37a21fcca506297d7829ac641a77613010c21f40ebe2b41e4fac89d2 mist-connections_0.0.0-SNAPSHOT-none_Linux_armv5
91b2f66864980a60a26ce02d785f0adf48e3681f6a1afb0237aef41606452d22 mist-connections_0.0.0-SNAPSHOT-none_Linux_armv7
98735c023bfebcea801735a31e89598843ff5189b599fbe045b09d875abc2bf5 mist-connections_0.0.0-SNAPSHOT-none_Windows_armv6.exe
9ca7630e6e9a336b438bc83a12b2cbfdb881a06a5f0dc6ecf0d5b54b4fe9c1ba mist-connections_0.0.0-SNAPSHOT-none_Linux_arm64
a2d30cc95dda65f12a87be4d89f7b03d58960d454a22658c0df7f6fdcbd5ddaf mist-connections_0.0.0-SNAPSHOT-none_Linux_armv6
b9ddddd9626bee169a0696928f8e81d560f29daddf16b9c379b14cea6f97eaea mist-connections_0.0.0-SNAPSHOT-none_Windows_armv7.exe
bbd8e26a261847d74146bf7c1279bdf31e9db629c9039324b853dc3f95657947 mist-connections_0.0.0-SNAPSHOT-none_Linux_x86_64
f0d94cff0f8d30d8bc7c039cb8e63178cfd3e2d30f6f61698f2b9b1d1a484d73 mist-connections_0.0.0-SNAPSHOT-none_Darwin_arm64

BIN
dist/mist-connections_darwin_amd64/mist-connections

Binary file not shown.

BIN
dist/mist-connections_darwin_arm64/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_386/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_amd64/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_arm64/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_arm_5/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_arm_6/mist-connections

Binary file not shown.

BIN
dist/mist-connections_linux_arm_7/mist-connections

Binary file not shown.

BIN
dist/mist-connections_windows_386/mist-connections.exe

Binary file not shown.

BIN
dist/mist-connections_windows_amd64/mist-connections.exe

Binary file not shown.

BIN
dist/mist-connections_windows_arm64/mist-connections.exe

Binary file not shown.

BIN
dist/mist-connections_windows_arm_5/mist-connections.exe

Binary file not shown.

BIN
dist/mist-connections_windows_arm_6/mist-connections.exe

Binary file not shown.

BIN
dist/mist-connections_windows_arm_7/mist-connections.exe

Binary file not shown.

5
go.mod

@ -0,0 +1,5 @@
module varia.zone/mist-connections
go 1.18
require github.com/elazarl/go-bindata-assetfs v1.0.1

2
go.sum

@ -0,0 +1,2 @@
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=

16
makefile

@ -0,0 +1,16 @@
default: run
MAIN := mist-connections.go
ASSETS := assets/assets_gen.go
generate:
@rm -rf $(ASSETS) && go generate $(MAIN)
run: generate
@go run $(MAIN)
bin: generate
@go build .
release:
@goreleaser release --snapshot --rm-dist

BIN
mist-connections

Binary file not shown.

308
mist-connections.go

@ -0,0 +1,308 @@
package main
//go:generate go-bindata -o assets/assets_gen.go -pkg assets public/...
import (
"container/list"
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"os/user"
"path/filepath"
"strings"
"sync"
"time"
"varia.zone/mist-connections/assets"
)
const help = `mist connections
Options:
-n node identifier (default: your system username)
-h output help
`
const webPortFlag = 1312
const filePortFlag = 5555
var nodeIDFlag string
var helpFlag bool
func main() {
systemUser, err := user.Current()
if err != nil {
log.Fatal(err)
}
cwdAbsPath, err := filepath.Abs(".")
if err != nil {
log.Fatal(err)
}
handleCliFlags(systemUser.Name, cwdAbsPath)
if helpFlag {
fmt.Printf(help)
os.Exit(0)
}
conf := &config{
NodeID: nodeIDFlag,
WebPort: webPortFlag,
FilePort: filePortFlag,
}
serve(conf)
}
func handleCliFlags(username, sharePath string) {
flag.StringVar(&nodeIDFlag, "n", username, "node identifier")
flag.BoolVar(&helpFlag, "h", false, "output help")
flag.Parse()
}
type config struct {
NodeID string `json:"nodeID"`
WebPort int `json:"webPort"`
FilePort int `json:"filePort"`
SharePath string `json:"sharePath"`
}
type announcer struct {
conf *config
}
type nodeInfo struct {
NodeID string `json:"nodeID"`
Addr string `json:"addr"`
WebPort int `json:"webPort"`
LastMulticast int64 `json:"lastMulticast"`
}
var (
nodeMutex sync.Mutex
)
func newAnnouncePacket(n *nodeInfo) (string, error) {
jsonMessage, err := json.Marshal(n)
if err != nil {
return "", err
}
message := fmt.Sprintf("%s%s%s", header, nodeAnnounceCommand, jsonMessage)
return message, nil
}
func announceNode(nodeInfo *nodeInfo) {
address, err := net.ResolveUDPAddr("udp", multicastAddress)
if err != nil {
return
}
conn, err := net.DialUDP("udp", nil, address)
if err != nil {
return
}
for {
message, err := newAnnouncePacket(nodeInfo)
if err != nil {
log.Fatal(err)
}
conn.Write([]byte(message))
time.Sleep(announceIntervalSec * time.Second)
}
}
const (
multicastAddress = "239.6.6.6:1337"
multicastBufferSize = 4096
nodeAnnounceCommand = "\x01"
header = "\x60\x0D\xF0\x0D"
minPackageSize = 6
expireTimeoutSec = 15
announceIntervalSec = 10
)
func announcedNodeHandler(ninfo *nodeInfo, nodeList *list.List) {
nodeMutex.Lock()
updateNodeList(ninfo, nodeList)
nodeMutex.Unlock()
}
func updateNodeList(ninfo *nodeInfo, nodeList *list.List) {
nodeExists := false
for el := nodeList.Front(); el != nil; el = el.Next() {
tmp := el.Value.(*nodeInfo)
if tmp.NodeID == ninfo.NodeID {
tmp.LastMulticast = time.Now().Unix()
nodeExists = true
break
}
}
for el := nodeList.Front(); el != nil; el = el.Next() {
tmp := el.Value.(*nodeInfo)
if isNodeExpired(tmp, expireTimeoutSec) {
nodeList.Remove(el)
}
}
if !nodeExists {
ninfo.LastMulticast = time.Now().Unix()
nodeList.PushBack(ninfo)
}
}
func isNodeExpired(nodeInfo *nodeInfo, timeout int) bool {
diff := time.Now().Unix() - nodeInfo.LastMulticast
return diff > int64(timeout)
}
func parseAnnouncePacket(size int, addr *net.UDPAddr, packet []byte) (*nodeInfo, error) {
if size <= minPackageSize {
return nil, fmt.Errorf("Invalid packet size")
}
if strings.Compare(string(packet[0:len(header)]), header) != 0 {
return nil, fmt.Errorf("Invalid packet header")
}
if string(packet[len(header):len(header)+1]) != nodeAnnounceCommand[0:] {
return nil, fmt.Errorf("Command different than nodeAnnounceCommand")
}
payload := string(packet[len(header)+1:])
payload = strings.Trim(payload, "\x00")
nodeInfo := &nodeInfo{}
err := json.Unmarshal([]byte(payload), nodeInfo)
nodeInfo.Addr = addr.IP.String()
nodeInfo.NodeID = fmt.Sprintf("%s", nodeInfo.NodeID)
if err != nil {
return nil, err
}
return nodeInfo, nil
}
func listenForNodes(nodeList *list.List) {
address, err := net.ResolveUDPAddr("udp", multicastAddress)
if err != nil {
return
}
conn, err := net.ListenMulticastUDP("udp", nil, address)
if err != nil {
return
}
conn.SetReadBuffer(multicastBufferSize)
for {
packet := make([]byte, multicastBufferSize)
size, udpAddr, err := conn.ReadFromUDP(packet)
if err != nil {
log.Fatal(err)
}
nodeInfo, err := parseAnnouncePacket(size, udpAddr, packet)
if err != nil {
log.Fatal(err)
}
go announcedNodeHandler(nodeInfo, nodeList)
}
}
func (a *announcer) Start(nodeList *list.List) {
nodeInfo := &nodeInfo{
NodeID: a.conf.NodeID,
Addr: "",
WebPort: a.conf.WebPort,
LastMulticast: 0,
}
go announceNode(nodeInfo)
go listenForNodes(nodeList)
}
func startAnnouncer(conf *config, nodeList *list.List) {
announcer := &announcer{conf: conf}
announcer.Start(nodeList)
}
func serve(conf *config) {
nodeList := list.New()
go startAnnouncer(conf, nodeList)
go fileServe(conf)
go dashboardServe(conf, nodeList)
fmt.Printf("getting misty @ http://localhost:%v\n", conf.FilePort)
select {}
}
func fileServe(conf *config) {
fileMux := http.NewServeMux()
fileMux.Handle("/", http.FileServer(http.Dir(conf.SharePath)))
http.ListenAndServe(fmt.Sprintf("0.0.0.0:%v", conf.WebPort), fileMux)
}
func configHandler(conf *config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
data, err := json.Marshal(conf)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
w.Write(data)
}
}
func nodesHandler(nodeList *list.List) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
nodes := make([]*nodeInfo, 0)
for el := nodeList.Front(); el != nil; el = el.Next() {
tmp := el.Value.(*nodeInfo)
nodes = append(nodes, tmp)
}
data, err := json.Marshal(nodes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
w.Write(data)
}
}
func dashboardServe(conf *config, nodeList *list.List) {
dashboardMux := http.NewServeMux()
dashboardMux.Handle("/", http.FileServer(assets.AssetFS()))
dashboardMux.HandleFunc("/api/config", configHandler(conf))
dashboardMux.HandleFunc("/api/nodes", nodesHandler(nodeList))
address := "0.0.0.0"
err := http.ListenAndServe(fmt.Sprintf("%s:%v", address, conf.FilePort), dashboardMux)
if err != nil {
log.Fatal(err)
}
}

59
public/index.html

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Mist Connections</title>
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/axios@0.27.2"></script>
<style>
ul li {
list-style: none;
}
.fade-enter-active,
.fade-leave-active {
transition: all 3.0s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
</head>
<body>
<div id="app">
<ul>
<transition-group name="fade" tag="li">
<li v-for="node in nodes" v-if="nodes.length">
<a :href="'http://' + node.addr + ':1312'">{{ node.nodeID }}</a>
</li>
</transition-group>
</ul>
</div>
</body>
<script>
var app = Vue.createApp({
data() {
return {
nodes: []
}
},
methods: {
pollNodes() {
axios
.get('/api/nodes')
.then(response => (this.nodes = response.data))
}
},
mounted() {
this.pollNodes()
setInterval(() => { this.pollNodes(); }, 1000);
},
})
app.mount("#app")
</script>
</html>
Loading…
Cancel
Save