├── .github ├── ISSUE_TEMPLATE │ └── bug_report_zhCN.yaml └── workflows │ └── docker.yml ├── Api_LuaCaller.lua ├── Dockerfile ├── Plugins └── lib │ ├── Utils.lua │ └── md5.lua ├── README.md └── entrypoint.sh /.github/ISSUE_TEMPLATE/bug_report_zhCN.yaml: -------------------------------------------------------------------------------- 1 | name: 问题反馈 2 | description: 报告一个错误,以帮助我们改善 OPQBot 3 | 4 | body: 5 | - type: checkboxes 6 | id: area 7 | attributes: 8 | label: 事先确认项 9 | options: 10 | - label: "我确定该反馈是新的,没有和 issue 列表中已有的问题重复" 11 | - label: "我确定查阅过了 官方文档、OPQBot 文档 等所有的信息来源" 12 | - label: "我确定我使用的 QPQBot 是最新版本" 13 | 14 | - type: input 15 | id: OPQBot-version 16 | attributes: 17 | label: OPQBot 版本 18 | description: 您下载了哪个版本的 OPQBot ? 19 | validations: 20 | required: true 21 | 22 | - type: input 23 | id: system-architecture 24 | attributes: 25 | label: 系统架构 26 | description: 您使用的架构,例如 `linux/amd64`, `windows/amd64` 27 | validations: 28 | required: true 29 | 30 | - type: textarea 31 | id: bug-description 32 | attributes: 33 | label: 错误描述 34 | description: 告诉我们您遇到了什么问题 35 | placeholder: 包括有关您尝试的内容,预期发生的事情以及实际发生的事情的信息。越多的细节越好! 36 | validations: 37 | required: true 38 | 39 | - type: textarea 40 | id: log 41 | attributes: 42 | label: Logs 43 | description: 在此处提供相关的错误日志(或者您可以使用屏幕截图来描述) 44 | placeholder: 注意隐藏您的个人信息 45 | 46 | - type: textarea 47 | id: steps-to-reproduce 48 | attributes: 49 | label: 重现步骤 50 | description: 如何复现它?对于我们来说,找到错误很重要 51 | value: | 52 | 1. 53 | 2. 54 | 3. 55 | ... 56 | 57 | - type: textarea 58 | id: Others 59 | attributes: 60 | label: 其他 61 | description: 你的现有解决方案或希望如何解决 62 | placeholder: 填写补充内容 63 | 64 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: docker 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | workflow_dispatch: 7 | inputs: 8 | version: 9 | description: 'Version (No "v")' 10 | required: true 11 | type: string 12 | 13 | jobs: 14 | build-image: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | - name: Set up Docker Buildx 22 | uses: docker/setup-buildx-action@v2 23 | - name: Log into registry 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_HUB_TOKEN }} 28 | - name: Get Version 29 | id: get_version 30 | uses: battila7/get-version-action@v2.2.1 31 | - name: Build and push ( manual ) 32 | if: ${{ inputs.version }} 33 | id: docker_build_manual 34 | uses: docker/build-push-action@v4 35 | with: 36 | context: . 37 | build-args: | 38 | version=${{ inputs.version }} 39 | push: true 40 | platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386 41 | tags: opqofficial/opq:latest,${{ format('opqofficial/opq:v{0}', inputs.version) }} 42 | - name: Build and push 43 | if: success() && startsWith(github.ref, 'refs/tags/') 44 | id: docker_build_auto 45 | uses: docker/build-push-action@v4 46 | with: 47 | build-args: | 48 | version=${{ steps.get_version.outputs.version-without-v }} 49 | context: . 50 | push: true 51 | platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386 52 | tags: opqofficial/opq:latest,${{ format('opqofficial/opq:v{0}', steps.get_version.outputs.version-without-v) }} 53 | -------------------------------------------------------------------------------- /Api_LuaCaller.lua: -------------------------------------------------------------------------------- 1 | --[[v6.9.6]] 2 | local log = require("log") 3 | local Api = require("coreApi") 4 | local json = require("json") 5 | local http = require("http") 6 | -- CurrentQQ 当前操作的QQ号 /funcName 欲调用LuaApi函数名 /data 组装Json数据 7 | function Api_LuaCaller(CurrentQQ, funcName, data) 8 | str = string.format("Api_LuaCaller FuncName %s\n", funcName) 9 | log.info("%s", str) 10 | local luaResp = nil 11 | local switch = { 12 | ["MagicCgiCmd"] = function() 13 | return Api.Api_MagicCgiCmd(CurrentQQ, data) 14 | end, 15 | --添加定时任务 16 | ["AddCrons"] = function() 17 | return Api.Api_AddCrons(data) 18 | end, 19 | --添加删除定时任务 20 | ["DelCrons"] = function() 21 | return Api.Api_DelCrons(data.TaskID) 22 | end, 23 | --获取任务列表 24 | ["GetCrons"] = function() 25 | return Api.Api_GetCrons() 26 | end 27 | } 28 | local fSwitch = switch[funcName] --switch func 29 | if fSwitch then --key exists 30 | luaResp = fSwitch() --do func 31 | else --key not found 32 | luaResp = Api.Api_CallFunc(CurrentQQ, funcName, data) 33 | end 34 | return luaResp 35 | end 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest AS build 2 | WORKDIR /apps 3 | ARG version 4 | ARG TARGETPLATFORM 5 | RUN apk add wget \ 6 | && echo "https://github.com/opq-osc/OPQ/releases/download/v${version}/OPQBot_${version}_linux_$(echo -e $TARGETPLATFORM | sed -e 's/linux\///g' -e 's/\/7//g').tar.gz" \ 7 | && wget --no-check-certificate -c -O /apps/tmp.tar.gz "https://github.com/opq-osc/OPQ/releases/download/v${version}/OPQBot_${version}_linux_$(echo $TARGETPLATFORM | sed -e 's/linux\///g' -e 's/\/v7//g').tar.gz"\ 8 | && tar -xvf tmp.tar.gz\ 9 | && mv OPQBot* opqbot 10 | 11 | FROM alpine:latest 12 | LABEL MAINTAINER enjoy 13 | 14 | 15 | WORKDIR /apps 16 | COPY --from=build /apps/opqbot/ /apps/ 17 | COPY ./entrypoint.sh /apps/entrypoint.sh 18 | # 设置时区 19 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 20 | 21 | # 设置编码 22 | ENV LANG C.UTF-8 23 | 24 | EXPOSE 8086 25 | 26 | 27 | RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 && chmod +x /apps/entrypoint.sh 28 | 29 | # 开RUN 30 | ENTRYPOINT ["/apps/entrypoint.sh"] -------------------------------------------------------------------------------- /Plugins/lib/Utils.lua: -------------------------------------------------------------------------------- 1 | -- 文件名为 module.lua 2 | -- 定义一个名为 module 的模块 3 | Utils = {} 4 | 5 | -- -- 定义一个常量 6 | -- Utils.constant = "这是一个常量" 7 | 8 | -- -- 定义一个函数 9 | function Utils.func1(test) 10 | io.write("这是一个公有函数!\n" .. test) 11 | end 12 | 13 | function Utils.Sleep(n) 14 | local t0 = os.clock() 15 | while os.clock() - t0 <= n do 16 | end 17 | end 18 | --时间戳->字符串 格式化时间 到秒 19 | function Utils.FormatUnixTime2Date(t) 20 | return string.format( 21 | "%s年%s月%s日%s时%s分%s秒", 22 | os.date("%Y", t), 23 | os.date("%m", t), 24 | os.date("%d", t), 25 | os.date("%H", t), 26 | os.date("%M", t), 27 | os.date("%S", t) 28 | ) 29 | end 30 | --时间戳->字符串 格式化时间 到日期 31 | function Utils.FormatUnixTime2Day(t) 32 | return string.format("%s年%s月%s日", os.date("%Y", t), os.date("%m", t), os.date("%d", t)) 33 | end 34 | --字符串分割 35 | function Utils.split(input, delimiter) 36 | input = tostring(input) 37 | delimiter = tostring(delimiter) 38 | if (delimiter == "") then 39 | return false 40 | end 41 | local pos, arr = 0, {} 42 | -- for each divider found 43 | for st, sp in function() 44 | return string.find(input, delimiter, pos, true) 45 | end do 46 | table.insert(arr, string.sub(input, pos, st - 1)) 47 | pos = sp + 1 48 | end 49 | table.insert(arr, string.sub(input, pos)) 50 | return arr 51 | end 52 | --读取文件 53 | function Utils.ReadFile(filePath) 54 | local f, err = io.open(filePath, "rb") 55 | if err ~= nil then 56 | return nil 57 | end 58 | local content = f:read("*all") 59 | f:close() 60 | return content 61 | end 62 | --Url解码 63 | function Utils.UrlDecode(s) 64 | s = 65 | string.gsub( 66 | s, 67 | "%%(%x%x)", 68 | function(h) 69 | return string.char(tonumber(h, 16)) 70 | end 71 | ) 72 | return s 73 | end 74 | --随机整数 75 | function Utils.GenRandInt(x, y) 76 | math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 6))) 77 | num = math.random(x, y) 78 | return num 79 | end 80 | function Random(n, m) 81 | math.randomseed(os.clock() * math.random(1000000, 90000000) + math.random(1000000, 90000000)) 82 | return math.random(n, m) 83 | end 84 | --随机字符串 85 | function Utils.RandomLetter(len) 86 | local rt = "" 87 | for i = 1, len, 1 do 88 | rt = rt .. string.char(Random(97, 122)) 89 | end 90 | return rt 91 | end 92 | --获取星期几 93 | function Utils.GetWday() 94 | local wday = os.date("%w", os.time()) 95 | local weekTab = { 96 | ["0"] = "日", 97 | ["1"] = "一", 98 | ["2"] = "二", 99 | ["3"] = "三", 100 | ["4"] = "四", 101 | ["5"] = "五", 102 | ["6"] = "六" 103 | } 104 | return weekTab[wday] 105 | end 106 | --写文件 107 | function Utils.WriteFile(path, content) 108 | local file = io.open(path, "wb+") 109 | if file then 110 | if file:write(content) == nil then 111 | return false 112 | end 113 | io.close(file) 114 | return true 115 | else 116 | return false 117 | end 118 | end 119 | 120 | 121 | 122 | return Utils 123 | -------------------------------------------------------------------------------- /Plugins/lib/md5.lua: -------------------------------------------------------------------------------- 1 | local md5 = { 2 | _VERSION = "md5.lua 1.1.0", 3 | _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)", 4 | _URL = "https://github.com/kikito/md5.lua", 5 | _LICENSE = [[ 6 | MIT LICENSE 7 | 8 | Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a 11 | copy of this software and associated documentation files (the 12 | "Software"), to deal in the Software without restriction, including 13 | without limitation the rights to use, copy, modify, merge, publish, 14 | distribute, sublicense, and/or sell copies of the Software, and to 15 | permit persons to whom the Software is furnished to do so, subject to 16 | the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included 19 | in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | ]] 29 | } 30 | 31 | -- bit lib implementions 32 | 33 | local char, byte, format, rep, sub = string.char, string.byte, string.format, string.rep, string.sub 34 | local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift 35 | 36 | local ok, bit = pcall(require, "bit") 37 | local ok_ffi, ffi = pcall(require, "ffi") 38 | if ok then 39 | bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = 40 | bit.bor, 41 | bit.band, 42 | bit.bnot, 43 | bit.bxor, 44 | bit.rshift, 45 | bit.lshift 46 | else 47 | ok, bit = pcall(require, "bit32") 48 | 49 | if ok then 50 | bit_not = bit.bnot 51 | 52 | local tobit = function(n) 53 | return n <= 0x7fffffff and n or -(bit_not(n) + 1) 54 | end 55 | 56 | local normalize = function(f) 57 | return function(a, b) 58 | return tobit(f(tobit(a), tobit(b))) 59 | end 60 | end 61 | 62 | bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor) 63 | bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift) 64 | else 65 | local function tbl2number(tbl) 66 | local result = 0 67 | local power = 1 68 | for i = 1, #tbl do 69 | result = result + tbl[i] * power 70 | power = power * 2 71 | end 72 | return result 73 | end 74 | 75 | local function expand(t1, t2) 76 | local big, small = t1, t2 77 | if (#big < #small) then 78 | big, small = small, big 79 | end 80 | -- expand small 81 | for i = #small + 1, #big do 82 | small[i] = 0 83 | end 84 | end 85 | 86 | local to_bits -- needs to be declared before bit_not 87 | 88 | bit_not = function(n) 89 | local tbl = to_bits(n) 90 | local size = math.max(#tbl, 32) 91 | for i = 1, size do 92 | if (tbl[i] == 1) then 93 | tbl[i] = 0 94 | else 95 | tbl[i] = 1 96 | end 97 | end 98 | return tbl2number(tbl) 99 | end 100 | 101 | -- defined as local above 102 | to_bits = function(n) 103 | if (n < 0) then 104 | -- negative 105 | return to_bits(bit_not(math.abs(n)) + 1) 106 | end 107 | -- to bits table 108 | local tbl = {} 109 | local cnt = 1 110 | local last 111 | while n > 0 do 112 | last = n % 2 113 | tbl[cnt] = last 114 | n = (n - last) / 2 115 | cnt = cnt + 1 116 | end 117 | 118 | return tbl 119 | end 120 | 121 | bit_or = function(m, n) 122 | local tbl_m = to_bits(m) 123 | local tbl_n = to_bits(n) 124 | expand(tbl_m, tbl_n) 125 | 126 | local tbl = {} 127 | for i = 1, #tbl_m do 128 | if (tbl_m[i] == 0 and tbl_n[i] == 0) then 129 | tbl[i] = 0 130 | else 131 | tbl[i] = 1 132 | end 133 | end 134 | 135 | return tbl2number(tbl) 136 | end 137 | 138 | bit_and = function(m, n) 139 | local tbl_m = to_bits(m) 140 | local tbl_n = to_bits(n) 141 | expand(tbl_m, tbl_n) 142 | 143 | local tbl = {} 144 | for i = 1, #tbl_m do 145 | if (tbl_m[i] == 0 or tbl_n[i] == 0) then 146 | tbl[i] = 0 147 | else 148 | tbl[i] = 1 149 | end 150 | end 151 | 152 | return tbl2number(tbl) 153 | end 154 | 155 | bit_xor = function(m, n) 156 | local tbl_m = to_bits(m) 157 | local tbl_n = to_bits(n) 158 | expand(tbl_m, tbl_n) 159 | 160 | local tbl = {} 161 | for i = 1, #tbl_m do 162 | if (tbl_m[i] ~= tbl_n[i]) then 163 | tbl[i] = 1 164 | else 165 | tbl[i] = 0 166 | end 167 | end 168 | 169 | return tbl2number(tbl) 170 | end 171 | 172 | bit_rshift = function(n, bits) 173 | local high_bit = 0 174 | if (n < 0) then 175 | -- negative 176 | n = bit_not(math.abs(n)) + 1 177 | high_bit = 0x80000000 178 | end 179 | 180 | local floor = math.floor 181 | 182 | for i = 1, bits do 183 | n = n / 2 184 | n = bit_or(floor(n), high_bit) 185 | end 186 | return floor(n) 187 | end 188 | 189 | bit_lshift = function(n, bits) 190 | if (n < 0) then 191 | -- negative 192 | n = bit_not(math.abs(n)) + 1 193 | end 194 | 195 | for i = 1, bits do 196 | n = n * 2 197 | end 198 | return bit_and(n, 0xFFFFFFFF) 199 | end 200 | end 201 | end 202 | 203 | -- convert little-endian 32-bit int to a 4-char string 204 | local lei2str 205 | -- function is defined this way to allow full jit compilation (removing UCLO instruction in LuaJIT) 206 | if ok_ffi then 207 | local ct_IntType = ffi.typeof("int[1]") 208 | lei2str = function(i) 209 | return ffi.string(ct_IntType(i), 4) 210 | end 211 | else 212 | lei2str = function(i) 213 | local f = function(s) 214 | return char(bit_and(bit_rshift(i, s), 255)) 215 | end 216 | return f(0) .. f(8) .. f(16) .. f(24) 217 | end 218 | end 219 | 220 | -- convert raw string to big-endian int 221 | local function str2bei(s) 222 | local v = 0 223 | for i = 1, #s do 224 | v = v * 256 + byte(s, i) 225 | end 226 | return v 227 | end 228 | 229 | -- convert raw string to little-endian int 230 | local str2lei 231 | 232 | if ok_ffi then 233 | local ct_constcharptr = ffi.typeof("const char*") 234 | local ct_constintptr = ffi.typeof("const int*") 235 | str2lei = function(s) 236 | local int = ct_constcharptr(s) 237 | return ffi.cast(ct_constintptr, int)[0] 238 | end 239 | else 240 | str2lei = function(s) 241 | local v = 0 242 | for i = #s, 1, -1 do 243 | v = v * 256 + byte(s, i) 244 | end 245 | return v 246 | end 247 | end 248 | 249 | -- cut up a string in little-endian ints of given size 250 | local function cut_le_str(s) 251 | return { 252 | str2lei(sub(s, 1, 4)), 253 | str2lei(sub(s, 5, 8)), 254 | str2lei(sub(s, 9, 12)), 255 | str2lei(sub(s, 13, 16)), 256 | str2lei(sub(s, 17, 20)), 257 | str2lei(sub(s, 21, 24)), 258 | str2lei(sub(s, 25, 28)), 259 | str2lei(sub(s, 29, 32)), 260 | str2lei(sub(s, 33, 36)), 261 | str2lei(sub(s, 37, 40)), 262 | str2lei(sub(s, 41, 44)), 263 | str2lei(sub(s, 45, 48)), 264 | str2lei(sub(s, 49, 52)), 265 | str2lei(sub(s, 53, 56)), 266 | str2lei(sub(s, 57, 60)), 267 | str2lei(sub(s, 61, 64)) 268 | } 269 | end 270 | 271 | -- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) 272 | -- 10/02/2001 jcw@equi4.com 273 | 274 | local CONSTS = { 275 | 0xd76aa478, 276 | 0xe8c7b756, 277 | 0x242070db, 278 | 0xc1bdceee, 279 | 0xf57c0faf, 280 | 0x4787c62a, 281 | 0xa8304613, 282 | 0xfd469501, 283 | 0x698098d8, 284 | 0x8b44f7af, 285 | 0xffff5bb1, 286 | 0x895cd7be, 287 | 0x6b901122, 288 | 0xfd987193, 289 | 0xa679438e, 290 | 0x49b40821, 291 | 0xf61e2562, 292 | 0xc040b340, 293 | 0x265e5a51, 294 | 0xe9b6c7aa, 295 | 0xd62f105d, 296 | 0x02441453, 297 | 0xd8a1e681, 298 | 0xe7d3fbc8, 299 | 0x21e1cde6, 300 | 0xc33707d6, 301 | 0xf4d50d87, 302 | 0x455a14ed, 303 | 0xa9e3e905, 304 | 0xfcefa3f8, 305 | 0x676f02d9, 306 | 0x8d2a4c8a, 307 | 0xfffa3942, 308 | 0x8771f681, 309 | 0x6d9d6122, 310 | 0xfde5380c, 311 | 0xa4beea44, 312 | 0x4bdecfa9, 313 | 0xf6bb4b60, 314 | 0xbebfbc70, 315 | 0x289b7ec6, 316 | 0xeaa127fa, 317 | 0xd4ef3085, 318 | 0x04881d05, 319 | 0xd9d4d039, 320 | 0xe6db99e5, 321 | 0x1fa27cf8, 322 | 0xc4ac5665, 323 | 0xf4292244, 324 | 0x432aff97, 325 | 0xab9423a7, 326 | 0xfc93a039, 327 | 0x655b59c3, 328 | 0x8f0ccc92, 329 | 0xffeff47d, 330 | 0x85845dd1, 331 | 0x6fa87e4f, 332 | 0xfe2ce6e0, 333 | 0xa3014314, 334 | 0x4e0811a1, 335 | 0xf7537e82, 336 | 0xbd3af235, 337 | 0x2ad7d2bb, 338 | 0xeb86d391, 339 | 0x67452301, 340 | 0xefcdab89, 341 | 0x98badcfe, 342 | 0x10325476 343 | } 344 | 345 | local f = function(x, y, z) 346 | return bit_or(bit_and(x, y), bit_and(-x - 1, z)) 347 | end 348 | local g = function(x, y, z) 349 | return bit_or(bit_and(x, z), bit_and(y, -z - 1)) 350 | end 351 | local h = function(x, y, z) 352 | return bit_xor(x, bit_xor(y, z)) 353 | end 354 | local i = function(x, y, z) 355 | return bit_xor(y, bit_or(x, -z - 1)) 356 | end 357 | local z = function(ff, a, b, c, d, x, s, ac) 358 | a = bit_and(a + ff(b, c, d) + x + ac, 0xFFFFFFFF) 359 | -- be *very* careful that left shift does not cause rounding! 360 | return bit_or(bit_lshift(bit_and(a, bit_rshift(0xFFFFFFFF, s)), s), bit_rshift(a, 32 - s)) + b 361 | end 362 | 363 | local function transform(A, B, C, D, X) 364 | local a, b, c, d = A, B, C, D 365 | local t = CONSTS 366 | 367 | a = z(f, a, b, c, d, X[0], 7, t[1]) 368 | d = z(f, d, a, b, c, X[1], 12, t[2]) 369 | c = z(f, c, d, a, b, X[2], 17, t[3]) 370 | b = z(f, b, c, d, a, X[3], 22, t[4]) 371 | a = z(f, a, b, c, d, X[4], 7, t[5]) 372 | d = z(f, d, a, b, c, X[5], 12, t[6]) 373 | c = z(f, c, d, a, b, X[6], 17, t[7]) 374 | b = z(f, b, c, d, a, X[7], 22, t[8]) 375 | a = z(f, a, b, c, d, X[8], 7, t[9]) 376 | d = z(f, d, a, b, c, X[9], 12, t[10]) 377 | c = z(f, c, d, a, b, X[10], 17, t[11]) 378 | b = z(f, b, c, d, a, X[11], 22, t[12]) 379 | a = z(f, a, b, c, d, X[12], 7, t[13]) 380 | d = z(f, d, a, b, c, X[13], 12, t[14]) 381 | c = z(f, c, d, a, b, X[14], 17, t[15]) 382 | b = z(f, b, c, d, a, X[15], 22, t[16]) 383 | 384 | a = z(g, a, b, c, d, X[1], 5, t[17]) 385 | d = z(g, d, a, b, c, X[6], 9, t[18]) 386 | c = z(g, c, d, a, b, X[11], 14, t[19]) 387 | b = z(g, b, c, d, a, X[0], 20, t[20]) 388 | a = z(g, a, b, c, d, X[5], 5, t[21]) 389 | d = z(g, d, a, b, c, X[10], 9, t[22]) 390 | c = z(g, c, d, a, b, X[15], 14, t[23]) 391 | b = z(g, b, c, d, a, X[4], 20, t[24]) 392 | a = z(g, a, b, c, d, X[9], 5, t[25]) 393 | d = z(g, d, a, b, c, X[14], 9, t[26]) 394 | c = z(g, c, d, a, b, X[3], 14, t[27]) 395 | b = z(g, b, c, d, a, X[8], 20, t[28]) 396 | a = z(g, a, b, c, d, X[13], 5, t[29]) 397 | d = z(g, d, a, b, c, X[2], 9, t[30]) 398 | c = z(g, c, d, a, b, X[7], 14, t[31]) 399 | b = z(g, b, c, d, a, X[12], 20, t[32]) 400 | 401 | a = z(h, a, b, c, d, X[5], 4, t[33]) 402 | d = z(h, d, a, b, c, X[8], 11, t[34]) 403 | c = z(h, c, d, a, b, X[11], 16, t[35]) 404 | b = z(h, b, c, d, a, X[14], 23, t[36]) 405 | a = z(h, a, b, c, d, X[1], 4, t[37]) 406 | d = z(h, d, a, b, c, X[4], 11, t[38]) 407 | c = z(h, c, d, a, b, X[7], 16, t[39]) 408 | b = z(h, b, c, d, a, X[10], 23, t[40]) 409 | a = z(h, a, b, c, d, X[13], 4, t[41]) 410 | d = z(h, d, a, b, c, X[0], 11, t[42]) 411 | c = z(h, c, d, a, b, X[3], 16, t[43]) 412 | b = z(h, b, c, d, a, X[6], 23, t[44]) 413 | a = z(h, a, b, c, d, X[9], 4, t[45]) 414 | d = z(h, d, a, b, c, X[12], 11, t[46]) 415 | c = z(h, c, d, a, b, X[15], 16, t[47]) 416 | b = z(h, b, c, d, a, X[2], 23, t[48]) 417 | 418 | a = z(i, a, b, c, d, X[0], 6, t[49]) 419 | d = z(i, d, a, b, c, X[7], 10, t[50]) 420 | c = z(i, c, d, a, b, X[14], 15, t[51]) 421 | b = z(i, b, c, d, a, X[5], 21, t[52]) 422 | a = z(i, a, b, c, d, X[12], 6, t[53]) 423 | d = z(i, d, a, b, c, X[3], 10, t[54]) 424 | c = z(i, c, d, a, b, X[10], 15, t[55]) 425 | b = z(i, b, c, d, a, X[1], 21, t[56]) 426 | a = z(i, a, b, c, d, X[8], 6, t[57]) 427 | d = z(i, d, a, b, c, X[15], 10, t[58]) 428 | c = z(i, c, d, a, b, X[6], 15, t[59]) 429 | b = z(i, b, c, d, a, X[13], 21, t[60]) 430 | a = z(i, a, b, c, d, X[4], 6, t[61]) 431 | d = z(i, d, a, b, c, X[11], 10, t[62]) 432 | c = z(i, c, d, a, b, X[2], 15, t[63]) 433 | b = z(i, b, c, d, a, X[9], 21, t[64]) 434 | 435 | return bit_and(A + a, 0xFFFFFFFF), bit_and(B + b, 0xFFFFFFFF), bit_and(C + c, 0xFFFFFFFF), bit_and(D + d, 0xFFFFFFFF) 436 | end 437 | 438 | ---------------------------------------------------------------- 439 | 440 | local function md5_update(self, s) 441 | self.pos = self.pos + #s 442 | s = self.buf .. s 443 | for ii = 1, #s - 63, 64 do 444 | local X = cut_le_str(sub(s, ii, ii + 63)) 445 | assert(#X == 16) 446 | X[0] = table.remove(X, 1) -- zero based! 447 | self.a, self.b, self.c, self.d = transform(self.a, self.b, self.c, self.d, X) 448 | end 449 | self.buf = sub(s, math.floor(#s / 64) * 64 + 1, #s) 450 | return self 451 | end 452 | 453 | local function md5_finish(self) 454 | local msgLen = self.pos 455 | local padLen = 56 - msgLen % 64 456 | 457 | if msgLen % 64 > 56 then 458 | padLen = padLen + 64 459 | end 460 | 461 | if padLen == 0 then 462 | padLen = 64 463 | end 464 | 465 | local s = 466 | char(128) .. 467 | rep(char(0), padLen - 1) .. lei2str(bit_and(8 * msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen / 0x20000000)) 468 | md5_update(self, s) 469 | 470 | assert(self.pos % 64 == 0) 471 | return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d) 472 | end 473 | 474 | ---------------------------------------------------------------- 475 | 476 | function md5.new() 477 | return { 478 | a = CONSTS[65], 479 | b = CONSTS[66], 480 | c = CONSTS[67], 481 | d = CONSTS[68], 482 | pos = 0, 483 | buf = "", 484 | update = md5_update, 485 | finish = md5_finish 486 | } 487 | end 488 | 489 | function md5.tohex(s) 490 | return format( 491 | "%08x%08x%08x%08x", 492 | str2bei(sub(s, 1, 4)), 493 | str2bei(sub(s, 5, 8)), 494 | str2bei(sub(s, 9, 12)), 495 | str2bei(sub(s, 13, 16)) 496 | ) 497 | end 498 | 499 | function md5.sum(s) 500 | return md5.new():update(s):finish() 501 | end 502 | 503 | function md5.sumhexa(s) 504 | return md5.tohex(md5.sum(s)) 505 | end 506 | 507 | return md5 508 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | OPQBot 4 | 5 |

