Есть множество статей как отправить почту из консоли терминала Linux. Но в основной своей массе, это всё касается уже настроенного почтового сервера. А если нужно отправить почту используя настройки SMTP с авторизацией, указанием кодировки и вложением в виде файла? Их есть у меня (с). Ниже пример:
Редко, но бывают ситуации, что под рукой только консоль терминала, а нужно скачать файл размещенный на яндек.диске (скачать с яндекс диска из консоли). Для решения такой ситуации есть утилита wldhx.yadisk-direct. Установим её:
pip3 install wldhx.yadisk-direct
После установки, закачка (скачать с яндекс диска из консоли) сводится к одной команде:
Итак, продолжаем продолжаем писать квест в консоли на языке Python. Первая часть описана здесь. В ней мы реализовали автоматическую загрузку и сохранение состояния прохождения квеста. Сейчас же займемся (начнем по крайне мере) отрисовкой локации, и реакцией на нажатые кнопки. В локации предусмотрим возможность отображения картинки из ASCII. Например json стартовой локации может выглядеть примерно так:
Создадим класс TLocation, при инициалиизации будем передавать в него инициализированный класс player. В переменной класса data — будем хранить загруженную локацию.
class TLocation:
data = {}
player={}
stdscr=curses.initscr()
scr_size=stdscr.getmaxyx()
def __init__(self,player):
self.player=player;
def load_location(self, location):
f = open("locations/" + str(location) + ".json", mode='r', encoding='utf-8')
self.data = json.load(f)
f.close()
Далее нарисуем верхнее меню, где сообщаем игроку, на какие локации он может перемещаться, и что он держит в руках:
def top_menu(self):
loc="Идти: "
if "left" in self.data["available_locations"]:
loc=loc+"влево(4) "
if "right" in self.data["available_locations"]:
loc=loc+"вправо(6) "
if "forward" in self.data["available_locations"]:
loc=loc+"вперед(8) "
if "back" in self.data["available_locations"]:
loc=loc+"назад(2) "
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
self.stdscr.addstr(1, 1, loc,curses.color_pair(1))
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
self.stdscr.addstr(1, 1, loc,curses.color_pair(1))
# что в руках
hands = "В руках: "
self.stdscr.addstr(2, 1, "")
for object in self.player.data["in_hands"]:
hands=hands+"["+object+"]"
if len(self.player.data["in_hands"])==0:
hands = hands+"ничего нет"
self.stdscr.addstr(2, 1, hands, curses.color_pair(1))
Ну и собственно основной код отрисовки локации, включающий бесконечный цикл ожидания нажатий клавиатуры. Предусматриваем переход на другую локацию, выход из игры и сохранение игры.
def location_view(self, location):
self.load_location(location)
self.stdscr.clear()
self.stdscr.border()
self.top_menu() # рисуем верхнее меню
# название локации
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
x = int((self.scr_size[1] - len(self.data["title"])) / 2)
self.stdscr.addstr(2, x, self.data["title"],curses.color_pair(2))
# рисуем рисунок ежели он есть
y=3
if "ascii_art" in self.data:
mass_art=self.data["ascii_art"].split("\n")
i=0
while i<len(mass_art):
x=int((self.scr_size[1]-len(mass_art[i]))/2)
self.stdscr.addstr(y+i, x, mass_art[i])
i+=1
y = y + len(mass_art);
# Выводим описательную часть
curses.init_pair(3, curses.COLOR_CYAN, curses.COLOR_BLACK)
self.stdscr.addstr(y, 1, self.data["description"],curses.color_pair(3))
# Выводим нижнее меню
curses.init_pair(4, curses.COLOR_RED, curses.COLOR_BLACK)
self.stdscr.addstr(y + 1, 1, "Осмотреться вокруг [v] Применить что в руках [h]", curses.color_pair(4))
self.stdscr.addstr(y + 2, 1, "Выйти из квеста [q] Сохранить состояние [r]", curses.color_pair(4))
self.stdscr.refresh()
while True:
key=self.stdscr.getch()
print(key)
# реализация перехода с локации на локацию
if key==52 and "left" in self.data["available_locations"]:
self.player.data["location"]=self.data["available_locations"]["left"]
self.location_view(self.player.data["location"])
if key==54 and "right" in self.data["available_locations"]:
self.player.data["location"]=self.data["available_locations"]["right"]
self.location_view(self.player.data["location"])
if key==56 and "forward" in self.data["available_locations"]:
self.player.data["location"]=self.data["available_locations"]["forward"]
self.location_view(self.player.data["location"])
if key==50 and "back" in self.data["available_locations"]:
self.player.data["location"]=self.data["available_locations"]["back"]
self.location_view(self.player.data["location"])
if key == 114:
self.player.save()
#self.message("Внимание!","Состояние прохождения завершено. \nФайл находится в папке /saves")
if key==113:
curses.reset_shell_mode()
curses.endwin()
exit(0)
print(self.data)
В результате картинка (квест в консоли) на мониторе выглядит уже чуть симпатичнее:
Довольно часто по работе приходится писать различного вида скрипты которые выполняются как в консоли, так и при вызове из браузера. Со временем сложился устойчивый стартовый шаблон консольного скрипта на PHP, который собственно и таскаю с сервера на сервер, когда начинаю что-то писать.
Можно конечно использовать для этого различные фреймворки, типа yii, которые предоставляют более удобный для этого функционал, но чаще всего для простых скриптов такого монстра тащить не рационально. Посему имеем то что имеем.
Что тут интересного? Сначала объявляем константу, куда ложим текущий физический путь до выполняемого скрипта. Далее загружаем все классы которые находятся в папке class (ака require_once vendor/autoload.php’ при использовании composer). Потом грузим файл config.php:
<?php
date_default_timezone_set('Europe/Moscow'); // Временная зона по умолчанию
if (isset($argv[0])){ // Тестовая
ini_set('display_errors', 1);
error_reporting(E_ALL);
define("log_file","dev.log");
} else { // БОЕВАЯ
define("log_file","work.log");
};
В котором прописываем логику определения разных констант в зависимости от переданного аргумента командной строки. Скрипт считает, что если аргумент есть — то значит версия скрипта «Для разработки».
В файле functions.php я добавил наиболее часто используемые мной функции:
PutLog — вывод лога в файл и дублирование в консоль, если скрипт запущен из командной строки
_GET — получение параметра $_GET, если отсутствует, возвращается пусто, или значение по умолчанию
_POST — получение параметра $_POST, если отсутствует, возвращается пусто, или значение по умолчанию
GetIpUser — попытаться получить IP пользователя вызвавшего выполнение скрипта
jsonExit — отдать на выход содержимое в формате json, установить заголовок json и выйти из программы
String2Boolean — преобразовать строку в тип boolean, Например на входе может быть строка «True» или число 1, на выходе будет именно Тип. Функция полезна при работе с JSON, где тип зачастую не определен однозначно.
Ну собственно и всё: этот шаблон консольного скрипта можно использовать на серверах как разместив его в cron, так и просто вызывая его через браузер.