diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Dockerfile | 4 | ||||
-rw-r--r-- | Dockerfile_scratch_vendored | 14 | ||||
-rw-r--r-- | go.mod | 6 | ||||
-rw-r--r-- | go.sum | 43 | ||||
-rw-r--r-- | main.go | 20 | ||||
-rw-r--r-- | plugins.go | 64 | ||||
-rw-r--r-- | plugins/hello.lua | 5 | ||||
-rw-r--r-- | plugins/repology.lua | 33 | ||||
-rw-r--r-- | rss.go | 2 | ||||
-rw-r--r-- | types.go | 14 | ||||
-rw-r--r-- | utils.go | 7 |
12 files changed, 183 insertions, 31 deletions
@@ -19,3 +19,5 @@ # Go workspace file go.work + +,* @@ -6,7 +6,7 @@ COPY *.go /milla/ RUN go build FROM alpine:3.21 -ENV HOME /home/user +ENV HOME=/home/user RUN set -eux; \ adduser -u 1001 -D -h "$HOME" user; \ mkdir "$HOME/.irssi"; \ @@ -14,4 +14,4 @@ RUN set -eux; \ COPY --from=builder /milla/milla "$HOME/milla" RUN chown user:user "$HOME/milla" USER user -ENTRYPOINT ["home/user/milla"] +ENTRYPOINT ["/home/user/milla"] diff --git a/Dockerfile_scratch_vendored b/Dockerfile_scratch_vendored new file mode 100644 index 0000000..34d6b07 --- /dev/null +++ b/Dockerfile_scratch_vendored @@ -0,0 +1,14 @@ +FROM golang:1.23-alpine3.21 AS builder +WORKDIR /milla +COPY go.sum go.mod /milla/ +COPY vendor /milla/vendor +COPY *.go /milla/ +RUN CGO_ENABLED=0 go build + +FROM alpine:3.21 AS cert +RUN apk add --no-cache ca-certificates + +FROM scratch +COPY --from=cert /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /milla/milla "/milla" +ENTRYPOINT ["/milla"] @@ -16,7 +16,7 @@ require ( github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf github.com/lrstanley/girc v0.0.0-20240125042120-9add3166e52e github.com/mmcdole/gofeed v1.3.0 - github.com/sashabaranov/go-openai v1.19.3 + github.com/sashabaranov/go-openai v1.36.0 github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed github.com/yuin/gopher-lua v1.1.1 gitlab.com/megalithic-llc/gluasocket v0.3.1 @@ -31,8 +31,8 @@ require ( cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/longrunning v0.5.7 // indirect - github.com/PuerkitoBio/goquery v1.8.0 // indirect - github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/PuerkitoBio/goquery v1.9.2 // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.1 // indirect @@ -13,8 +13,8 @@ cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuA cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= -github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= +github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= +github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/ailncode/gluaxmlpath v0.0.0-20161126153117-6ce478ecb4a6 h1:FM0WudTZ+xeiXPJcs+X1Zg8JXe4vlb9P2GZYqCYjZkk= github.com/ailncode/gluaxmlpath v0.0.0-20161126153117-6ce478ecb4a6/go.mod h1:Ti1AvV2KUYtHEBX7eYbdAGEfFyKz9+lHrJPcr79Vkng= github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= @@ -23,8 +23,8 @@ github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= -github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/cenkalti/backoff/v5 v5.0.1 h1:kGZdCHH1+eW+Yd0wftimjMuhg9zidDvNF5aGdnkkb+U= github.com/cenkalti/backoff/v5 v5.0.1/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -121,8 +121,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/sashabaranov/go-openai v1.19.3 h1:xJvkU8Tye6MOKLaoqjh7qXYwKiEYGtlmp06cb8179yo= -github.com/sashabaranov/go-openai v1.19.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sashabaranov/go-openai v1.36.0 h1:fcSrn8uGuorzPWCBp8L0aCR95Zjb/Dd+ZSML0YZy9EI= +github.com/sashabaranov/go-openai v1.36.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -133,8 +133,11 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vitoraguila/forza v0.0.0-20250308133152-28e9d4675774 h1:BCGeQcdyr+aqVU+mS2roqivUzv7d9wy9oeMze43SUe0= +github.com/vitoraguila/forza v0.0.0-20250308133152-28e9d4675774/go.mod h1:h3MHloI9aeI+xO4S4tpQ+XEAJt370k/g7l6FZaj76Mc= github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed h1:I1vcLHWU9m30rA90rMrKPu0eD3NDA4FBlkB8WMaDyUw= github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed/go.mod h1:9w6KSdZh23UWqOywWsRLUcJUrUNjRh4Ql3z9uVgnSP4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= gitlab.com/megalithic-llc/gluasocket v0.3.1 h1:CtsSTZa3G5WnMbhZ3TgvpLwpVlQv6KjO2mqxNOGrhY4= @@ -153,19 +156,26 @@ go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2L go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -174,6 +184,8 @@ golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -181,13 +193,22 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -197,6 +218,10 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.186.0 h1:n2OPp+PPXX0Axh4GuSsL5QL8xQCTb2oDwyzPnQvqUug= google.golang.org/api v0.186.0/go.mod h1:hvRbBmgoje49RV3xqVXrmP6w93n6ehGgIVPYrGtBFFc= @@ -483,7 +483,7 @@ func runCommand( appConfig.deleteLstate(args[1]) case "remind": if len(args) < 2 { //nolint: mnd,gomnd - client.Cmd.Reply(event, errNotEnoughArgs.Error()) + client.Cmd.Message(event.Source.Name, errNotEnoughArgs.Error()) break } @@ -491,14 +491,15 @@ func runCommand( seconds, err := strconv.Atoi(args[1]) if err != nil { client.Cmd.Reply(event, errNotEnoughArgs.Error()) + client.Cmd.Message(event.Source.Name, errNotEnoughArgs.Error()) break } - client.Cmd.Reply(event, "Ok, I'll remind you in "+args[1]+" seconds.") + client.Cmd.Message(event.Source.Name, "Ok, I'll remind you in "+args[1]+" seconds.") time.Sleep(time.Duration(seconds) * time.Second) - client.Cmd.ReplyTo(event, " Ping!") + client.Cmd.Message(event.Source.Name, "Ping!") case "forget": client.Cmd.Reply(event, "I no longer even know whether you're supposed to wear or drink a camel.'") case "whois": @@ -1380,6 +1381,8 @@ func runIRC(appConfig TomlConfig) { go LoadAllPlugins(&appConfig, irc) + go LoadAllEventPlugins(&appConfig, irc) + if appConfig.DatabaseAddress != "" { context, cancel := context.WithTimeout(context.Background(), time.Duration(appConfig.RequestTimeout)*time.Second) defer cancel() @@ -1474,6 +1477,7 @@ func main() { signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM) configPath := flag.String("config", "./config.toml", "path to the config file") + prof := flag.Bool("prof", false, "enable prof server") flag.Parse() @@ -1503,10 +1507,12 @@ func main() { go runIRC(v) } - go func() { - err := http.ListenAndServe(":6060", nil) - log.Println(err) - }() + if *prof { + go func() { + err := http.ListenAndServe(":6060", nil) + log.Println(err) + }() + } <-quitChannel } @@ -7,6 +7,7 @@ import ( "net/url" "os" "reflect" + "strings" "github.com/ailncode/gluaxmlpath" "github.com/cjoudrey/gluahttp" @@ -197,6 +198,17 @@ func sendMessageClosure(luaState *lua.LState, client *girc.Client) func(*lua.LSt return 0 } } + +func replyToMessageClosure(luaStete *lua.LState, client *girc.Client, event girc.Event) func(*lua.LState) int { + return func(luaState *lua.LState) int { + message := luaState.CheckString(1) + + client.Cmd.Message(event.Source.Name, message) + + return 0 + } +} + func registerLuaCommand(luaState *lua.LState, appConfig *TomlConfig) func(*lua.LState) int { return func(luaState *lua.LState) int { path := luaState.CheckString(1) @@ -410,6 +422,37 @@ func millaModuleLoaderClosure(luaState *lua.LState, client *girc.Client, appConf } } +func millaModuleLoaderEventClosure(luaState *lua.LState, client *girc.Client, appConfig *TomlConfig, event girc.Event) func(*lua.LState) int { + return func(luaState *lua.LState) int { + exports := map[string]lua.LGFunction{ + "send_message": lua.LGFunction(sendMessageClosure(luaState, client)), + "reply_to": lua.LGFunction(replyToMessageClosure(luaState, client, event)), + "join_channel": lua.LGFunction(ircJoinChannelClosure(luaState, client)), + "part_channel": lua.LGFunction(ircPartChannelClosure(luaState, client)), + "send_ollama_request": lua.LGFunction(ollamaRequestClosure(luaState, appConfig)), + "send_gemini_request": lua.LGFunction(geminiRequestClosure(luaState, appConfig)), + "send_chatgpt_request": lua.LGFunction(chatGPTRequestClosure(luaState, appConfig)), + "send_or_request": lua.LGFunction(orRequestClosure(luaState, appConfig)), + "query_db": lua.LGFunction(dbQueryClosure(luaState, appConfig)), + "register_cmd": lua.LGFunction(registerLuaCommand(luaState, appConfig)), + "url_encode": lua.LGFunction(urlEncode(luaState)), + } + millaModule := luaState.SetFuncs(luaState.NewTable(), exports) + + registerStructAsLuaMetaTable[TomlConfig](luaState, millaModule, checkStruct, TomlConfig{}, "toml_config") + registerStructAsLuaMetaTable[CustomCommand](luaState, millaModule, checkStruct, CustomCommand{}, "custom_command") + registerStructAsLuaMetaTable[LogModel](luaState, millaModule, checkStruct, LogModel{}, "log_model") + registerStructAsLuaMetaTable[girc.Source](luaState, millaModule, checkStruct, girc.Source{}, "girc_source") + registerStructAsLuaMetaTable[girc.Event](luaState, millaModule, checkStruct, girc.Event{}, "girc_event") + + luaState.SetGlobal("milla", millaModule) + + luaState.Push(millaModule) + + return 1 + } +} + func RunScript(scriptPath string, client *girc.Client, appConfig *TomlConfig) { luaState := lua.NewState() defer luaState.Close() @@ -469,6 +512,15 @@ func LoadAllPlugins(appConfig *TomlConfig, client *girc.Client) { } } +func LoadAllEventPlugins(appConfig *TomlConfig, client *girc.Client) { + for _, triggeredScript := range appConfig.TriggeredScripts { + log.Print("Loading event plugin: ", triggeredScript.Path) + + go RunScript(triggeredScript.Path, client, appConfig) + registerTriggeredScripts(client, *appConfig) + } +} + func RunLuaFunc( cmd, args string, client *girc.Client, @@ -565,7 +617,7 @@ func RunTriggeredLuaFunc( appConfig.insertLState(scriptPath, luaState, cancel) - luaState.PreloadModule("milla", millaModuleLoaderClosure(luaState, client, appConfig)) + luaState.PreloadModule("milla", millaModuleLoaderEventClosure(luaState, client, appConfig, event)) gluasocket.Preload(luaState) gluaxmlpath.Preload(luaState) luaState.PreloadModule("yaml", gluayaml.Loader) @@ -629,10 +681,18 @@ func RunTriggeredLuaFunc( func registerTriggeredScripts(irc *girc.Client, appConfig TomlConfig) { for _, triggeredScript := range appConfig.TriggeredScripts { - for _, triggerType := range triggeredScript.TriggerType { + for _, triggerType := range triggeredScript.TriggerTypes { switch triggerType { case girc.PRIVMSG: irc.Handlers.AddBg(girc.PRIVMSG, func(_ *girc.Client, event girc.Event) { + if !strings.HasPrefix(event.Last(), appConfig.IrcNick+": ") { + return + } + + if appConfig.AdminOnly && !isFromAdmin(appConfig.Admins, event) { + return + } + RunTriggeredLuaFunc(triggeredScript.FuncName, triggeredScript.Path, irc, event, &appConfig) }) default: diff --git a/plugins/hello.lua b/plugins/hello.lua new file mode 100644 index 0000000..b9c5bc2 --- /dev/null +++ b/plugins/hello.lua @@ -0,0 +1,5 @@ +local milla = require("milla") + +function hello() milla.reply_to("hello") end + +milla.register_cmd("/plugins/hello.lua", "hello", "hello") diff --git a/plugins/repology.lua b/plugins/repology.lua new file mode 100644 index 0000000..f3de647 --- /dev/null +++ b/plugins/repology.lua @@ -0,0 +1,33 @@ +local milla = require("milla") +local os = require("os") +local json = require("json") + +-- /repology void_x86_64 +function repology(arg) + os.setenv("http_proxy", "http://172.17.0.1:8120") + + local http = require("http") + + local url = "https://repology.org/api/v1/repository/" .. arg .. "/problems" + + local response = http.request("GET", url) + + io.write(response.body) + + local json_response, err = json.decode(response.body) + io.write(json_response) + if err ~= nil then print(err) end + + for _, item in pairs(json_response) do + for k, v in ipairs(item) do print(k, v) end + end + + local result = "" + for key, value in pairs(json_response) do + result = result .. key .. ": " .. value .. " -- " + end + + return result +end + +milla.register_cmd("/plugins/repology.lua", "repology", "repology") @@ -65,7 +65,7 @@ func GetFeed(feed FeedConfig, for _, item := range parsedFeed.Items { if item.PublishedParsed.Unix() > newestFromDB { - client.Cmd.Message(channel[0], parsedFeed.Title+": "+item.Title+" >>> "+item.Link) + client.Cmd.Message(channel[0], feed.Name[0:Min(20, len(feed.Name))]+": "+parsedFeed.Title+": "+item.Title+" >>> "+item.Link) } } @@ -54,10 +54,10 @@ type LuaCommand struct { } type TriggeredScripts struct { - Path string - FuncName string - Channels [][]string - TriggerType []string + Path string + FuncName string + Channels [][]string + TriggerTypes []string } type RssFile struct { @@ -190,9 +190,9 @@ func (config *TomlConfig) insertTriggeredScript(path, cmd string, triggerType [] config.TriggeredScripts = make(map[string]TriggeredScripts) } config.TriggeredScripts[path] = TriggeredScripts{ - Path: path, - FuncName: cmd, - TriggerType: triggerType, + Path: path, + FuncName: cmd, + TriggerTypes: triggerType, } } @@ -7,6 +7,13 @@ import ( "github.com/lrstanley/girc" ) +func Min(x, y int) int { + if x < y { + return x + } + return y +} + func IrcJoin(irc *girc.Client, channel []string) { if len(channel) > 1 && channel[1] != "" { irc.Cmd.JoinKey(channel[0], channel[1]) |