А вот во что бы поконтрибьютить, например?
Хочу полапать жабку с микросервисами вне своего болотца и поглядеть, как оно у нормальных людей.
Лор не предлагать.
Хочу полапать жабку с микросервисами вне своего болотца и поглядеть, как оно у нормальных людей.
Лор не предлагать.
Пишу в Development, потому что это всё-таки не веб ни разу.
У меня есть пачка скриптов на питоне, каждый из которых вызывает цепочку внешних утилит и генерирует бинарный выходной файл. Время работы скрипта ~2-3 минуты, большую часть которого (99%) он проводит в ожидании завершения дочерних процессов.
Я хочу сделать из этих скриптов HTTP-сервер, т. е. вместо
python3 ./script1.py --foo=bar > output
писать
curl -fsSL http://localhost:8000/script1 -G -d foo=bar -o output
Я набросал прототип на http.server
, но мне не нравится, что приходится заниматься разбором URL и ещё много чего делать вручную. Плюс я бы хотел уметь обрабатывать несколько запросов одновременно. Да, я знаю про GIL, но поскольку большая часть работы происходит во внешних процессах, как минимум в теории GIL не должен мешать.
Так вот, как это сделать?
subprocess.run
/ subprocess.Popen
?Продублирую свой вопрос на форуме.
Так какие книги на данный момент самые лучшие для полного вката в программирование?
Речь идёт о ряде книг, которые следует изучать друг за другом и обязательно постоянно практиковаться, создавая реальные рабочие проекты (хоть и простые в начале, но точно сложнее калькуляторов).
От самых фундаментальных азов и машинных кодов до сверхвысокоуровневых языков с программированием из визуальных блоков и автоматического программирования при помощи нейронок и других автоматов-генераторов кода? Хочется понимать и то, как именно программируют автоматы.
Сомневаюсь, что остальных можно назвать омниполноценными профессиональными высококачественными специалистами программистами, если они не имеют всю эту фундаментальную базу.
manifest.json
{
"manifest_version": 3,
"name": "Proxy Settings Extension",
"version": "1.0",
"description": "Set proxy type, IP, and port for Chrome.",
"permissions": [
"proxy",
"storage"
],
"host_permissions": [
"http://*/*",
"https://*/*"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
}
}
background.js
chrome.runtime.onInstalled.addListener(() => {
// Инициализация значений по умолчанию для прокси
for (let i = 1; i <= 3; i++) {
chrome.storage.sync.get([`proxyType${i}`, `proxyIP${i}`, `proxyPort${i}`], (data) => {
if (!data[`proxyType${i}`]) {
chrome.storage.sync.set({
[`proxyType${i}`]: 'SOCKS5',
[`proxyIP${i}`]: '0.0.0.0',
[`proxyPort${i}`]: '1080'
});
}
});
}
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'get-proxy-status') {
chrome.proxy.settings.get({}, (config) => {
const proxyIsActive = config.value && config.value.mode === 'fixed_servers';
if (proxyIsActive) {
chrome.storage.sync.get(['activeProxyProfile'], (data) => {
const activeProfile = data.activeProxyProfile || 1;
sendResponse({ active: true, activeProfile });
});
} else {
sendResponse({ active: false });
}
});
return true;
}
if (message.action === 'apply-proxy') {
const profile = message.profile;
chrome.storage.sync.get([`proxyType${profile}`, `proxyIP${profile}`, `proxyPort${profile}`], (data) => {
const proxyType = data[`proxyType${profile}`] || 'SOCKS5';
const proxyIP = data[`proxyIP${profile}`] || '0.0.0.0';
const proxyPort = data[`proxyPort${profile}`] || '1080';
if (!isValidPort(proxyPort)) {
sendResponse({ success: false, error: 'Invalid proxy port number' });
return;
}
const config = {
mode: "fixed_servers",
rules: {
singleProxy: {
scheme: proxyType.toLowerCase(),
host: proxyIP,
port: parseInt(proxyPort, 10)
},
bypassList: []
}
};
chrome.proxy.settings.set({ value: config, scope: 'regular' }, () => {
if (chrome.runtime.lastError) {
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
chrome.storage.sync.set({ activeProxyProfile: profile }, () => {
sendResponse({ success: true });
});
}
});
});
return true;
}
if (message.action === 'disable-all-proxies') {
const config = { mode: "direct" };
chrome.proxy.settings.set({ value: config, scope: 'regular' }, () => {
if (chrome.runtime.lastError) {
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else {
chrome.storage.sync.remove('activeProxyProfile', () => {
sendResponse({ success: true });
});
}
});
return true;
}
});
function isValidPort(port) {
const parsedPort = parseInt(port, 10);
return !isNaN(parsedPort) && parsedPort > 0 && parsedPort <= 65535;
}
function isValidIP(ip) {
// Простейшая проверка на формат IP-адреса
const regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return regex.test(ip);
}
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proxy Settings</title>
<style>
body {
width: 600px;
padding: 20px;
font-family: Arial, sans-serif;
background: linear-gradient(to bottom, #F7F7F7, #ECECEC);
}
.header-container {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
h3 {
margin: 0;
font-size: 16px;
text-align: left;
margin-left: 20px;
color: #333;
}
#disable-proxy {
font-size: 12px;
padding: 5px 10px;
background-color: #e57373;
color: white;
border: none;
cursor: pointer;
border-radius: 5px;
display: inline-block;
opacity: 0.8;
}
#disable-proxy:hover {
opacity: 1;
background-color: #f44336;
}
#disable-proxy:disabled {
background-color: #ccc;
cursor: not-allowed;
opacity: 0.8;
}
label {
display: block;
margin-top: 10px;
font-weight: bold;
color: #555;
}
input, select {
width: 100%;
padding: 5px;
margin-top: 5px;
box-sizing: border-box;
border: 1px solid #ddd;
border-radius: 4px;
}
.profiles-container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
margin: 0;
padding: 0;
}
.profile {
flex: 1 1 170px;
border: 1px solid #ddd;
padding: 15px;
border-radius: 5px;
margin: 10px;
box-sizing: border-box;
max-width: 170px;
background-color: #fff;
}
.apply-proxy {
width: 100%;
margin-top: 20px;
margin-bottom: 10px;
padding: 10px;
background-color: #64b5f6;
color: white;
border: none;
cursor: pointer;
border-radius: 5px;
text-align: center;
opacity: 0.8;
}
.apply-proxy:hover {
background-color: #42a5f5;
opacity: 1;
}
.apply-proxy:disabled {
background-color: #ccc;
cursor: not-allowed;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="header-container">
<button id="disable-proxy" disabled>Disable Proxy</button>
<h3 id="proxy-status">Proxy OFF</h3>
</div>
<div class="profiles-container">
<div class="profile">
<label for="proxy-type-1">Proxy Type</label>
<select id="proxy-type-1">
<option value="SOCKS5">SOCKS5</option>
<option value="HTTP">HTTP</option>
<option value="HTTPS">HTTPS</option>
</select>
<label for="proxy-ip-1">Proxy IP</label>
<input type="text" id="proxy-ip-1" value="0.0.0.0">
<label for="proxy-port-1">Proxy Port</label>
<input type="number" id="proxy-port-1" value="1080">
<button class="apply-proxy" id="apply-proxy-1">Apply Proxy</button>
</div>
<div class="profile">
<label for="proxy-type-2">Proxy Type</label>
<select id="proxy-type-2">
<option value="SOCKS5">SOCKS5</option>
<option value="HTTP">HTTP</option>
<option value="HTTPS">HTTPS</option>
</select>
<label for="proxy-ip-2">Proxy IP</label>
<input type="text" id="proxy-ip-2" value="0.0.0.0">
<label for="proxy-port-2">Proxy Port</label>
<input type="number" id="proxy-port-2" value="1080">
<button class="apply-proxy" id="apply-proxy-2">Apply Proxy</button>
</div>
<div class="profile">
<label for="proxy-type-3">Proxy Type</label>
<select id="proxy-type-3">
<option value="SOCKS5">SOCKS5</option>
<option value="HTTP">HTTP</option>
<option value="HTTPS">HTTPS</option>
</select>
<label for="proxy-ip-3">Proxy IP</label>
<input type="text" id="proxy-ip-3" value="0.0.0.0">
<label for="proxy-port-3">Proxy Port</label>
<input type="number" id="proxy-port-3" value="1080">
<button class="apply-proxy" id="apply-proxy-3">Apply Proxy</button>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', () => {
chrome.runtime.sendMessage({ action: 'get-proxy-status' }, (response) => {
if (response && response.active) {
document.getElementById('proxy-status').textContent = `Proxy Active (Profile ${response.activeProfile})`;
document.getElementById('disable-proxy').disabled = false;
} else {
document.getElementById('proxy-status').textContent = 'Proxy OFF';
document.getElementById('disable-proxy').disabled = true;
}
// Загрузка сохраненных значений в поля ввода
for (let i = 1; i <= 3; i++) {
chrome.storage.sync.get([`proxyType${i}`, `proxyIP${i}`, `proxyPort${i}`], (data) => {
document.getElementById(`proxy-type-${i}`).value = data[`proxyType${i}`] || 'SOCKS5';
document.getElementById(`proxy-ip-${i}`).value = data[`proxyIP${i}`] || '0.0.0.0';
document.getElementById(`proxy-port-${i}`).value = data[`proxyPort${i}`] || '1080';
});
}
});
// Обработчик для кнопки "Применить прокси"
for (let i = 1; i <= 3; i++) {
const applyButton = document.getElementById(`apply-proxy-${i}`);
if (applyButton) {
applyButton.addEventListener('click', () => {
const proxyType = document.getElementById(`proxy-type-${i}`).value;
const proxyIP = document.getElementById(`proxy-ip-${i}`).value;
const proxyPort = document.getElementById(`proxy-port-${i}`).value;
if (!isValidPort(proxyPort)) {
alert('Invalid proxy port number');
return;
}
if (!isValidIP(proxyIP)) {
alert('Invalid proxy IP address');
return;
}
chrome.storage.sync.set({ [`proxyType${i}`]: proxyType, [`proxyIP${i}`]: proxyIP, [`proxyPort${i}`]: proxyPort }, () => {
chrome.runtime.sendMessage({ action: 'apply-proxy', profile: i }, (response) => {
if (response.success) {
document.getElementById('proxy-status').textContent = `Proxy Active (Profile ${i})`;
document.getElementById('disable-proxy').disabled = false;
} else {
alert(`Error applying proxy: ${response.error || 'Unknown error'}`);
}
});
});
});
} else {
console.error(`Button with id 'apply-proxy-${i}' not found.`);
}
}
// Обработчик для кнопки "Отключить прокси"
const disableProxyButton = document.getElementById('disable-proxy');
if (disableProxyButton) {
disableProxyButton.addEventListener('click', () => {
chrome.runtime.sendMessage({ action: 'disable-all-proxies' }, (response) => {
if (response.success) {
document.getElementById('proxy-status').textContent = 'Proxy OFF';
document.getElementById('disable-proxy').disabled = true;
} else {
alert(`Error disabling proxy: ${response.error || 'Unknown error'}`);
}
});
});
}
// Слушаем изменения в полях ввода, чтобы сохранять данные при вводе
for (let i = 1; i <= 3; i++) {
const proxyTypeElement = document.getElementById(`proxy-type-${i}`);
const proxyIPElement = document.getElementById(`proxy-ip-${i}`);
const proxyPortElement = document.getElementById(`proxy-port-${i}`);
if (proxyTypeElement) {
proxyTypeElement.addEventListener('input', () => {
saveProxyData(i);
});
}
if (proxyIPElement) {
proxyIPElement.addEventListener('input', () => {
saveProxyData(i);
});
}
if (proxyPortElement) {
proxyPortElement.addEventListener('input', () => {
saveProxyData(i);
});
}
}
});
// Функция для сохранения данных в chrome.storage
function saveProxyData(profileIndex) {
const proxyType = document.getElementById(`proxy-type-${profileIndex}`).value;
const proxyIP = document.getElementById(`proxy-ip-${profileIndex}`).value;
const proxyPort = document.getElementById(`proxy-port-${profileIndex}`).value;
chrome.storage.sync.set({
[`proxyType${profileIndex}`]: proxyType,
[`proxyIP${profileIndex}`]: proxyIP,
[`proxyPort${profileIndex}`]: proxyPort
});
}
// Проверка на корректность IP адреса
function isValidIP(ip) {
const regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return regex.test(ip);
}
// Проверка на корректность порта
function isValidPort(port) {
const portNumber = parseInt(port, 10);
return portNumber >= 1 && portNumber <= 65535;
}
Мне понадобился Hexchat. Как-то привык к нему. Но в новых дистрах он требует старый gtk+2. Решил на отдельном диске завести ещё один дистрибутив, но без установки.
Для примера был взят дистрибутив Calculate Linux 2024 года.
mount /dev/sda8/ /mnt/d1
И копируем файлы с Live ISO Linux на этот отдельный раздел (допустим ext4), с опцией -a
cp -a /bin /mnt/d1
и т.д.
(/mnt /media лучше создать вручную, дабы избежать рекурсии :) run, proc, sys копировать не надо, но можно создать эти директории)
Загружаемся в основную систему.
Ставим на хост:
emerge x11-apps/xhost
Выполняем на хосте:
export DISPLAY=:0
xhost +local:
(Может, придется поставить права на диск вроде chmod 777 /dev/sdaХ (но 777 я, конечно, круто взял :) первое что пришло в голову в качестве примера. Решайте сами, какие права нужны вам))
mount /dev/sda8 /mnt/d1
mount --rbind /dev /mnt/d1/dev
mount --make-rslave /mnt/d1/dev
mount -t proc /proc /mnt/d1/proc
mount --rbind /sys /mnt/d1/sys
mount --make-rslave /mnt/d1/sys
mount --rbind /tmp /mnt/d1/tmp
mount --bind /run /mnt/d1/run
chroot /mnt/d1 /bin/bash
. /etc/profile
export PS1="(chroot) $PS1"
(Можно продублировать в chroot, если что-то лишнее накрутили, как у меня это было:
export DISPLAY=:0
)
su guest
hexchat
С Новым Годом!
Я решил углубиться в эту тему. Интересуют не конкретные библиотеки, а алгоритмы в целом, общие подходы к обработке изображений. Сходу информацию, с чего стоит начать, я не нашёл, поэтому решил попробовать обратиться на ЛОР.