6 | 7 |
8 | 9 | # OPQBot 10 | 11 | _🔮 全 🆕 内核 从 💖 出发 Golang 原生实现机器人框架 免费 🆓 闭源 🔮_ 12 | 13 |
14 | 15 | 16 | ## 介绍 17 | 18 | OPQ RST UVW XYZ,无论是服务器、Mac、树莓派、电视盒子、路由器,AI 机器人框架 OPQ 为跨平台而生,轻松应对 19 | OPQBot 采用独特的插件机制(Lua插件全平台通用),内置协程池,高效、稳定、迸发,提供 WebSocket,Web API,极低内存运行,稳定 0 崩溃,配置简单、一件启动、对小白🥬友好 20 | 21 | ### 接口 22 | 23 | - [x] Lua API 24 | - [x] Web API 25 | - [x] 正向 WebSocket 26 | - [x] 反向 WebSocket 27 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | run_args="" 4 | 5 | if [[ "$token" == "" ]] ; then 6 | echo "注意,你没有配置 Token" 7 | else 8 | run_args="-token $token" 9 | fi 10 | 11 | if [[ "$port" == "" ]] ; then 12 | echo "将默认运行在 8086 ,注意安全组和防火墙情况,若仅内网使用,请关闭端口防止渗透" 13 | else 14 | echo "将运行在 $port 端口" 15 | run_args="$run_args -port $port" 16 | fi 17 | 18 | if [[ "$wsserver" != "" ]] ; then 19 | echo "ws server: $wsserver" 20 | run_args="$run_args -wsserver $wsserver" 21 | fi 22 | 23 | if [[ "$wthread" != "" ]] ; then 24 | echo "ws thread: $wthread" 25 | run_args="$run_args -wthread $wthread" 26 | fi 27 | 28 | echo "开始运行 OPQBot" 29 | 30 | echo "运行参数: $run_args" 31 | exec /apps/OPQBot $run_args 32 | --------------------------------------------------------------------------------