diff options
Diffstat (limited to '')
| -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]) | 
