wtf
This commit is contained in:
parent
13b77c1d6d
commit
2b970ed58f
@ -1,426 +0,0 @@
|
||||
¢‿¢
|
||||
©¿© o
|
||||
ª{•̃̾_•̃̾}ª
|
||||
¬_¬
|
||||
¯\(º_o)/¯
|
||||
¯\(º o)/¯
|
||||
¯\_(⊙︿⊙)_/¯
|
||||
¯\_(ツ)_/¯
|
||||
°ω°
|
||||
°Д°
|
||||
°‿‿°
|
||||
°ﺑ°
|
||||
´ ▽ ` )ノ
|
||||
¿ⓧ_ⓧﮌ
|
||||
Ò,ó
|
||||
ó‿ó
|
||||
ô⌐ô
|
||||
ôヮô
|
||||
ŎםŎ
|
||||
ŏﺡó
|
||||
ʕ•̫͡•ʔ
|
||||
ʕ•ᴥ•ʔ
|
||||
ʘ‿ʘ
|
||||
˚•_•˚
|
||||
˚⌇˚
|
||||
˚▱˚
|
||||
̿ ̿̿'̿'\̵͇̿̿\=(•̪●)=/̵͇̿̿/'̿̿ ̿ ̿ ̿
|
||||
͡° ͜ʖ ͡°
|
||||
Σ ◕ ◡ ◕
|
||||
Σ (゚Д゚;)
|
||||
Σ(゚Д゚;≡;゚д゚)
|
||||
Σ(゚Д゚ )
|
||||
Σ(||゚Д゚)
|
||||
Φ,Φ
|
||||
δﺡό
|
||||
σ_σ
|
||||
д_д
|
||||
ф_ф
|
||||
щ(゚Д゚щ)
|
||||
щ(ಠ益ಠщ)
|
||||
щ(ಥДಥщ)
|
||||
Ծ_Ծ
|
||||
أ‿أ
|
||||
ب_ب
|
||||
ح˚௰˚づ
|
||||
ح˚ᆺ˚ว
|
||||
حᇂﮌᇂ)
|
||||
٩๏̯͡๏۶
|
||||
٩๏̯͡๏)۶
|
||||
٩◔̯◔۶
|
||||
٩(×̯×)۶
|
||||
٩(̾●̮̮̃̾•̃̾)۶
|
||||
٩(͡๏̯͡๏)۶
|
||||
٩(͡๏̯ ͡๏)۶
|
||||
٩(ಥ_ಥ)۶
|
||||
٩(•̮̮̃•̃)۶
|
||||
٩(●̮̮̃•̃)۶
|
||||
٩(●̮̮̃●̃)۶
|
||||
٩(。͡•‿•。)۶
|
||||
٩(-̮̮̃•̃)۶
|
||||
٩(-̮̮̃-̃)۶
|
||||
۞_۞
|
||||
۞_۟۞
|
||||
۹ↁﮌↁ
|
||||
۹⌤_⌤۹
|
||||
॓_॔
|
||||
१✌◡✌५
|
||||
१|˚–˚|५
|
||||
ਉ_ਉ
|
||||
ଘ_ଘ
|
||||
இ_இ
|
||||
ఠ_ఠ
|
||||
రృర
|
||||
ಠ¿ಠi
|
||||
ಠ‿ಠ
|
||||
ಠ⌣ಠ
|
||||
ಠ╭╮ಠ
|
||||
ಠ▃ಠ
|
||||
ಠ◡ಠ
|
||||
ಠ益ಠ
|
||||
ಠ益ಠ
|
||||
ಠ︵ಠ凸
|
||||
ಠ , ಥ
|
||||
ಠ.ಠ
|
||||
ಠoಠ
|
||||
ಠ_ృ
|
||||
ಠ_ಠ
|
||||
ಠ_๏
|
||||
ಠ~ಠ
|
||||
ಡ_ಡ
|
||||
ತಎತ
|
||||
ತ_ತ
|
||||
ಥдಥ
|
||||
ಥ‿ಥ
|
||||
ಥ⌣ಥ
|
||||
ಥ◡ಥ
|
||||
ಥ﹏ಥ
|
||||
ಥ_ಥ
|
||||
ಭ_ಭ
|
||||
ರ_ರ
|
||||
ಸ , ໖
|
||||
ಸ_ಸ
|
||||
ക_ക
|
||||
อ้_อ้
|
||||
อ_อ
|
||||
โ๏௰๏ใ ื
|
||||
๏̯͡๏﴿
|
||||
๏̯͡๏
|
||||
๏̯͡๏﴿
|
||||
๏[-ิิ_•ิ]๏
|
||||
๏_๏
|
||||
໖_໖
|
||||
ლ(´ڡ`ლ)
|
||||
ლ(́◉◞౪◟◉‵ლ)
|
||||
ლ(ಠ益ಠლ)
|
||||
ლ(╹◡╹ლ)
|
||||
ლ(◉◞౪◟◉‵ლ)
|
||||
ლ,ᔑ•ﺪ͟͠•ᔐ.ლ
|
||||
ᄽὁȍ ̪ őὀᄿ
|
||||
ᕕ( ᐛ )ᕗ
|
||||
ᕙ(⇀‸↼‶)ᕗ
|
||||
ᕦ(ò_óˇ)ᕤ
|
||||
ᶘ ᵒᴥᵒᶅ
|
||||
‘︿’
|
||||
•▱•
|
||||
•✞_✞•
|
||||
•ﺑ•
|
||||
•(⌚_⌚)•
|
||||
•_•)
|
||||
‷̗ↂ凸ↂ‴̖
|
||||
‹•.•›
|
||||
‹› ‹(•¿•)› ‹›
|
||||
‹(ᵒᴥᵒ)›
|
||||
‹(•¿•)›
|
||||
ↁ_ↁ
|
||||
⇎_⇎
|
||||
∩(︶▽︶)∩
|
||||
∩( ・ω・)∩
|
||||
≖‿≖
|
||||
≧ヮ≦
|
||||
⊂•⊃_⊂•⊃
|
||||
⊂⌒~⊃。Д。)⊃
|
||||
⊂(◉‿◉)つ
|
||||
⊂(゚Д゚,,⊂⌒`つ
|
||||
⊙ω⊙
|
||||
⊙▂⊙
|
||||
⊙▃⊙
|
||||
⊙△⊙
|
||||
⊙︿⊙
|
||||
⊙﹏⊙
|
||||
⊙0⊙
|
||||
⊛ठ̯⊛
|
||||
⋋ō_ō`
|
||||
━━━ヽ(ヽ(゚ヽ(゚ヽ(゚゚ヽ(゚゚)ノ゚゚)ノ゚)ノ゚)ノ)ノ━━━
|
||||
┌∩┐(◕_◕)┌∩┐
|
||||
┌( ಠ_ಠ)┘
|
||||
┌( ಥ_ಥ)┘
|
||||
╚(•⌂•)╝
|
||||
╭╮╭╮☜{•̃̾_•̃̾}☞╭╮╭╮
|
||||
╭✬⌢✬╮
|
||||
╮(▽)╭
|
||||
╯‵Д′)╯彡┻━┻
|
||||
╰☆╮
|
||||
□_□
|
||||
►_◄
|
||||
◃┆◉◡◉┆▷
|
||||
◉△◉
|
||||
◉︵◉
|
||||
◉_◉
|
||||
○_○
|
||||
●¿●\ ~
|
||||
●_●
|
||||
◔̯◔
|
||||
◔ᴗ◔
|
||||
◔ ⌣ ◔
|
||||
◔_◔
|
||||
◕ω◕
|
||||
◕‿◕
|
||||
◕◡◕
|
||||
◕ ◡ ◕
|
||||
◖♪_♪|◗
|
||||
◖|◔◡◉|◗
|
||||
◘_◘
|
||||
◙‿◙
|
||||
◜㍕◝
|
||||
◪_◪
|
||||
◮_◮
|
||||
☁ ☝ˆ~ˆ☂
|
||||
☆¸☆
|
||||
☉‿⊙
|
||||
☉_☉
|
||||
☐_☐
|
||||
☜ق❂Ⴢ❂ق☞
|
||||
☜(⌒▽⌒)☞
|
||||
☜(゚ヮ゚☜)
|
||||
☜-(ΘLΘ)-☞
|
||||
☝☞✌
|
||||
☮▁▂▃▄☾ ♛ ◡ ♛ ☽▄▃▂▁☮
|
||||
☹_☹
|
||||
☻_☻
|
||||
☼.☼
|
||||
☾˙❀‿❀˙☽
|
||||
♀ح♀ヾ
|
||||
♥‿♥
|
||||
♥╣[-_-]╠♥
|
||||
♥╭╮♥
|
||||
♥◡♥
|
||||
✌♫♪˙❤‿❤˙♫♪✌
|
||||
✌.ʕʘ‿ʘʔ.✌
|
||||
✌.|•͡˘‿•͡˘|.✌
|
||||
✖‿✖
|
||||
✖_✖
|
||||
❐‿❑
|
||||
_
|
||||
_Ꙩ
|
||||
⨂_⨂
|
||||
〆(・・@)
|
||||
《〠_〠》
|
||||
【•】_【•】
|
||||
〠_〠
|
||||
〴⋋_⋌〵
|
||||
の<EFBFBD> <20>の
|
||||
ニガー? ━━━━━━(゚゚)━━━━━━ ニガー?
|
||||
ペ㍕˚\
|
||||
ヽ(´ー` )ノ
|
||||
ヽ(๏๏ )ノ
|
||||
ヽ(`Д´)ノ
|
||||
ヽ(o`皿′o)ノ
|
||||
ヽ(`Д´)ノ
|
||||
ㅎ_ㅎ
|
||||
乂◜◬◝乂
|
||||
凸ಠ益ಠ)凸
|
||||
句_句
|
||||
Ꙩ⌵Ꙩ
|
||||
Ꙩ_Ꙩ
|
||||
ꙩ_ꙩ
|
||||
Ꙫ_Ꙫ
|
||||
ꙫ_ꙫ
|
||||
ꙮ_ꙮ
|
||||
흫_흫
|
||||
句_句
|
||||
﴾͡๏̯͡๏﴿ O'RLY?
|
||||
¯\(ºдಠ)/¯
|
||||
(·×·)
|
||||
(⌒Д⌒)
|
||||
(╹ェ╹)
|
||||
(♯・・)⊃
|
||||
( ´`)☆
|
||||
( ´`)
|
||||
(゜Д゜)
|
||||
(・・)
|
||||
(・A・)
|
||||
(゚゚)
|
||||
( ̄へ ̄)
|
||||
( ´☣///_ゝ///☣`)
|
||||
( つ Д `)
|
||||
_☆( ´_⊃`)☆_
|
||||
。◕‿‿◕。
|
||||
。◕ ‿ ◕。
|
||||
!⑈ˆ~ˆ!⑈
|
||||
!(`・ω・。)
|
||||
(¬‿¬)
|
||||
(¬▂¬)
|
||||
(¬_¬)
|
||||
(°ℇ °)
|
||||
(°°)
|
||||
(´ω`)
|
||||
(´◉◞౪◟◉)
|
||||
(´ヘ`;)
|
||||
(´・ω・`)
|
||||
(´ー`)
|
||||
(ʘ‿ʘ)
|
||||
(ʘ_ʘ)
|
||||
(˚இ˚)
|
||||
(͡๏̯͡๏)
|
||||
(ΘεΘ;)
|
||||
(ι´Д`)ノ
|
||||
(Ծ‸ Ծ)
|
||||
(॓_॔)
|
||||
(० ्०)
|
||||
(ு८ு_ .:)
|
||||
(ಠ‾ಠ)
|
||||
(ಠ‿ʘ)
|
||||
(ಠ‿ಠ)
|
||||
(ಠ⌣ಠ)
|
||||
(ಠ益ಠ ╬)
|
||||
(ಠ益ಠ)
|
||||
(ಠ_ృ)
|
||||
(ಠ_ಠ)
|
||||
(ಥ﹏ಥ)
|
||||
(ಥ_ಥ)
|
||||
(๏̯͡๏ )
|
||||
(ღ˘⌣˘ღ) ♫・*:.。. .。.:*・
|
||||
(ღ˘⌣˘ღ)
|
||||
(ᵔᴥᵔ)
|
||||
(•ω•)
|
||||
(•‿•)
|
||||
(•⊙ω⊙•)
|
||||
(• ε •)
|
||||
(∩▂∩)
|
||||
(∩︵∩)
|
||||
(∪ ◡ ∪)
|
||||
(≧ω≦)
|
||||
(≧◡≦)
|
||||
(≧ロ≦)
|
||||
(⊙ヮ⊙)
|
||||
(⊙_◎)
|
||||
(⋋▂⋌)
|
||||
(⌐■_■)
|
||||
(‿‿)
|
||||
(┛◉Д◉)┛┻━┻
|
||||
(╥_╥)
|
||||
(╬ಠ益ಠ)
|
||||
(╬◣д◢)
|
||||
(╬ ಠ益ಠ)
|
||||
(╯°□°)╯︵ ┻━┻
|
||||
(╯ಊ╰)
|
||||
(╯◕_◕)╯
|
||||
(╯︵╰,)
|
||||
(╯3╰)
|
||||
(╯_╰)
|
||||
(╹◡╹)凸
|
||||
(▰˘◡˘▰)
|
||||
(●´ω`●)
|
||||
(●´`●)
|
||||
(◑‿◐)
|
||||
(◑◡◑)
|
||||
(◕‿◕✿)
|
||||
(◕‿◕)
|
||||
(◕‿-)
|
||||
(◕︵◕)
|
||||
(◕ ^ ◕)
|
||||
(◕_◕)
|
||||
(◜௰◝)
|
||||
(◡‿◡✿)
|
||||
(◣_◢)
|
||||
(☞゚゚)☞
|
||||
(☞゚ヮ゚)☞
|
||||
(☞゚ ゚ )☞
|
||||
(☼◡☼)
|
||||
(☼_☼)
|
||||
(✌゚゚)☞
|
||||
(✖╭╮✖)
|
||||
(✪㉨✪)
|
||||
(✿◠‿◠)
|
||||
(✿ ♥‿♥)
|
||||
( ・・)
|
||||
( ・ัω・ั)?
|
||||
( ゚゚)o彡゜えーりんえーりん!!
|
||||
(。・_・。)
|
||||
(つд`)
|
||||
(づ。◕‿‿◕。)づ
|
||||
(ノಠ益ಠ)ノ彡┻━┻
|
||||
(ノ ◑‿◑)ノ
|
||||
(ノ_・。)
|
||||
(・・ )
|
||||
(屮゚Д゚)屮
|
||||
(︶ω︶)
|
||||
(︶︹︺)
|
||||
(ﺧ益ﺨ)
|
||||
(;一_一)
|
||||
(`・ω・´)”
|
||||
(。◕‿‿◕。)
|
||||
(。◕‿◕。)
|
||||
(。◕ ‿ ◕。)
|
||||
(。♥‿♥。)
|
||||
(。・ω..・)っ
|
||||
(・ェ-)
|
||||
(ノ◕ヮ◕)ノ*:・゚✧
|
||||
(゚Д゚)
|
||||
(゚Д゚)y┛~~
|
||||
(゚゚)
|
||||
(゚ヮ゚)
|
||||
( ̄□ ̄)
|
||||
( ̄。 ̄)
|
||||
( ̄ー ̄)
|
||||
( ̄(エ) ̄)
|
||||
( °٢° )
|
||||
( ´_ゝ`)
|
||||
( ͡° ͜ʖ ͡°)
|
||||
( ͡~ ͜ʖ ͡°)
|
||||
( ಠ◡ಠ )
|
||||
( •_•)>⌐■-■
|
||||
( ゚,_ゝ゚)
|
||||
( ・ิз・ิ)
|
||||
( ゚д゚)、
|
||||
( ^▽^)σ)~O~)
|
||||
((((゜д゜;))))
|
||||
(*´д`*)
|
||||
(*..Д`)
|
||||
(*..д`*)
|
||||
(*~▽~)
|
||||
(-’๏_๏’-)
|
||||
(-_- )ノ
|
||||
(/◔ ◡ ◔)/
|
||||
(///_ಥ)
|
||||
(;´Д`)
|
||||
(=ω=;)
|
||||
(=゜ω゜)
|
||||
(>'o')> ♥ <('o'<)
|
||||
(n˘v˘•)¬
|
||||
(o´ω`o)
|
||||
(V)(°,,°)(V)
|
||||
(\/) (°,,°) (\/)
|
||||
(^▽^)
|
||||
(`・ω・´)
|
||||
(~ ̄▽ ̄)~
|
||||
/╲/\╭ºoꍘoº╮/\╱\
|
||||
<【☯】‿【☯】>
|
||||
= (゚д゚)ウ
|
||||
@_@
|
||||
d(*⌒▽⌒*)b
|
||||
o(≧≦)o
|
||||
o(≧o≦)o
|
||||
q(❂‿❂)p
|
||||
y=ー( ゚д゚)・∵.
|
||||
\˚ㄥ˚\
|
||||
\ᇂ_ᇂ\
|
||||
\(ಠ ὡ ಠ )/
|
||||
\(◕ ◡ ◕\)
|
||||
^̮^
|
||||
^ㅂ^
|
||||
_(͡๏̯͡๏)_
|
||||
{´◕ ◡ ◕`}
|
||||
{ಠ_ಠ}__,,|,
|
||||
{◕ ◡ ◕}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1,30 +0,0 @@
|
||||
[bot]
|
||||
nick = maple
|
||||
username = g1mp
|
||||
realname = "[ g1mp'n ain't easy unless you're maple ]"
|
||||
host = ircd.chat
|
||||
port = 6697
|
||||
version = 1
|
||||
url = ircd.chat
|
||||
ssl = true
|
||||
ssl_verify = CERT_NONE
|
||||
|
||||
includes =
|
||||
irc3.plugins.log
|
||||
irc3.plugins.logger
|
||||
plugins.command_plugin
|
||||
plugins.storage_plugin
|
||||
plugins.fifo_plugin
|
||||
plugins.sasl_custom_plugin
|
||||
plugins.net_hydra_plugin
|
||||
|
||||
autojoins =
|
||||
${#}PalletTown
|
||||
|
||||
flood_burst = 0
|
||||
flood_rate = 1
|
||||
flood_rate_delay = 1
|
||||
storage = json://databases/maple_db.json
|
||||
|
||||
[plugins.fifo_plugin]
|
||||
runpath = .fifo
|
@ -1,528 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from irc3.compat import asyncio
|
||||
from irc3 import utils
|
||||
from collections import defaultdict
|
||||
import functools
|
||||
import venusian
|
||||
import fnmatch
|
||||
import logging
|
||||
import docopt
|
||||
import shlex
|
||||
import irc3
|
||||
import sys
|
||||
import re
|
||||
__doc__ = '''
|
||||
==========================================
|
||||
:mod:`irc3.plugins.command` Command plugin
|
||||
==========================================
|
||||
|
||||
Introduce a ``@command`` decorator
|
||||
|
||||
The decorator use `docopts <http://docopt.org/>`_ to parse command arguments.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Create a python module with some commands:
|
||||
|
||||
.. literalinclude:: ../../examples/mycommands.py
|
||||
|
||||
..
|
||||
>>> import sys
|
||||
>>> sys.path.append('examples')
|
||||
>>> from irc3.testing import IrcBot
|
||||
>>> from irc3.testing import ini2config
|
||||
|
||||
And register it::
|
||||
|
||||
>>> bot = IrcBot()
|
||||
>>> bot.include('irc3.plugins.command') # register the plugin
|
||||
>>> bot.include('mycommands') # register your commands
|
||||
|
||||
|
||||
Check the result::
|
||||
|
||||
>>> bot.test(':gawel!user@host PRIVMSG #chan :!echo foo')
|
||||
PRIVMSG #chan :foo
|
||||
|
||||
In the docstring, ``%%`` is replaced by the command character. ``!`` by
|
||||
default. You can override it by passing a ``cmd`` parameter to bot's config.
|
||||
|
||||
When a command is not public, you can't use it on a channel::
|
||||
|
||||
>>> bot.test(':gawel!user@host PRIVMSG #chan :!adduser foo pass')
|
||||
PRIVMSG gawel :You can only use the 'adduser' command in private.
|
||||
|
||||
If a command is tagged with ``show_in_help_list=False``, it won't be shown
|
||||
on the result of ``!help``.
|
||||
|
||||
>>> bot.test(':gawel!user@host PRIVMSG #chan :!help')
|
||||
PRIVMSG #chan :Available commands: !adduser, !echo, !help
|
||||
|
||||
View extra info about a command by specifying it to ``!help``.
|
||||
|
||||
>>> bot.test(':gawel!user@host PRIVMSG #chan :!help echo')
|
||||
PRIVMSG #chan :Echo command
|
||||
PRIVMSG #chan :!echo <words>...
|
||||
>>> bot.test(':gawel!user@host PRIVMSG #chan :!help nonexistant')
|
||||
PRIVMSG #chan :No such command. Try !help for an overview of all commands.
|
||||
|
||||
Guard
|
||||
=====
|
||||
|
||||
You can use a guard to prevent untrusted users to run some commands. The
|
||||
:class:`free_policy` is used by default.
|
||||
|
||||
There is two builtin policy:
|
||||
|
||||
.. autoclass:: free_policy
|
||||
|
||||
|
||||
.. autoclass:: mask_based_policy
|
||||
|
||||
Mask based guard using permissions::
|
||||
|
||||
>>> config = ini2config("""
|
||||
... [bot]
|
||||
... nick = nono
|
||||
... includes =
|
||||
... irc3.plugins.command
|
||||
... mycommands
|
||||
... [irc3.plugins.command]
|
||||
... guard = irc3.plugins.command.mask_based_policy
|
||||
... [irc3.plugins.command.masks]
|
||||
... gawel!*@* = all_permissions
|
||||
... foo!*@* = help
|
||||
... """)
|
||||
>>> bot = IrcBot(**config)
|
||||
|
||||
foo is allowed to use command without permissions::
|
||||
|
||||
>>> bot.test(':foo!u@h PRIVMSG nono :!echo got the power')
|
||||
PRIVMSG foo :got the power
|
||||
|
||||
foo is not allowed to use command except those with the help permission::
|
||||
|
||||
>>> bot.test(':foo!u@h PRIVMSG nono :!ping')
|
||||
PRIVMSG foo :You are not allowed to use the 'ping' command
|
||||
|
||||
gawel is allowed::
|
||||
|
||||
>>> bot.test(':gawel!u@h PRIVMSG nono :!ping')
|
||||
NOTICE gawel :PONG gawel!
|
||||
|
||||
Async commands
|
||||
==============
|
||||
|
||||
Commands can be coroutines:
|
||||
|
||||
.. literalinclude:: ../../examples/async_command.py
|
||||
:language: py
|
||||
|
||||
Available options
|
||||
=================
|
||||
|
||||
The plugin accept the folowing options:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[irc3.plugins.command]
|
||||
cmd = !
|
||||
use_shlex = true
|
||||
antiflood = true
|
||||
casesensitive = true
|
||||
guard = irc3.plugins.command.mask_based_policy
|
||||
|
||||
|
||||
Command arguments
|
||||
=================
|
||||
|
||||
The :func:`command` decorator accept the folowing arguments:
|
||||
|
||||
**name**: if set, use this name as the command name instead of the function
|
||||
name.
|
||||
|
||||
**permission**: if set, this permission will be required to run the command.
|
||||
See Guard section
|
||||
|
||||
**use_shlex**: if `False`, do not use `shlex` to parse command line.
|
||||
|
||||
**options_first**: if `True` use docopt's options_first options. Allow to have
|
||||
args that starts with `-` as arguments.
|
||||
|
||||
**error_format**: allow to customize error messages. must be a callable that
|
||||
accept keyword arguments `cmd`, `args` and `exc`.
|
||||
For example, `error_format="Error for {cmd}".format` will work.
|
||||
|
||||
**quiet**: if `True` don't show errors
|
||||
|
||||
**aliases**: this argument, when present, should be a list of strings. All
|
||||
those strings will become alternative command names (i.e. aliases).
|
||||
For example, command 'mycmd' with aliases=['theircmd', 'noonescmd'] could
|
||||
be called via all three names.
|
||||
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class free_policy:
|
||||
"""Default policy"""
|
||||
def __init__(self, bot):
|
||||
self.context = bot
|
||||
|
||||
def __call__(self, predicates, meth, client, target, args, **kwargs):
|
||||
return meth(client, target, args)
|
||||
|
||||
|
||||
class mask_based_policy:
|
||||
"""Allow only valid masks. Able to take care or permissions"""
|
||||
|
||||
key = __name__ + '.masks'
|
||||
|
||||
def __init__(self, bot):
|
||||
self.context = bot
|
||||
self.log = logging.getLogger(__name__)
|
||||
self.log.debug('Masks: %r', self.masks)
|
||||
|
||||
@property
|
||||
def masks(self):
|
||||
masks = self.context.config[self.key]
|
||||
if hasattr(self.context, 'db'):
|
||||
# update config with storage values
|
||||
try:
|
||||
value = self.context.db[self]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(value, dict):
|
||||
masks.update(value)
|
||||
return masks
|
||||
|
||||
def has_permission(self, mask, permission):
|
||||
if permission is None:
|
||||
return True
|
||||
for pattern in self.masks:
|
||||
if fnmatch.fnmatch(mask, pattern):
|
||||
if not isinstance(self.masks, dict):
|
||||
return True
|
||||
perms = self.masks[pattern]
|
||||
if permission in perms or 'all_permissions' in perms:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __call__(self, predicates, meth, client, target, args, **kwargs):
|
||||
if self.has_permission(client, predicates.get('permission')):
|
||||
return meth(client, target, args)
|
||||
cmd_name = predicates.get('name', meth.__name__)
|
||||
self.context.privmsg(
|
||||
client.nick,
|
||||
'You are not allowed to use the %r command' % cmd_name)
|
||||
|
||||
|
||||
def attach_command(func, depth=2, **predicates):
|
||||
commands = predicates.pop('commands',
|
||||
'irc3.plugins.command.Commands')
|
||||
category = predicates.pop('venusian_category',
|
||||
'irc3.plugins.command')
|
||||
|
||||
def callback(context, name, ob):
|
||||
obj = context.context
|
||||
if info.scope == 'class':
|
||||
callback = func.__get__(obj.get_plugin(ob), ob)
|
||||
else:
|
||||
callback = utils.wraps_with_context(func, obj)
|
||||
plugin = obj.get_plugin(utils.maybedotted(commands))
|
||||
predicates.update(module=func.__module__)
|
||||
cmd_name = predicates.get('name', func.__name__)
|
||||
if not plugin.case_sensitive:
|
||||
cmd_name = cmd_name.lower()
|
||||
plugin[cmd_name] = (predicates, callback)
|
||||
aliases = predicates.get('aliases', None)
|
||||
if aliases is not None:
|
||||
for alias in aliases:
|
||||
plugin.aliases[alias] = cmd_name
|
||||
obj.log.debug('Register command %r %r', cmd_name, aliases)
|
||||
else:
|
||||
obj.log.debug('Register command %r', cmd_name)
|
||||
info = venusian.attach(func, callback,
|
||||
category=category, depth=depth)
|
||||
|
||||
|
||||
def command(*func, **predicates):
|
||||
if func:
|
||||
func = func[0]
|
||||
attach_command(func, **predicates)
|
||||
return func
|
||||
else:
|
||||
def wrapper(func):
|
||||
attach_command(func, **predicates)
|
||||
return func
|
||||
return wrapper
|
||||
|
||||
|
||||
@irc3.plugin
|
||||
class Commands(dict):
|
||||
|
||||
__reloadable__ = False
|
||||
|
||||
requires = [
|
||||
__name__.replace('command', 'core'),
|
||||
]
|
||||
default_policy = free_policy
|
||||
case_sensitive = False
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
module = self.__class__.__module__
|
||||
self.config = config = context.config.get(module, {})
|
||||
self.log = logging.getLogger(module)
|
||||
self.log.debug('Config: %r', config)
|
||||
|
||||
if 'cmd' in context.config: # in case of
|
||||
config['cmd'] = context.config['cmd']
|
||||
context.config['cmd'] = self.cmd = config.get('cmd', '!')
|
||||
context.config['re_cmd'] = re.escape(self.cmd)
|
||||
|
||||
self.use_shlex = self.config.get('use_shlex', True)
|
||||
self.antiflood = self.config.get('antiflood', False)
|
||||
self.case_sensitive = self.config.get('casesensitive',
|
||||
self.case_sensitive)
|
||||
|
||||
guard = utils.maybedotted(config.get('guard', self.default_policy))
|
||||
self.log.debug('Guard: %s', guard.__name__)
|
||||
self.guard = guard(context)
|
||||
|
||||
self.error_format = utils.maybedotted(config.get('error_format',
|
||||
"Invalid arguments.".format))
|
||||
self.handles = defaultdict(Done)
|
||||
self.tasks = defaultdict(Done)
|
||||
|
||||
self.aliases = {}
|
||||
|
||||
def split_command(self, data, use_shlex=None):
|
||||
if not data:
|
||||
return []
|
||||
return shlex.split(data) if use_shlex else data.split(' ')
|
||||
|
||||
@irc3.event((r'(@(?P<tags>\S+) )?:(?P<mask>\S+) PRIVMSG (?P<target>\S+) '
|
||||
r':{re_cmd}(?P<cmd>[\w-]+)(\s+(?P<data>\S.*)|(\s*$))'))
|
||||
def on_command(self, cmd, mask=None, target=None, client=None, **kw):
|
||||
if not self.case_sensitive:
|
||||
cmd = cmd.lower()
|
||||
cmd = self.aliases.get(cmd, cmd)
|
||||
predicates, meth = self.get(cmd, (None, None))
|
||||
if meth is not None:
|
||||
if predicates.get('public', True) is False and target.is_channel:
|
||||
self.context.privmsg(
|
||||
mask.nick,
|
||||
'You can only use the %r command in private.' % str(cmd))
|
||||
else:
|
||||
return self.do_command(predicates, meth, mask, target, **kw)
|
||||
|
||||
def do_command(self, predicates, meth, client, target, data=None, **kw):
|
||||
nick = self.context.nick or '-'
|
||||
to = client.nick if target == nick else target
|
||||
doc = meth.__doc__ or ''
|
||||
doc = [line.strip() for line in doc.strip().split('\n')]
|
||||
doc = [nick + ' ' + line.strip('%%')
|
||||
for line in doc if line.startswith('%%')]
|
||||
doc = 'Usage:' + '\n ' + '\n '.join(doc)
|
||||
if data:
|
||||
if not isinstance(data, str): # pragma: no cover
|
||||
encoding = self.context.encoding
|
||||
data = data.encode(encoding)
|
||||
try:
|
||||
data = self.split_command(
|
||||
data, use_shlex=predicates.get('use_shlex', self.use_shlex))
|
||||
except ValueError as e:
|
||||
if not predicates.get('quiet', False):
|
||||
self.context.privmsg(to, 'Invalid arguments: {}.'.format(e))
|
||||
return
|
||||
docopt_args = dict(help=False)
|
||||
if "options_first" in predicates:
|
||||
docopt_args.update(options_first=predicates["options_first"])
|
||||
cmd_name = predicates.get('name', meth.__name__)
|
||||
try:
|
||||
args = docopt.docopt(doc, [cmd_name] + data, **docopt_args)
|
||||
except docopt.DocoptExit as exc:
|
||||
if not predicates.get('quiet', False):
|
||||
args = {'cmd': cmd_name, 'args': data,
|
||||
'args_str': " ".join(data), 'exc': exc}
|
||||
error_format = predicates.get('error_format',
|
||||
self.error_format)
|
||||
self.context.privmsg(to, error_format(**args))
|
||||
else:
|
||||
uid = (cmd_name, to)
|
||||
use_client = isinstance(client, asyncio.Protocol)
|
||||
if not self.tasks[uid].done():
|
||||
self.context.notice(
|
||||
client if use_client else client.nick,
|
||||
"Another task is already running. "
|
||||
"Please be patient and don't flood me", nowait=True)
|
||||
elif not self.handles[uid].done() and self.antiflood:
|
||||
self.context.notice(
|
||||
client if use_client else client.nick,
|
||||
"Please be patient and don't flood me", nowait=True)
|
||||
else:
|
||||
# get command result
|
||||
res = self.guard(predicates, meth, client, target, args=args)
|
||||
|
||||
callback = functools.partial(self.command_callback, uid, to)
|
||||
if res is not None:
|
||||
coros = (
|
||||
asyncio.iscoroutinefunction(meth),
|
||||
asyncio.iscoroutinefunction(self.guard.__call__)
|
||||
)
|
||||
if any(coros):
|
||||
task = asyncio.ensure_future(
|
||||
res, loop=self.context.loop)
|
||||
# use a callback if command is a coroutine
|
||||
task.add_done_callback(callback)
|
||||
self.tasks[uid] = task
|
||||
return task
|
||||
else:
|
||||
# no callback needed
|
||||
callback(res)
|
||||
|
||||
def command_callback(self, uid, to, msgs):
|
||||
if isinstance(msgs, asyncio.Future): # pragma: no cover
|
||||
msgs = msgs.result()
|
||||
if msgs is not None:
|
||||
def iterator(msgs):
|
||||
for msg in msgs:
|
||||
yield to, msg
|
||||
if isinstance(msgs, str):
|
||||
msgs = [msgs]
|
||||
handle = self.context.call_many('privmsg', iterator(msgs))
|
||||
if handle is not None:
|
||||
self.handles[uid] = handle
|
||||
|
||||
@command
|
||||
def help(self, mask, target, args):
|
||||
"""Show help
|
||||
|
||||
%%help [<cmd>]
|
||||
"""
|
||||
return "not today stan"
|
||||
if args['<cmd>']:
|
||||
args = args['<cmd>']
|
||||
# Strip out self.context.config.cmd from args so we can use
|
||||
# both !help !foo and !help foo
|
||||
if args.startswith(self.context.config.cmd):
|
||||
args = args[len(self.context.config.cmd):]
|
||||
args = self.aliases.get(args, args)
|
||||
predicates, meth = self.get(args, (None, None))
|
||||
if meth is not None:
|
||||
doc = meth.__doc__ or ''
|
||||
doc = [
|
||||
line.strip() for line in doc.split('\n')
|
||||
if line.strip()
|
||||
]
|
||||
buf = ''
|
||||
for line in doc:
|
||||
if '%%' not in line and buf is not None:
|
||||
buf += line + ' '
|
||||
else:
|
||||
if buf is not None:
|
||||
for b in utils.split_message(buf, 160):
|
||||
yield b
|
||||
buf = None
|
||||
line = line.replace('%%', self.context.config.cmd)
|
||||
yield line
|
||||
aliases = predicates.get('aliases', None)
|
||||
if aliases is not None:
|
||||
yield 'Aliases: {0}'.format(','.join(sorted(aliases)))
|
||||
else:
|
||||
yield ('No such command. Try %shelp for an '
|
||||
'overview of all commands.'
|
||||
% self.context.config.cmd)
|
||||
else:
|
||||
cmds = sorted((k for (k, (p, m)) in self.items()
|
||||
if p.get('show_in_help_list', True)))
|
||||
cmds_str = ', '.join([self.cmd + k for k in cmds])
|
||||
lines = utils.split_message(
|
||||
'Available commands: %s ' % cmds_str, 160)
|
||||
for line in lines:
|
||||
yield line
|
||||
url = self.config.get('url')
|
||||
if url:
|
||||
yield 'Full help is available at ' + url
|
||||
|
||||
def __repr__(self):
|
||||
return '<Commands %s>' % sorted([self.cmd + k for k in self.keys()])
|
||||
|
||||
|
||||
class Done:
|
||||
|
||||
def done(self):
|
||||
return True
|
||||
|
||||
|
||||
@command(permission='admin', show_in_help_list=False, public=False)
|
||||
def ping(bot, mask, target, args):
|
||||
"""ping/pong
|
||||
|
||||
%%ping
|
||||
"""
|
||||
bot.send('NOTICE %(nick)s :PONG %(nick)s!' % dict(nick=mask.nick))
|
||||
|
||||
|
||||
@command(venusian_category='irc3.debug', show_in_help_list=False)
|
||||
def quote(bot, mask, target, args):
|
||||
"""send quote to the server
|
||||
|
||||
%%quote <args>...
|
||||
"""
|
||||
msg = ' '.join(args['<args>'])
|
||||
bot.log.info('quote> %r', msg)
|
||||
bot.send(msg)
|
||||
|
||||
|
||||
@command(venusian_category='irc3.debug', show_in_help_list=False)
|
||||
def reconnect(bot, mask, target, args):
|
||||
"""force reconnect
|
||||
|
||||
%%reconnect
|
||||
"""
|
||||
plugin = bot.get_plugin(utils.maybedotted('irc3.plugins.core.Core'))
|
||||
bot.loop.call_soon(plugin.reconnect)
|
||||
|
||||
|
||||
@irc3.extend
|
||||
def print_help_page(bot, file=sys.stdout):
|
||||
"""print help page"""
|
||||
def p(text):
|
||||
print(text, file=file)
|
||||
plugin = bot.get_plugin(Commands)
|
||||
title = "Available Commands for {nick} at {host}".format(**bot.config)
|
||||
p("=" * len(title))
|
||||
p(title)
|
||||
p("=" * len(title))
|
||||
p('')
|
||||
p('.. contents::')
|
||||
p('')
|
||||
modules = {}
|
||||
for name, (predicates, callback) in plugin.items():
|
||||
commands = modules.setdefault(callback.__module__, [])
|
||||
commands.append((name, callback, predicates))
|
||||
|
||||
for module in sorted(modules):
|
||||
p(module)
|
||||
p('=' * len(module))
|
||||
p('')
|
||||
for name, callback, predicates in sorted(modules[module]):
|
||||
p(name)
|
||||
p('-' * len(name))
|
||||
p('')
|
||||
doc = callback.__doc__
|
||||
doc = doc.replace('%%', bot.config.cmd)
|
||||
for line in doc.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith(bot.config.cmd):
|
||||
line = ' ``{}``'.format(line)
|
||||
p(line)
|
||||
if 'permission' in predicates:
|
||||
p('*Require {0[permission]} permission.*'.format(predicates))
|
||||
if predicates.get('public', True) is False:
|
||||
p('*Only available in private.*')
|
||||
p('')
|
@ -1,118 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from irc3 import event
|
||||
from irc3 import rfc
|
||||
__doc__ = '''
|
||||
==============================================
|
||||
:mod:`irc3.plugins.core` Core plugin
|
||||
==============================================
|
||||
|
||||
Core events
|
||||
|
||||
.. autoclass:: Core
|
||||
:members:
|
||||
|
||||
..
|
||||
>>> from irc3.testing import IrcBot
|
||||
|
||||
Usage::
|
||||
|
||||
>>> bot = IrcBot()
|
||||
>>> bot.include('irc3.plugins.core')
|
||||
'''
|
||||
|
||||
|
||||
class Core:
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.timeout = int(self.bot.config.get('timeout'))
|
||||
self.max_lag = int(self.bot.config.get('max_lag'))
|
||||
self.reconn_handle = None
|
||||
self.ping_handle = None
|
||||
self.nick_handle = None
|
||||
self.before_connect_events = [
|
||||
event(rfc.CONNECTED, self.connected),
|
||||
event(r"^:\S+ 005 \S+ (?P<data>.+) :\S+.*",
|
||||
self.set_config),
|
||||
]
|
||||
|
||||
def connection_made(self, client=None):
|
||||
# handle server config
|
||||
config = self.bot.defaults['server_config'].copy()
|
||||
self.bot.config['server_config'] = config
|
||||
self.bot.detach_events(*self.before_connect_events)
|
||||
self.bot.attach_events(insert=True, *self.before_connect_events)
|
||||
|
||||
# ping/ping
|
||||
self.connection_made_at = self.bot.loop.time()
|
||||
self.pong(event='CONNECT', data='')
|
||||
|
||||
def connected(self, **kwargs):
|
||||
"""triger the server_ready event"""
|
||||
self.bot.log.info('Server config: %r', self.bot.server_config)
|
||||
|
||||
# recompile when I'm sure of my nickname
|
||||
self.bot.config['nick'] = kwargs['me']
|
||||
self.bot.recompile()
|
||||
|
||||
# Let all plugins know that server can handle commands
|
||||
self.bot.notify('server_ready')
|
||||
|
||||
# detach useless events
|
||||
self.bot.detach_events(*self.before_connect_events)
|
||||
|
||||
def reconnect(self): # pragma: no cover
|
||||
self.bot.log.info(
|
||||
"We're waiting a ping for too long. Trying to reconnect...")
|
||||
self.bot.loop.call_soon(
|
||||
self.bot.protocol.connection_lost,
|
||||
'No pong reply'
|
||||
)
|
||||
self.pong(event='RECONNECT', data='')
|
||||
|
||||
@event(rfc.PONG)
|
||||
def pong(self, event='PONG', data='', **kw): # pragma: no cover
|
||||
"""P0NG/PING"""
|
||||
self.bot.log.debug('%s ping-pong (%s)', event, data)
|
||||
if self.reconn_handle is not None:
|
||||
self.reconn_handle.cancel()
|
||||
self.reconn_handle = self.bot.loop.call_later(self.timeout,
|
||||
self.reconnect)
|
||||
if self.ping_handle is not None:
|
||||
self.ping_handle.cancel()
|
||||
self.ping_handle = self.bot.loop.call_later(
|
||||
self.timeout - self.max_lag, self.bot.send,
|
||||
'PING :%s' % int(self.bot.loop.time()))
|
||||
|
||||
@event(rfc.PING)
|
||||
def ping(self, data):
|
||||
"""PING reply"""
|
||||
self.bot.send('PONG :' + data)
|
||||
self.pong(event='PING', data=data)
|
||||
|
||||
@event(rfc.NEW_NICK)
|
||||
def recompile(self, nick=None, new_nick=None, **kw):
|
||||
"""recompile regexp on new nick"""
|
||||
if self.bot.nick == nick.nick:
|
||||
self.bot.config['nick'] = new_nick
|
||||
self.bot.recompile()
|
||||
|
||||
@event(rfc.ERR_NICK)
|
||||
def badnick(self, me=None, nick=None, **kw):
|
||||
"""Use alt nick on nick error"""
|
||||
if me == '*':
|
||||
self.bot.set_nick(self.bot.nick + '_')
|
||||
self.bot.log.debug('Trying to regain nickname in 30s...')
|
||||
self.nick_handle = self.bot.loop.call_later(
|
||||
30, self.bot.set_nick, self.bot.original_nick)
|
||||
|
||||
def set_config(self, data=None, **kwargs):
|
||||
"""Store server config"""
|
||||
config = self.bot.config['server_config']
|
||||
for opt in data.split(' '):
|
||||
if '=' in opt:
|
||||
opt, value = opt.split('=', 1)
|
||||
else:
|
||||
value = True
|
||||
if opt.isupper():
|
||||
config[opt] = value
|
@ -1,101 +0,0 @@
|
||||
# -*- coding: utf-8 -*- ############################################################### SOF
|
||||
import os
|
||||
import irc3
|
||||
from stat import S_ISFIFO
|
||||
###########################################################################################
|
||||
@irc3.plugin
|
||||
class Fifo:
|
||||
#######################################################################################
|
||||
BLOCK_SIZE = 1024
|
||||
MAX_BUFFER_SIZE = 800
|
||||
#######################################################################################
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self.config = self.context.config
|
||||
self.send_blank_line = self.config.get('send_blank_line', True)
|
||||
self.runpath = self.config.get('runpath', f'{os.getcwd()}/fifo')
|
||||
if not os.path.exists(self.runpath):
|
||||
os.makedirs(self.runpath)
|
||||
self.loop = self.context.loop
|
||||
self.fifos = {}
|
||||
self.buffers = {}
|
||||
self.create_fifo(None)
|
||||
#######################################################################################
|
||||
@classmethod
|
||||
def read_fd(cls, fd):
|
||||
while True:
|
||||
try:
|
||||
return os.read(fd, cls.BLOCK_SIZE)
|
||||
except InterruptedError:
|
||||
continue
|
||||
except BlockingIOError:
|
||||
return b""
|
||||
#######################################################################################
|
||||
def handle_line(self, line, channel):
|
||||
if not line:
|
||||
return
|
||||
line = line.decode("utf8")
|
||||
if not self.send_blank_line and not line.strip():
|
||||
return
|
||||
if channel is None:
|
||||
self.context.send_line(line)
|
||||
else:
|
||||
self.context.privmsg(channel, line)
|
||||
#######################################################################################
|
||||
def data_received(self, data, channel):
|
||||
if not data:
|
||||
return
|
||||
prev = self.buffers.get(channel, b"")
|
||||
lines = (prev + data).splitlines(True)
|
||||
last = lines[-1]
|
||||
for line in lines[:-1]:
|
||||
line = line.rstrip(b'\r\n')
|
||||
self.handle_line(line, channel)
|
||||
if last.endswith(b'\n'):
|
||||
line = last.rstrip(b'\r\n')
|
||||
self.handle_line(line, channel)
|
||||
self.buffers[channel] = b""
|
||||
return
|
||||
if len(last) > self.MAX_BUFFER_SIZE:
|
||||
self.handle_line(last, channel)
|
||||
self.buffers[channel] = b""
|
||||
else:
|
||||
self.buffers[channel] = last
|
||||
#######################################################################################
|
||||
def watch_fd(self, fd, channel):
|
||||
reading = True
|
||||
|
||||
while reading:
|
||||
data = self.read_fd(fd)
|
||||
reading = len(data) == self.BLOCK_SIZE
|
||||
self.data_received(data, channel)
|
||||
#######################################################################################
|
||||
def create_fifo(self, channel):
|
||||
if channel is None:
|
||||
path = os.path.join(self.runpath, ':raw')
|
||||
else:
|
||||
path = os.path.join(self.runpath, channel.strip('#&+'))
|
||||
try:
|
||||
mode = os.stat(path).st_mode
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
if not S_ISFIFO(mode):
|
||||
self.context.log.warn(
|
||||
'file %s created without mkfifo. remove it',
|
||||
path)
|
||||
os.remove(path)
|
||||
if not os.path.exists(path):
|
||||
os.mkfifo(path)
|
||||
fd = os.open(path, os.O_RDWR | os.O_NONBLOCK)
|
||||
self.loop.add_reader(fd, self.watch_fd, fd, channel)
|
||||
self.context.log.debug("%s's fifo is %s %r",
|
||||
channel or ':raw', path, fd)
|
||||
return fd
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.JOIN)
|
||||
def join(self, mask=None, channel=None, **kwargs):
|
||||
if mask.nick == self.context.nick:
|
||||
if channel not in self.fifos:
|
||||
self.fifos[channel] = self.create_fifo(channel)
|
||||
####################################################################################### EOF
|
@ -1,176 +0,0 @@
|
||||
# -*- coding: utf-8 -*- ############################################################### SOF
|
||||
from irc3.plugins.command import command
|
||||
from irc3.plugins.cron import cron
|
||||
from irc3.plugins import core
|
||||
import irc3
|
||||
import os
|
||||
from random import randint as rint
|
||||
from random import shuffle
|
||||
from datetime import datetime
|
||||
###########################################################################################
|
||||
class dr1p:
|
||||
def __init__():
|
||||
dr1p.designation=""
|
||||
dr1p.enforcing=False
|
||||
dr1p.purpose=""
|
||||
dr1p.color=""
|
||||
dr1p.keyid=""
|
||||
dr1p.token=""
|
||||
dr1p.home=""
|
||||
###########################################################################################
|
||||
@irc3.plugin
|
||||
class Plugin:
|
||||
#######################################################################################
|
||||
def __init__(self,bot):
|
||||
self.bot=bot
|
||||
try:
|
||||
dr1p.purpose=os.environ['HYDRA_PURPOSE']
|
||||
dr1p.designation=os.environ['HYDRA_DESIGNATION']
|
||||
dr1p.home=os.environ['HYDRA_HOME']
|
||||
dr1p.enforcing=False
|
||||
except:
|
||||
dr1p.designation="dupe"
|
||||
dr1p.enforcing=False
|
||||
return
|
||||
if dr1p.designation=="core": dr1p.color="\x0304"
|
||||
dr1p.keyid=self.hydra_id(1)
|
||||
dr1p.token=self.hydra_id(0)
|
||||
#######################################################################################
|
||||
def hydra_id(self,mode=1):
|
||||
# from datetime import datetime
|
||||
# from random import randint as rint
|
||||
# from random import shuffle
|
||||
hydra=""
|
||||
for i in range(7): hydra+=hex(rint(0,255))[2:].zfill(2).upper()
|
||||
hydra+=hex(int(datetime.now().timestamp()))[-4:].upper()
|
||||
hydra=list(hydra)
|
||||
shuffle(hydra)
|
||||
if mode:
|
||||
hydra=''.join(hydra)
|
||||
self.keyid=hydra
|
||||
else:
|
||||
hydra=''.join(hydra)[6:14]
|
||||
self.token=hydra
|
||||
return hydra
|
||||
#######################################################################################
|
||||
def server_ready(self):
|
||||
if not dr1p.designation=='core':
|
||||
self.token
|
||||
self.bot.privmsg("maple",f"[hydra:{dr1p.keyid}] - dupe - connected")
|
||||
else:
|
||||
self.bot.privmsg("maple",f"core - connected")
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.ERR_NICK)
|
||||
def on_errnick(self,srv=None,retcode=None,me=None,nick=None,data=None):
|
||||
###################################################################################
|
||||
if not dr1p.designation=='core': return
|
||||
msg=f'err_nick - srv:{srv} - retcode:{retcode} - me:{me} - nick:{nick} - data:{data}'
|
||||
self.bot.privmsg("maple",msg.lower())
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.NEW_NICK)
|
||||
def on_newnick(self,nick=None,new_nick=None):
|
||||
###################################################################################
|
||||
if not dr1p.designation=='core': return
|
||||
if nick==self.bot.config['nick'] or new_nick==self.bot.config['nick']:
|
||||
msg=f'new_nick - nick:{nick} - new_nick:{new_nick}'
|
||||
self.bot.privmsg("maple",msg.lower())
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.CTCP)
|
||||
def on_ctcp(self,mask=None,event=None,target=None,ctcp=None):
|
||||
###################################################################################
|
||||
if not dr1p.designation=='core': return
|
||||
msg=f'ctcpd - mask:{mask} - event:{event} - target:{target} - ctcp:{ctcp}'
|
||||
self.bot.privmsg("maple",msg.lower())
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.INVITE)
|
||||
def on_invite(self,mask=None,channel=None):
|
||||
###################################################################################
|
||||
if not dr1p.designation=='core': return
|
||||
msg=f'invited - mask:{mask} - channel:{channel}'
|
||||
self.bot.privmsg("maple",msg.lower())
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.KICK)
|
||||
def on_kick(self,mask=None,event=None,channel=None,target=None,data=None):
|
||||
###################################################################################
|
||||
if not dr1p.designation=='core': return
|
||||
msg=f'kicked - mask:{mask} - event:{event} - target:{target} - data:{data}'
|
||||
self.bot.privmsg("maple",msg)
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.PRIVMSG)
|
||||
def on_privmsg(self,mask=None,event=None,target=None,data=None,**kw):
|
||||
###################################################################################
|
||||
# if dr1p.enforcing==False: return
|
||||
if target!=self.bot.config['nick'] and mask.nick==self.bot.nick: return
|
||||
if mask.nick==self.bot.nick and target==self.bot.config['nick'] and dr1p.designation=='core':
|
||||
if data.endswith('dupe - connected'):
|
||||
_keyid=data.split("[hydra:")[1].split("]")[0]
|
||||
_diyek=_keyid[::-1]
|
||||
msg=f'[KEYID:{_keyid}] - [DIYEK:{_diyek}] - COLOR:{rint(16,87)}'
|
||||
self.bot.privmsg(self.bot.config['nick'],msg)
|
||||
if mask.nick==self.bot.nick and target==self.bot.config['nick'] and dr1p.designation=='dupe':
|
||||
if not data.find('DIYEK')==-1:
|
||||
_keyid=data.split(":")[1].split("]")[0]
|
||||
if _keyid.lower()==dr1p.keyid.lower():
|
||||
if not data.find("] - [DIYEK:")==-1:
|
||||
_diyek=data.split("] - [DIYEK:")[1].split("]")[0]
|
||||
if _keyid.lower()==_diyek[::-1].lower():
|
||||
_color=int(data.split(" - COLOR:")[1].strip())
|
||||
if not dr1p.color:
|
||||
dr1p.color=f"\x03{str(_color)}"
|
||||
if dr1p.designation=='core':
|
||||
msg=f"{dr1p.color}[maple:{dr1p.keyid}] - "
|
||||
else:
|
||||
_keyid=data.split("[hydra:")[1].split("]")[0]
|
||||
if self.keyid==_keyid:
|
||||
try:
|
||||
msg=f"{dr1p.color}[hydra:{dr1p.keyid}] - "
|
||||
except:
|
||||
dr1p.color="\x0303"
|
||||
msg=f"{dr1p.color}[hydra:{dr1p.keyid}] - "
|
||||
_keyid=data.split("[hydra:")[1].split("]")[0]
|
||||
if self.keyid==_keyid:
|
||||
if mask.nick!=self.bot.config['nick']:
|
||||
if target!=dr1p.home: return
|
||||
if target==dr1p.home: return
|
||||
msg+=f'event:{event} - mask:{mask} - target:{target} - data:'
|
||||
msg+=f'{data}'
|
||||
if kw: msg+=f" - kw:{kw}"
|
||||
self.bot.privmsg(dr1p.home,msg.lower())
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.MY_PRIVMSG)
|
||||
def on_my_privmsg(self,mask=None,event=None,target=None,data=None,**kw):
|
||||
###################################################################################
|
||||
pass
|
||||
#######################################################################################
|
||||
@irc3.event(irc3.rfc.JOIN_PART_QUIT)
|
||||
def on_join_part_quit(self,mask=None,target=None,data=None,**kw):
|
||||
target=kw['channel']
|
||||
###################################################################################
|
||||
if mask.nick==self.bot.config['nick']:
|
||||
###############################################################################
|
||||
if kw['event']=='JOIN':
|
||||
self.bot.privmsg("maple",f"joined {target}".lower())
|
||||
if target!=dr1p.home:
|
||||
if dr1p.enforcing:
|
||||
reason=".[d]."
|
||||
self.bot.part(target,reason)
|
||||
self.bot.privmsg("maple",f"parted {target} - {reason}".lower())
|
||||
if dr1p.designation=="core":
|
||||
msg=f"[maple:{dr1p.keyid}] - core - maple online - test purpose: {dr1p.purpose}"
|
||||
self.bot.privmsg(dr1p.home,msg)
|
||||
else:
|
||||
msg=f"[hydra:{dr1p.keyid}] - dupe - hydra online - test purpose: {dr1p.purpose}"
|
||||
self.bot.privmsg(dr1p.home,msg)
|
||||
if kw['event']=='PART':
|
||||
if dr1p.designation=="core":
|
||||
msg=f"[maple:{dr1p.keyid}] -"
|
||||
else:
|
||||
msg=f"[hydra:{dr1p.keyid}] -"
|
||||
self.bot.privmsg("maple",msg+f"parted {target} - {data}")
|
||||
if kw['event']=='QUIT':
|
||||
if dr1p.designation=="core":
|
||||
msg=f"[maple:{dr1p.keyid}] -"
|
||||
else:
|
||||
msg=f"[hydra:{dr1p.keyid}] -"
|
||||
self.bot.privmsg("maple",msg+f"quit {target} - {data}")
|
||||
####################################################################################### EOF
|
@ -1,48 +0,0 @@
|
||||
# -*- coding: utf-8 -*- ########################################################## SOF
|
||||
import irc3, os, base64
|
||||
######################################################################################
|
||||
BOT_SASL_USERNAME=os.environ['BOT_SASL_USERNAME']
|
||||
BOT_SASL_PASSWORD=os.environ['BOT_SASL_PASSWORD']
|
||||
######################################################################################
|
||||
@irc3.plugin
|
||||
class DR1PSASL:
|
||||
##################################################################################
|
||||
def __init__(self, bot):
|
||||
print('<<< _sasl_custom_plugin >>> [ custom sasl initiated ]')
|
||||
self.bot=bot
|
||||
self.auth=(f'{BOT_SASL_USERNAME}\0{BOT_SASL_USERNAME}\0{BOT_SASL_PASSWORD}')
|
||||
self.auth=base64.encodebytes(self.auth.encode('utf8'))
|
||||
self.auth=self.auth.decode('utf8').rstrip('\n')
|
||||
self.events = [
|
||||
irc3.event(r'^:\S+ CAP \S+ LS :(?P<data>.*)', self.cap_ls),
|
||||
irc3.event(r'^:\S+ CAP \S+ ACK sasl', self.cap_ack),
|
||||
irc3.event(r'AUTHENTICATE +', self.authenticate),
|
||||
irc3.event(r'^:\S+ 903 \S+ :Authentication successful',self.cap_end),
|
||||
]
|
||||
##################################################################################
|
||||
def connection_ready(self, *args, **kwargs):
|
||||
print('<<< _sasl_custom_plugin >>> [ CAP LS ]')
|
||||
self.bot.send('CAP LS\r\n')
|
||||
self.bot.attach_events(*self.events)
|
||||
##################################################################################
|
||||
def cap_ls(self, data=None, **kwargs):
|
||||
print('<<< _sasl_custom_plugin >>> [ CAP REQ :sasl ]')
|
||||
if 'sasl' in data.lower():
|
||||
self.bot.send_line('CAP REQ :sasl')
|
||||
else:
|
||||
self.cap_end()
|
||||
##################################################################################
|
||||
def cap_ack(self, **kwargs):
|
||||
print('<<< _sasl_custom_plugin >>> [ AUTHENTICATE PLAIN ]')
|
||||
self.bot.send_line('AUTHENTICATE PLAIN')
|
||||
##################################################################################
|
||||
def authenticate(self, **kwargs):
|
||||
print(f'<<< _sasl_custom_plugin >>> [ AUTHENTICATE {self.auth} ]')
|
||||
self.bot.send_line(f'AUTHENTICATE {self.auth}\n')
|
||||
##################################################################################
|
||||
def cap_end(self, **kwargs):
|
||||
print('<<< _sasl_custom_plugin >>> [ CAP END ]')
|
||||
self.bot.send_line('CAP END\r\n')
|
||||
self.bot.detach_events(*self.events)
|
||||
##################################################################################
|
||||
################################################################################## EOF
|
@ -1,293 +0,0 @@
|
||||
# -*- coding: utf-8 -*- ############################################################### SOF
|
||||
import os
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
import irc3
|
||||
import shelve
|
||||
###########################################################################################
|
||||
class Shelve:
|
||||
#######################################################################################
|
||||
def __init__(self, uri=None, **kwargs):
|
||||
self.filename = uri[9:]
|
||||
self.db = shelve.open(self.filename)
|
||||
#######################################################################################
|
||||
def set(self, key, value):
|
||||
self.db[key] = value
|
||||
self.db.sync()
|
||||
#######################################################################################
|
||||
def get(self, key):
|
||||
return self.db[key]
|
||||
#######################################################################################
|
||||
def delete(self, key):
|
||||
del self.db[key]
|
||||
self.sync()
|
||||
#######################################################################################
|
||||
def contains(self, key):
|
||||
return key in self.db
|
||||
#######################################################################################
|
||||
def sync(self):
|
||||
self.db.sync()
|
||||
#######################################################################################
|
||||
def close(self):
|
||||
self.db.close()
|
||||
###########################################################################################
|
||||
class JSON:
|
||||
def __init__(self, uri=None, **kwargs):
|
||||
self.filename = uri[7:]
|
||||
if os.path.isfile(self.filename): # pragma: no cover
|
||||
with open(self.filename) as fd:
|
||||
self.db = json.load(fd)
|
||||
else:
|
||||
self.db = {}
|
||||
#######################################################################################
|
||||
def set(self, key, value):
|
||||
self.db[key] = value
|
||||
self.sync()
|
||||
#######################################################################################
|
||||
def get(self, key):
|
||||
return self.db[key]
|
||||
#######################################################################################
|
||||
def delete(self, key):
|
||||
del self.db[key]
|
||||
self.sync()
|
||||
#######################################################################################
|
||||
def contains(self, key):
|
||||
return key in self.db
|
||||
#######################################################################################
|
||||
def sync(self):
|
||||
with open(self.filename, 'w') as fd:
|
||||
json.dump(self.db, fd, indent=2, sort_keys=True)
|
||||
#######################################################################################
|
||||
def close(self):
|
||||
self.sync()
|
||||
###########################################################################################
|
||||
class Redis:
|
||||
def __init__(self, uri=None, **kwargs):
|
||||
ConnectionPool = irc3.utils.maybedotted(
|
||||
'redis.connection.ConnectionPool')
|
||||
pool = ConnectionPool.from_url(uri)
|
||||
StrictRedis = irc3.utils.maybedotted('redis.client.StrictRedis')
|
||||
self.db = StrictRedis(connection_pool=pool)
|
||||
#######################################################################################
|
||||
def set(self, key, value):
|
||||
self.db.hmset(key, value)
|
||||
#######################################################################################
|
||||
def get(self, key):
|
||||
keys = self.db.hkeys(key)
|
||||
if not keys:
|
||||
raise KeyError()
|
||||
values = self.db.hmget(key, keys)
|
||||
keys = [k.decode('utf8') for k in keys]
|
||||
values = [v.decode('utf8') for v in values]
|
||||
values = dict(zip(keys, values))
|
||||
return values
|
||||
#######################################################################################
|
||||
def delete(self, key):
|
||||
self.db.delete(key)
|
||||
#######################################################################################
|
||||
def contains(self, key):
|
||||
return self.db.exists(key)
|
||||
#######################################################################################
|
||||
def flushdb(self):
|
||||
self.db.flushdb()
|
||||
#######################################################################################
|
||||
def sync(self):
|
||||
self.db.save()
|
||||
#######################################################################################
|
||||
def close(self):
|
||||
self.sync()
|
||||
###########################################################################################
|
||||
class SQLite:
|
||||
CREATE_TABLE = """
|
||||
CREATE TABLE IF NOT EXISTS
|
||||
irc3_storage (
|
||||
key text not null,
|
||||
value text default '',
|
||||
PRIMARY KEY (key)
|
||||
);
|
||||
"""
|
||||
UPSERT = """
|
||||
INSERT OR REPLACE INTO irc3_storage(key,value) VALUES(?, ?);
|
||||
"""
|
||||
#######################################################################################
|
||||
def __init__(self, uri=None, **kwargs):
|
||||
self.sqlite = irc3.utils.maybedotted('sqlite3')
|
||||
self.uri = uri.split('://')[-1]
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(self.CREATE_TABLE)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
#######################################################################################
|
||||
def set(self, key, value):
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(self.UPSERT, (key, json.dumps(value)))
|
||||
cursor.fetchall()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
#######################################################################################
|
||||
def get(self, key):
|
||||
value = None
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT value FROM irc3_storage where key=?;", (key,))
|
||||
for row in cursor.fetchall():
|
||||
value = json.loads(row[0])
|
||||
break
|
||||
cursor.close()
|
||||
conn.close()
|
||||
if value is None:
|
||||
raise KeyError(key)
|
||||
return value
|
||||
#######################################################################################
|
||||
def delete(self, key):
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DELETE FROM irc3_storage where key=?;", (key,))
|
||||
cursor.close()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
#######################################################################################
|
||||
def contains(self, key):
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT value FROM irc3_storage where key=?;", (key,))
|
||||
res = False
|
||||
if len(list(cursor.fetchall())) == 1:
|
||||
res = True
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return res
|
||||
#######################################################################################
|
||||
def flushdb(self):
|
||||
conn = self.sqlite.connect(self.uri)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("DROP TABLE IF EXISTS irc3_storage;")
|
||||
cursor.execute(self.CREATE_TABLE)
|
||||
cursor.close()
|
||||
conn.commit()
|
||||
conn.close()
|
||||
#######################################################################################
|
||||
def sync(self):
|
||||
pass
|
||||
#######################################################################################
|
||||
def close(self):
|
||||
pass
|
||||
###########################################################################################
|
||||
@irc3.plugin
|
||||
class Storage:
|
||||
backends = {
|
||||
'shelve': Shelve,
|
||||
'json': JSON,
|
||||
'unix': Redis,
|
||||
'redis': Redis,
|
||||
'rediss': Redis,
|
||||
'sqlite': SQLite,
|
||||
}
|
||||
#######################################################################################
|
||||
def __init__(self, context):
|
||||
uri = context.config.storage
|
||||
name = uri.split('://', 1)[0]
|
||||
try:
|
||||
factory = self.backends[name]
|
||||
except KeyError: # pragma: no cover
|
||||
raise LookupError('No such backend %s' % name)
|
||||
self.backend = factory(uri)
|
||||
self.context = context
|
||||
self.context.db = self
|
||||
#######################################################################################
|
||||
def setdefault(self, key_, **kwargs):
|
||||
"""Update storage value for key with kwargs iif the keys doesn't
|
||||
exist. Return stored values"""
|
||||
stored = self[key_]
|
||||
changed = False
|
||||
for k, v in kwargs.items():
|
||||
if k not in stored:
|
||||
stored[k] = v
|
||||
changed = True
|
||||
else:
|
||||
kwargs[k] = stored[k]
|
||||
if changed:
|
||||
self[key_] = stored
|
||||
return kwargs
|
||||
#######################################################################################
|
||||
def get(self, key_, default=None):
|
||||
"""Get storage value for key or return default"""
|
||||
if key_ not in self:
|
||||
return default
|
||||
else:
|
||||
return self[key_]
|
||||
#######################################################################################
|
||||
def getlist(self, key_, default=None):
|
||||
"""Get storage value (as list) for key or return default"""
|
||||
if key_ not in self:
|
||||
return default
|
||||
else:
|
||||
value = self[key_]
|
||||
value = [(int(i), v) for i, v in value.items()]
|
||||
return [v for k, v in sorted(value)]
|
||||
#######################################################################################
|
||||
def set(self, key_, **kwargs):
|
||||
"""Update storage value for key with kwargs"""
|
||||
stored = self.get(key_, dict())
|
||||
changed = False
|
||||
for k, v in kwargs.items():
|
||||
if k not in stored or stored[k] != v:
|
||||
stored[k] = v
|
||||
changed = True
|
||||
if changed:
|
||||
self[key_] = stored
|
||||
#######################################################################################
|
||||
def setlist(self, key_, value):
|
||||
"""Update storage value (as list)"""
|
||||
value = dict([(str(i), v) for i, v in enumerate(value)])
|
||||
if key_ in self:
|
||||
del self[key_]
|
||||
self.set(key_, **value)
|
||||
#######################################################################################
|
||||
def __setitem__(self, key, value):
|
||||
"""Set storage value for key"""
|
||||
key = getattr(key, '__module__', key)
|
||||
if not isinstance(value, dict): # pragma: no cover
|
||||
raise TypeError('value must be a dict')
|
||||
try:
|
||||
return self.backend.set(key, value)
|
||||
except Exception as e: # pragma: no cover
|
||||
self.context.log.exception(e)
|
||||
raise
|
||||
#######################################################################################
|
||||
def __getitem__(self, key):
|
||||
"""Get storage value for key"""
|
||||
key = getattr(key, '__module__', key)
|
||||
try:
|
||||
return self.backend.get(key)
|
||||
except KeyError:
|
||||
raise KeyError(key)
|
||||
except Exception as e: # pragma: no cover
|
||||
self.context.log.exception(e)
|
||||
raise
|
||||
#######################################################################################
|
||||
def __delitem__(self, key):
|
||||
"""Delete key in storage"""
|
||||
key = getattr(key, '__module__', key)
|
||||
try:
|
||||
self.backend.delete(key)
|
||||
except Exception as e: # pragma: no cover
|
||||
self.context.log.exception(e)
|
||||
raise
|
||||
#######################################################################################
|
||||
def __contains__(self, key):
|
||||
"""Return True if storage contains key"""
|
||||
key = getattr(key, '__module__', key)
|
||||
try:
|
||||
return self.backend.contains(key)
|
||||
except Exception as e: # pragma: no cover
|
||||
self.context.log.exception(e)
|
||||
raise
|
||||
#######################################################################################
|
||||
def SIGINT(self):
|
||||
self.backend.close()
|
||||
####################################################################################### EOF
|
@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
HYDRA="hydra_core__standalone"
|
||||
clear
|
||||
FAILED=0
|
||||
echo -e "[ setting up $HYDRA ]"
|
||||
which python3 > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then echo "python3 not installed, install like pacman -Sy python3, apt install python3, brew install python3"; FAILED=1; fi
|
||||
python3 -m pip > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then echo "python3 pip module not installed, attempting to auto-install"; wget https://bootstrap.pypa.io/get-pip.py; python3 get-pip.py; fi
|
||||
python3 -m pip > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then echo "python3 pip module still not installed, manually install python3 pip module before proceeding"; FAILED=1; fi
|
||||
which virtualenv > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then echo "python3 virtualenv module not installed, attempting to auto-install"; python3 -m pip install virtualenv; fi
|
||||
which virtualenv > /dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then echo "python3 virtualenv module still not installed, manually instlal python3 virtualenv module before proceeding"; FAILED=1; fi
|
||||
if [ $FAILED -eq 1 ]; then echo "pre-requisites not met, aborting installation"; exit 1; fi
|
||||
which python3.9 > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then virtualenv -p python3.9 env; else virtualenv python3 env; fi
|
||||
source env/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install irc3 ipdb
|
||||
echo -e "[ $HYDRA setup complete ]"
|
||||
deactivate
|
||||
echo "[ setting up $HYDRA activation ]"
|
||||
echo "echo '[ running $HYDRA ]'" > run.sh
|
||||
echo "source env/bin/activate" >> run.sh
|
||||
echo "irc3 maple.ini" >> run.sh
|
||||
echo "echo '[ $HYDRA bot finished ]'" >> run.sh
|
||||
echo "deactivate" >> run.sh
|
||||
echo "[ copying $HYDRA credentials ]"
|
||||
sudo cat /root/maple/activate__$HYDRA >> env/bin/activate
|
||||
if [ $? -eq 1 ]
|
||||
then
|
||||
echo "[ copying $HYDRA credentials failed, you will need to edit env/bin/activate manually ]"
|
||||
echo '#################################################### ACTIVATION ##### SOF' >> env/bin/activate
|
||||
echo 'export BOT_SASL_USERNAME=notmaple' >> env/bin/activate
|
||||
echo 'export BOT_SASL_PASSWORD=notpassword' >> env/bin/activate
|
||||
echo '#########################################################################' >> env/bin/activate
|
||||
echo 'export HYDRA_DESIGNATION=core' >> env/bin/activate
|
||||
echo 'export HYDRA_HOME="#b0ts3x"' >> env/bin/activate
|
||||
echo 'export HYDRA_PURPOSE="uptime and designating tasks"' >> env/bin/activate
|
||||
echo '#################################################### ACTIVATION ##### EOF' >> env/bin/activate
|
||||
fi
|
||||
echo "[ leaving setup and running $HYDRA ]"
|
||||
mv $0 env
|
||||
bash run.sh
|
@ -1,6 +0,0 @@
|
||||
echo '[ running hydra_core__standalone ]'
|
||||
[ -e env ] || bash setup_core__standalone.sh
|
||||
source env/bin/activate
|
||||
sh -c 'echo $$>hydra_core__standalone.pid; exec irc3 maple.ini'
|
||||
echo '[ hydra_core__standalone bot finished ]'
|
||||
deactivate
|
@ -1 +0,0 @@
|
||||
pid=`cat hydra_core__standalone.pid` && kill -9 $pid
|
Loading…
Reference in New Issue
Block a user