auth key
parent
19844be327
commit
8027dc3716
|
@ -0,0 +1 @@
|
|||
Subproject commit a6418dc619af7cef6a1d2573bd32c9f4dc9d7006
|
|
@ -1,16 +1,48 @@
|
|||
version: '2.4'
|
||||
version: "2.4"
|
||||
|
||||
services:
|
||||
octoprint_server_test2:
|
||||
container_name: octoprint-server-test2
|
||||
octoprint_server_a1_first:
|
||||
container_name: octoprint-server-a1_first
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 127.0.0.1:50138:80
|
||||
- 10.8.0.1:50139:80
|
||||
extra_hosts:
|
||||
- "ovpn_gateway:10.8.0.1"
|
||||
volumes:
|
||||
- octoprint-server-test2:/octoprint
|
||||
- octoprint-server-a1_first:/octoprint
|
||||
bambu-go2rtc_a1_first:
|
||||
container_name: bambu-go2rtc-a1_first
|
||||
image: "docker.io/alexxit/go2rtc"
|
||||
restart: "unless-stopped"
|
||||
# These are the configuration options if a
|
||||
# traefik setup is in place.
|
||||
#labels:
|
||||
# - "traefik.enable=true"
|
||||
# - "traefik.http.routers.bambu-go2rtc.rule=Host(`bambu-webcam.example.com`)"
|
||||
# - "traefik.http.routers.bambu-go2rtc.entrypoints=websecure"
|
||||
# - "traefik.http.routers.bambu-go2rtc.tls=true"
|
||||
# - "traefik.http.services.bambu-go2rtc.loadbalancer.server.port=1984"
|
||||
# # This is enabling automatic LE certificate generation
|
||||
# - "traefik.http.routers.bambu-go2rtc.tls.certresolver=leresolver"
|
||||
# - "traefik.http.routers.bambu-go2rtc.tls.domains[0].main=bambu-webcam.example.com"
|
||||
# # To enable basic auth uncomment and generate approprioate password using htpasswd
|
||||
# #- "traefik.http.routers.bambu-go2rtc.middlewares=auth-$COMPOSE_PROJECT_NAME"
|
||||
# #- "traefik.http.middlewares.auth-bambu-go2rtc.basicauth.users=bambu:$$HTPASSWD_FORMAT_PASSWORD"
|
||||
ports:
|
||||
- 10.8.0.1:50140:1984
|
||||
environment:
|
||||
# Remember these values are defaults that can
|
||||
# be overriden by a .env file. Putting sensitive
|
||||
# data in a docker-compose.yml is less secure.
|
||||
# See env-example for the exact format.
|
||||
PRINTER_ADDRESS: "192.168.188.32"
|
||||
PRINTER_ACCESS_CODE: "24008302"
|
||||
volumes:
|
||||
- "/home/octoprint/bambu-go2rtc/go2rtc.yaml:/config/go2rtc.yaml"
|
||||
- "/home/octoprint/bambu-go2rtc/camera-stream.py:/config/camera-stream.py"
|
||||
|
||||
volumes:
|
||||
octoprint-server-test2:
|
||||
octoprint-server-a1_first:
|
||||
|
|
|
@ -3,8 +3,8 @@ accessControl:
|
|||
api:
|
||||
key: 91EEB0475E5844059C3CBC0C18E37B63
|
||||
appearance:
|
||||
color: white
|
||||
name: My Template
|
||||
color: blue
|
||||
name: My_Template
|
||||
plugins:
|
||||
announcements:
|
||||
_config_version: 1
|
||||
|
@ -19,21 +19,30 @@ plugins:
|
|||
read_until: 1714176000
|
||||
_releases:
|
||||
read_until: 1713957300
|
||||
enabled_channels:
|
||||
- _important
|
||||
- _releases
|
||||
bambu_printer:
|
||||
access_code: '1234'
|
||||
device_type: P1P
|
||||
device_type: A1
|
||||
flow_cali: true
|
||||
host: 127.0.0.1
|
||||
serial: '1234'
|
||||
use_ams: true
|
||||
classicwebcam:
|
||||
_config_version: 1
|
||||
snapshot: http://localhost:8080/?action=snapshot
|
||||
stream: /webcam/?action=stream
|
||||
snapshot: http://10.8.0.1:50140/api/frame.jpeg?src=bambu_camera
|
||||
stream: http://10.8.0.1:50140/api/stream.mjpeg?src=bambu_camera
|
||||
discovery:
|
||||
upnpUuid: f208a345-7fab-4b7b-8922-a12766395145
|
||||
errortracking:
|
||||
unique_id: 2074483d-5218-452c-992f-07225b0f7efd
|
||||
gcodeviewer:
|
||||
_config_version: 1
|
||||
obico:
|
||||
auth_token: 3dc3c1cb9aa0858a32d5
|
||||
endpoint_prefix: https://obico.ex.umbach.dev
|
||||
sentry_opt: asked
|
||||
softwareupdate:
|
||||
_config_version: 9
|
||||
tracking:
|
||||
|
@ -45,6 +54,7 @@ printerProfiles:
|
|||
default: _default
|
||||
serial:
|
||||
autoconnect: true
|
||||
port: BAMBU
|
||||
server:
|
||||
commands:
|
||||
serverRestartCommand: s6-svc -r /var/run/s6/services/octoprint
|
||||
|
@ -72,3 +82,4 @@ temperature:
|
|||
name: PLA
|
||||
webcam:
|
||||
ffmpeg: /usr/bin/ffmpeg
|
||||
timelapseEnabled: false
|
||||
|
|
|
@ -4,7 +4,7 @@ api:
|
|||
key: 91EEB0475E5844059C3CBC0C18E37B63
|
||||
appearance:
|
||||
color: white
|
||||
name: My A2
|
||||
name: A1 First
|
||||
plugins:
|
||||
announcements:
|
||||
_config_version: 1
|
||||
|
@ -19,21 +19,30 @@ plugins:
|
|||
read_until: 1714176000
|
||||
_releases:
|
||||
read_until: 1713957300
|
||||
enabled_channels:
|
||||
- _important
|
||||
- _releases
|
||||
bambu_printer:
|
||||
access_code: '1234'
|
||||
device_type: P1P
|
||||
host: 127.0.0.1
|
||||
serial: '1234'
|
||||
access_code: '24008302'
|
||||
device_type: A1
|
||||
flow_cali: true
|
||||
host: 192.168.188.32
|
||||
serial: 03919C431403345
|
||||
use_ams: true
|
||||
classicwebcam:
|
||||
_config_version: 1
|
||||
snapshot: http://localhost:8080/?action=snapshot
|
||||
stream: /webcam/?action=stream
|
||||
snapshot: http://10.8.0.1:50140/api/frame.jpeg?src=bambu_camera
|
||||
stream: http://10.8.0.1:50140/api/stream.mjpeg?src=bambu_camera
|
||||
discovery:
|
||||
upnpUuid: f208a345-7fab-4b7b-8922-a12766395145
|
||||
errortracking:
|
||||
unique_id: 2074483d-5218-452c-992f-07225b0f7efd
|
||||
gcodeviewer:
|
||||
_config_version: 1
|
||||
obico:
|
||||
auth_token: 1be7f2f022ddbe6f230d
|
||||
endpoint_prefix: https://obico.ex.umbach.dev
|
||||
sentry_opt: asked
|
||||
softwareupdate:
|
||||
_config_version: 9
|
||||
tracking:
|
||||
|
@ -45,6 +54,7 @@ printerProfiles:
|
|||
default: _default
|
||||
serial:
|
||||
autoconnect: true
|
||||
port: BAMBU
|
||||
server:
|
||||
commands:
|
||||
serverRestartCommand: s6-svc -r /var/run/s6/services/octoprint
|
||||
|
@ -72,3 +82,4 @@ temperature:
|
|||
name: PLA
|
||||
webcam:
|
||||
ffmpeg: /usr/bin/ffmpeg
|
||||
timelapseEnabled: false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"last_version": "1.10.0",
|
||||
"seen_versions": 1,
|
||||
"server_starts": 8,
|
||||
"server_starts": 10,
|
||||
"prints_started": 0,
|
||||
"prints_cancelled": 0,
|
||||
"prints_errored": 0,
|
||||
|
@ -15,8 +15,8 @@
|
|||
"longest_print_date": 0,
|
||||
"files_uploaded": 0,
|
||||
"files_deleted": 0,
|
||||
"plugins_installed": 0,
|
||||
"plugins_installed": 1,
|
||||
"plugins_uninstalled": 0,
|
||||
"most_plugins": 20,
|
||||
"achievements": 1
|
||||
"most_plugins": 21,
|
||||
"achievements": 2
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"stats": {
|
||||
"last_version": "1.10.0",
|
||||
"seen_versions": 1,
|
||||
"server_starts": 8,
|
||||
"server_starts": 10,
|
||||
"prints_started": 0,
|
||||
"prints_cancelled": 0,
|
||||
"prints_errored": 0,
|
||||
|
@ -16,14 +16,15 @@
|
|||
"longest_print_date": 0,
|
||||
"files_uploaded": 0,
|
||||
"files_deleted": 0,
|
||||
"plugins_installed": 0,
|
||||
"plugins_installed": 1,
|
||||
"plugins_uninstalled": 0,
|
||||
"most_plugins": 20,
|
||||
"most_plugins": 21,
|
||||
"created": 1715245186,
|
||||
"created_version": "1.10.0"
|
||||
},
|
||||
"achievements": {
|
||||
"the_wizard": 1715245188
|
||||
"the_wizard": 1715245188,
|
||||
"adventurer": 1715359212
|
||||
},
|
||||
"state": {
|
||||
"date_last_print": "",
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,11 @@
|
|||
/:
|
||||
- _count: 32
|
||||
_timestamp: 1715285965.6765628
|
||||
- _count: 37
|
||||
_timestamp: 1715373060.9737663
|
||||
base_url: http://localhost:50136/
|
||||
path: /
|
||||
query_string: l10n=en
|
||||
- _count: 4
|
||||
_timestamp: 1715360862.799835
|
||||
base_url: http://localhost:50136/
|
||||
path: /
|
||||
query_string: l10n=de
|
||||
|
|
|
@ -16,7 +16,7 @@ bambu_printer:
|
|||
value: 0.0.18
|
||||
online: true
|
||||
possible: true
|
||||
timestamp: 1715253505.066055
|
||||
timestamp: 1715354113.0579495
|
||||
file_check:
|
||||
available: false
|
||||
compatible: true
|
||||
|
@ -34,7 +34,7 @@ file_check:
|
|||
value: 2024.3.27
|
||||
online: true
|
||||
possible: true
|
||||
timestamp: 1715245191.0575087
|
||||
timestamp: 1715354113.0563233
|
||||
firmware_check:
|
||||
available: false
|
||||
compatible: true
|
||||
|
@ -52,7 +52,25 @@ firmware_check:
|
|||
value: 2021.10.11
|
||||
online: true
|
||||
possible: true
|
||||
timestamp: 1715245191.0564404
|
||||
timestamp: 1715354113.057019
|
||||
obico:
|
||||
available: false
|
||||
compatible: true
|
||||
disabled: false
|
||||
error: null
|
||||
hash: 7cb104e955bb5d69eaeadc01fa989884
|
||||
information:
|
||||
local:
|
||||
name: 2.4.13
|
||||
value: 2.4.13
|
||||
needs_online: true
|
||||
remote:
|
||||
name: Fix the compatibility issues in OctoPrint 1.10.0
|
||||
release_notes: https://github.com/TheSpaghettiDetective/OctoPrint-Obico/releases/tag/2.4.13
|
||||
value: 2.4.13
|
||||
online: true
|
||||
possible: true
|
||||
timestamp: 1715359540.366526
|
||||
octoprint:
|
||||
available: false
|
||||
compatible: true
|
||||
|
@ -70,4 +88,4 @@ octoprint:
|
|||
value: 1.10.0
|
||||
online: true
|
||||
possible: true
|
||||
timestamp: 1715245191.0577404
|
||||
timestamp: 1715354113.0573716
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -102,3 +102,687 @@
|
|||
${exc.stack || exc}`);
|
||||
}
|
||||
})();
|
||||
|
||||
// JS assets for plugin obico
|
||||
(function () {
|
||||
try {
|
||||
// source: plugin/obico/js/ObicoSettings.js
|
||||
/*
|
||||
* View model for Obico Settings
|
||||
*
|
||||
* Author: The Obico team
|
||||
* License: AGPLv3
|
||||
*/
|
||||
$(function () {
|
||||
|
||||
$(function() {
|
||||
$('.obico-collapsable__title').click(function() {
|
||||
$(this).parent().toggleClass('opened');
|
||||
})
|
||||
});
|
||||
|
||||
function ObicoSettingsViewModel(parameters) {
|
||||
var self = this;
|
||||
|
||||
const defaultServerAddress = 'https://app.obico.io';
|
||||
function getServerType(serverAddress) {
|
||||
return serverAddress == defaultServerAddress ? 'cloud' : 'self-hosted';
|
||||
}
|
||||
|
||||
// assign the injected parameters, e.g.:
|
||||
// self.loginStateViewModel = parameters[0];
|
||||
self.obicoWizardViewModel = parameters[0];
|
||||
self.settingsViewModel = parameters[1];
|
||||
self.wizardViewModel = parameters[2];
|
||||
|
||||
self.alertsShown = {};
|
||||
self.piCamResolutionOptions = [{ id: "low", text: "Low" }, { id: "medium", text: "Medium" }, { id: "high", text: "High" }, { id: "ultra_high", text: "Ultra High" }];
|
||||
self.isWizardShown = ko.observable(
|
||||
retrieveFromLocalStorage('disableTSDWizardAutoPopupUntil', 0) > new Date().getTime()
|
||||
);
|
||||
self.showDetailPage = ko.observable(false);
|
||||
self.serverStatus = ko.mapping.fromJS({ is_connected: false, status_posted_to_server_ts: 0, bailed_because_tsd_plugin_running: false });
|
||||
self.streaming = ko.mapping.fromJS({ is_pi_camera: false, webrtc_streaming: false, compat_streaming: false});
|
||||
self.linkedPrinter = ko.mapping.fromJS({ is_pro: false, id: null, name: null});
|
||||
self.errorStats = ko.mapping.fromJS({ server: { attempts: 0, error_count: 0, first: null, last: null }, webcam: { attempts: 0, error_count: 0, first: null, last: null }});
|
||||
self.serverTestStatusCode = ko.observable(null);
|
||||
self.serverTested = ko.observable('never');
|
||||
self.sentryOptedIn = ko.pureComputed(function () {
|
||||
return self.settingsViewModel.settings.plugins.obico.sentry_opt() === "in";
|
||||
}, self);
|
||||
self.configured = ko.pureComputed(function () {
|
||||
return self.settingsViewModel.settings.plugins.obico.auth_token
|
||||
&& self.settingsViewModel.settings.plugins.obico.auth_token();
|
||||
}, self);
|
||||
self.wizardAutoPoppedup = ko.observable(false);
|
||||
self.disableWizardAutoPopUp = ko.observable(false);
|
||||
self.serverType = ko.observable('cloud');
|
||||
self.hasTsdMigratedModalShown = ko.observable(false);
|
||||
|
||||
self.onStartupComplete = function (plugin, data) {
|
||||
self.fetchPluginStatus();
|
||||
self.serverType(getServerType(self.settingsViewModel.settings.plugins.obico.endpoint_prefix()));
|
||||
};
|
||||
|
||||
self.onSettingsBeforeSave = function() {
|
||||
self.serverType(getServerType(self.settingsViewModel.settings.plugins.obico.endpoint_prefix()));
|
||||
}
|
||||
|
||||
self.hasServerErrors = function() {
|
||||
return self.errorStats.server.error_count() > 0;
|
||||
};
|
||||
|
||||
self.hasWebcamErrors = function() {
|
||||
return self.errorStats.webcam.error_count() > 0;
|
||||
};
|
||||
|
||||
self.serverErrorRate = function() {
|
||||
return Math.round(self.errorStats.server.error_count() / self.errorStats.server.attempts() * 100);
|
||||
};
|
||||
|
||||
self.webcamErrorRate = function() {
|
||||
return Math.round(self.errorStats.webcam.error_count() / self.errorStats.webcam.attempts() * 100);
|
||||
};
|
||||
|
||||
self.serverTestSucceeded = function() {
|
||||
return self.serverTestStatusCode() == 200;
|
||||
};
|
||||
|
||||
self.serverTestUnknownError = function() {
|
||||
return self.serverTestStatusCode() != null && self.serverTestStatusCode() != 401 && self.serverTestStatusCode() != 200;
|
||||
};
|
||||
|
||||
self.fetchPluginStatus = function() {
|
||||
apiCommand({
|
||||
command: "get_plugin_status",
|
||||
})
|
||||
.done(function (data) {
|
||||
ko.mapping.fromJS(data.server_status, self.serverStatus);
|
||||
ko.mapping.fromJS(data.streaming_status, self.streaming);
|
||||
ko.mapping.fromJS(data.error_stats, self.errorStats);
|
||||
ko.mapping.fromJS(data.linked_printer, self.linkedPrinter);
|
||||
|
||||
_.get(data, 'alerts', []).forEach(function (alertMsg) {
|
||||
self.displayAlert(alertMsg);
|
||||
})
|
||||
|
||||
if (self.settingsViewModel.settings.plugins.obico.tsd_migrated
|
||||
&& self.settingsViewModel.settings.plugins.obico.tsd_migrated() == 'yes'
|
||||
&& !self.hasTsdMigratedModalShown()) {
|
||||
self.showTsdMigratedModal();
|
||||
self.hasTsdMigratedModalShown(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.configured() && !self.isWizardShown() && !self.wizardViewModel.isDialogActive()) {
|
||||
self.showWizardModal();
|
||||
self.isWizardShown(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_.get(data, 'sentry_opt') === "out") {
|
||||
var sentrynotice = new PNotify({
|
||||
title: "Obico",
|
||||
text: "<p>Turn on bug reporting to help us make Obico plugin better?</p><p>The debugging info included in the report will be anonymized.</p>",
|
||||
hide: false,
|
||||
destroy: true,
|
||||
confirm: {
|
||||
confirm: true,
|
||||
},
|
||||
});
|
||||
sentrynotice.get().on('pnotify.confirm', function () {
|
||||
self.toggleSentryOpt();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.testServerConnection = function() {
|
||||
self.serverTested('testing');
|
||||
apiCommand({
|
||||
command: "test_server_connection",
|
||||
})
|
||||
.done(function (data) {
|
||||
self.serverTested('tested');
|
||||
self.serverTestStatusCode(data.status_code);
|
||||
});
|
||||
};
|
||||
|
||||
self.toggleSentryOpt = function (ev) {
|
||||
apiCommand({
|
||||
command: "toggle_sentry_opt",
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
self.resetEndpointPrefix = function () {
|
||||
self.settingsViewModel.settings.plugins.obico.endpoint_prefix(defaultServerAddress);
|
||||
return true;
|
||||
};
|
||||
|
||||
self.clearEndpointPrefix = function () {
|
||||
self.settingsViewModel.settings.plugins.obico.endpoint_prefix('');
|
||||
return true;
|
||||
};
|
||||
|
||||
self.selectPage = function(page) {
|
||||
self.showDetailPage(true);
|
||||
|
||||
switch (page) {
|
||||
case 'troubleshooting':
|
||||
$('li[data-page="advanced"]').removeClass('active');
|
||||
$('#obico-advanced').removeClass('active');
|
||||
$('li[data-page="troubleshooting"]').addClass('active');
|
||||
$('#obico-troubleshooting').addClass('active');
|
||||
break;
|
||||
case 'advanced':
|
||||
$('li[data-page="troubleshooting"]').removeClass('active');
|
||||
$('#obico-troubleshooting').removeClass('active');
|
||||
$('li[data-page="advanced"]').addClass('active');
|
||||
$('#obico-advanced').addClass('active');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
self.returnToSelection = function() {
|
||||
self.showDetailPage(false);
|
||||
}
|
||||
|
||||
/*** Plugin error alerts */
|
||||
|
||||
self.onDataUpdaterPluginMessage = function (plugin, data) {
|
||||
if (plugin != "obico") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.plugin_updated) {
|
||||
self.fetchPluginStatus();
|
||||
}
|
||||
|
||||
if (data.printer_autolinked) {
|
||||
self.fetchPluginStatus();
|
||||
self.obicoWizardViewModel.toStep(5);
|
||||
self.obicoWizardViewModel.startAutoCloseTimout();
|
||||
}
|
||||
}
|
||||
|
||||
self.displayAlert = function (alertMsg) {
|
||||
|
||||
var AVAILABLE_BUTTONS = {
|
||||
more_info: {
|
||||
text: "More Info",
|
||||
click: function (notice) {
|
||||
window.open(alertMsg.info_url, '_blank');
|
||||
notice.remove();
|
||||
},
|
||||
},
|
||||
never: {
|
||||
text: "Never Show Again",
|
||||
click: function (notice) {
|
||||
saveToLocalStorage(ignoredItemPath, true);
|
||||
notice.remove();
|
||||
},
|
||||
addClass: "never_button"
|
||||
},
|
||||
ok: {
|
||||
text: "OK",
|
||||
click: function (notice) {
|
||||
notice.remove();
|
||||
},
|
||||
addClass: "ok_button"
|
||||
},
|
||||
close: {
|
||||
text: "Close",
|
||||
addClass: "remove_button"
|
||||
},
|
||||
diagnose: {
|
||||
text: "Details",
|
||||
click: function (notice) {
|
||||
self.showDiagnosticReportModal();
|
||||
notice.remove();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
var ignoredItemPath = "ignored." + alertMsg.cause + "." + alertMsg.level;
|
||||
if (retrieveFromLocalStorage(ignoredItemPath, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var showItemPath = alertMsg.cause + "." + alertMsg.level;
|
||||
if (_.get(self.alertsShown, showItemPath, false)) {
|
||||
return;
|
||||
}
|
||||
_.set(self.alertsShown, showItemPath, true);
|
||||
|
||||
var msgType = "error";
|
||||
if (alertMsg.level === "warning") {
|
||||
msgType = "notice";
|
||||
}
|
||||
|
||||
var buttons = _.map(alertMsg.buttons, function(k) {
|
||||
return AVAILABLE_BUTTONS[k];
|
||||
});
|
||||
|
||||
hiddenButtons = [];
|
||||
|
||||
// PNotify needs this dance to hide the default "Ok" and "Cancel" button
|
||||
['ok', 'close'].forEach(function(k) {
|
||||
if (!_.includes(alertMsg.buttons, k)) {
|
||||
buttons.push(AVAILABLE_BUTTONS[k]);
|
||||
hiddenButtons.push(AVAILABLE_BUTTONS[k].addClass);
|
||||
}
|
||||
})
|
||||
|
||||
if (alertMsg.text) {
|
||||
new PNotify({
|
||||
title: "Obico",
|
||||
text: alertMsg.text,
|
||||
type: msgType,
|
||||
hide: false,
|
||||
confirm: {
|
||||
confirm: true,
|
||||
buttons: buttons,
|
||||
},
|
||||
history: {
|
||||
history: false
|
||||
},
|
||||
before_open: function (notice) {
|
||||
hiddenButtons.forEach(function(className) {
|
||||
notice
|
||||
.get()
|
||||
.find("." + className)
|
||||
.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self.showDiagnosticReportModal = function () {
|
||||
$('#diagnosticReportModal').modal();
|
||||
};
|
||||
|
||||
self.showWizardModal = function (maybeViewModel) {
|
||||
self.wizardAutoPoppedup(!Boolean(maybeViewModel)); // When it's triggered by user click, maybeViewModel is not undefined
|
||||
$('#wizardModal').modal({backdrop: 'static', keyboard: false});
|
||||
};
|
||||
|
||||
$('#wizardModal').on('shown', function(){
|
||||
self.obicoWizardViewModel.reset();
|
||||
});
|
||||
$('#wizardModal').on('hidden', function(){
|
||||
if (self.disableWizardAutoPopUp()) {
|
||||
saveToLocalStorage('disableTSDWizardAutoPopupUntil', (new Date()).getTime() + 1000*60*60*24*30); // Not show for 30 days
|
||||
}
|
||||
});
|
||||
|
||||
self.showTsdMigratedModal = function (maybeViewModel) {
|
||||
$('#tsdMigratedModal').modal();
|
||||
};
|
||||
self.hideTsdMigratedModal = function() {
|
||||
$('#tsdMigratedModal').modal('hide');
|
||||
self.settingsViewModel.saveData({plugins: {obico: {tsd_migrated: 'confirmed'}}});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Helper methods
|
||||
function apiCommand(data) {
|
||||
return $.ajax("api/plugin/obico", {
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
var LOCAL_STORAGE_KEY = 'plugin.obico';
|
||||
|
||||
function localStorageObject() {
|
||||
var retrievedObject = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (!retrievedObject) {
|
||||
retrievedObject = '{}';
|
||||
}
|
||||
return JSON.parse(retrievedObject);
|
||||
}
|
||||
|
||||
function retrieveFromLocalStorage(itemPath, defaultValue) {
|
||||
return _.get(localStorageObject(), itemPath, defaultValue);
|
||||
}
|
||||
|
||||
function saveToLocalStorage(itemPath, value) {
|
||||
var retrievedObject = localStorageObject();
|
||||
_.set(retrievedObject, itemPath, value);
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(retrievedObject));
|
||||
}
|
||||
|
||||
|
||||
/* view model class, parameters for constructor, container to bind to
|
||||
* Please see http://docs.octoprint.org/en/master/plugins/viewmodels.html#registering-custom-viewmodels for more details
|
||||
* and a full list of the available options.
|
||||
*/
|
||||
OCTOPRINT_VIEWMODELS.push({
|
||||
construct: ObicoSettingsViewModel,
|
||||
// ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ...
|
||||
dependencies: ["obicoWizardViewModel", "settingsViewModel", "wizardViewModel"],
|
||||
// Elements to bind to, e.g. #settings_plugin_obico, #tab_plugin_obico, ...
|
||||
elements: [
|
||||
"#settings_plugin_obico",
|
||||
]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
;
|
||||
|
||||
// source: plugin/obico/js/ObicoWizard.js
|
||||
/*
|
||||
* View model for Obico Wizard
|
||||
*
|
||||
* Author: The Obico team
|
||||
* License: AGPLv3
|
||||
*/
|
||||
$(function () {
|
||||
|
||||
function apiCommand(data) {
|
||||
return $.ajax("api/plugin/obico", {
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
function ObicoWizardViewModel(parameters) {
|
||||
var self = this;
|
||||
|
||||
const defaultServerAddress = 'https://app.obico.io';
|
||||
function getServerType(serverAddress) {
|
||||
return serverAddress == defaultServerAddress ? 'cloud' : 'self-hosted';
|
||||
}
|
||||
|
||||
// assign the injected parameters, e.g.:
|
||||
// self.loginStateViewModel = parameters[0];
|
||||
self.settingsViewModel = parameters[0];
|
||||
|
||||
self.step = ko.observable(1);
|
||||
self.mobileFlow = ko.observable(true);
|
||||
self.securityCode = ko.observable('');
|
||||
self.verifying = ko.observable(false);
|
||||
self.userAgreementChecked = ko.observable(true);
|
||||
self.printerName = ko.observable('');
|
||||
self.printerNameTimeoutId = ko.observable(null);
|
||||
self.currentFeatureSlide = ko.observable(1);
|
||||
|
||||
self.serverType = ko.observable('cloud');
|
||||
|
||||
self.onStartupComplete = function () {
|
||||
self.reset();
|
||||
};
|
||||
|
||||
self.isServerInvalid = ko.observable(false);
|
||||
|
||||
self.checkSeverValidity = (url) => {
|
||||
return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/.test(url);
|
||||
}
|
||||
|
||||
// Handle verification code typing:
|
||||
|
||||
$.find('.obico-verification-code-input input').forEach(function(input) {
|
||||
// Add event listener for paste event
|
||||
$(input).on('paste', handlePaste);
|
||||
|
||||
// Handle typing in verification code to automatically move cursor back/forward
|
||||
$(input).on('keydown', handleKeydown);
|
||||
});
|
||||
|
||||
// Paste verification code digit by digit
|
||||
function handlePaste(event) {
|
||||
let text = (event.originalEvent.clipboardData || window.clipboardData).getData('text');
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
let char = text[i];
|
||||
appendToVerificationCode(char);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// Move cursor back/forward
|
||||
function handleKeydown(event) {
|
||||
|
||||
// Skip Paste event
|
||||
if (event.key === 'Meta' || event.key === 'Control' || event.originalEvent.code === 'KeyV') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === 'Backspace') {
|
||||
for (let i = 6; i >= 1; i--) {
|
||||
let input = $('.obico-verification-code-input input[data-number='+ i +']');
|
||||
if (input.val()) {
|
||||
input.val('').trigger('focus');
|
||||
self.securityCode(self.securityCode().slice(0, -1));
|
||||
clearVerificationCodeMessages();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appendToVerificationCode(event.key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append digit to verification code
|
||||
function appendToVerificationCode(char) {
|
||||
let availableInputs = ['0','1','2','3','4','5','6','7','8','9'];
|
||||
|
||||
if (!availableInputs.includes(char)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= 6; i++) {
|
||||
let input = $('.obico-verification-code-input input[data-number='+ i +']');
|
||||
|
||||
if (!input.val()) {
|
||||
// Put value to input visible to user
|
||||
input.val(char);
|
||||
|
||||
// Move cursor forward
|
||||
if (i < 6) {
|
||||
$('.obico-verification-code-input input[data-number='+ (i + 1) +']').trigger('focus');
|
||||
}
|
||||
|
||||
// Append char to inner code
|
||||
self.securityCode(self.securityCode() + char);
|
||||
|
||||
// Clear all error and other messages for the input
|
||||
if (self.securityCode().length < 6) {
|
||||
clearVerificationCodeMessages();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear error messages from verification code
|
||||
function clearVerificationCodeMessages() {
|
||||
$('.obico-verification-wrapper').removeClass(['error', 'success', 'unknown']);
|
||||
}
|
||||
|
||||
self.startAutoCloseTimout = function() {
|
||||
setTimeout(function() {
|
||||
$('.obico-auto-close').addClass('active');
|
||||
setTimeout(function() { self.hideWizardModal(); }, 10000); // auto-close in 10s
|
||||
}, 500) // Add .5s delay to make transition visible
|
||||
}
|
||||
|
||||
|
||||
self.nextStep = function() {
|
||||
if (self.step() === 1) {
|
||||
let url = self.settingsViewModel.settings.plugins.obico.endpoint_prefix()
|
||||
|
||||
if (self.serverType() === 'self-hosted') {
|
||||
if (self.checkSeverValidity(url)) {
|
||||
self.isServerInvalid(false);
|
||||
} else {
|
||||
self.isServerInvalid(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.serverType(getServerType(url))
|
||||
if (self.settingsViewModel.settings.plugins.obico.endpoint_prefix() !== self.initialServerEndpointPrefix) {
|
||||
self.settingsViewModel.saveData({plugins: {obico: {endpoint_prefix: url}}});
|
||||
}
|
||||
}
|
||||
|
||||
self.toStep(self.step() + 1);
|
||||
|
||||
if (self.step() === 4) {
|
||||
$('.obico-modal[aria-hidden="false"] .obico-verification-code-input input[data-number=1]').trigger('focus');
|
||||
} else if (self.step() === 5) {
|
||||
// Close button with countdown animation
|
||||
self.startAutoCloseTimout()
|
||||
}
|
||||
};
|
||||
|
||||
self.prevStep = function() {
|
||||
self.toStep(self.step() - 1);
|
||||
};
|
||||
|
||||
self.toStep = function(nextStep) {
|
||||
self.step(nextStep);
|
||||
};
|
||||
|
||||
|
||||
self.toggleCheck = function() {
|
||||
self.userAgreementChecked(!self.userAgreementChecked());
|
||||
}
|
||||
|
||||
self.securityCode.subscribe(function(code) {
|
||||
self.verifySecurityCode(code);
|
||||
});
|
||||
|
||||
self.printerName.subscribe(function() {
|
||||
if (self.printerNameTimeoutId()) {
|
||||
clearTimeout(self.printerNameTimeoutId());
|
||||
}
|
||||
let newTimeoutId = setTimeout(self.savePrinterName, 1000);
|
||||
self.printerNameTimeoutId(newTimeoutId);
|
||||
})
|
||||
|
||||
self.verifySecurityCode = function(code) {
|
||||
if (code.length !== 6) {
|
||||
return;
|
||||
}
|
||||
self.verifying(true);
|
||||
|
||||
apiCommand({
|
||||
command: "verify_code",
|
||||
code: code,
|
||||
endpoint_prefix: $('#endpoint_prefix-input').val(),
|
||||
})
|
||||
.done(function(apiStatus) {
|
||||
if (apiStatus.succeeded == null) {
|
||||
$('.obico-verification-wrapper').addClass('unknown');
|
||||
}
|
||||
else if (apiStatus.succeeded) {
|
||||
$('.obico-verification-wrapper').addClass('success');
|
||||
self.printerName(apiStatus.printer.name);
|
||||
self.nextStep();
|
||||
} else {
|
||||
$('.obico-verification-wrapper').addClass('error');
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
$('.obico-verification-wrapper').addClass('unknown');
|
||||
})
|
||||
.always(function () {
|
||||
self.verifying(false);
|
||||
});
|
||||
};
|
||||
|
||||
self.resetEndpointPrefix = function () {
|
||||
self.settingsViewModel.settings.plugins.obico.endpoint_prefix(defaultServerAddress);
|
||||
return true;
|
||||
};
|
||||
|
||||
self.clearEndpointPrefix = function () {
|
||||
self.settingsViewModel.settings.plugins.obico.endpoint_prefix('');
|
||||
return true;
|
||||
};
|
||||
|
||||
self.reset = function() {
|
||||
self.step(1);
|
||||
self.verifying(false);
|
||||
self.securityCode('');
|
||||
$('.obico-auto-close').removeClass('active');
|
||||
|
||||
let verificationWrapper = $('.obico-verification-wrapper');
|
||||
verificationWrapper.removeClass('success error unknown');
|
||||
|
||||
for (let i = 1; i <= 6; i++) {
|
||||
verificationWrapper.find('.obico-verification-code-input input[data-number='+ i +']').val('');
|
||||
}
|
||||
self.serverType(getServerType(self.settingsViewModel.settings.plugins.obico.endpoint_prefix()));
|
||||
self.initialServerEndpointPrefix = self.settingsViewModel.settings.plugins.obico.endpoint_prefix();
|
||||
}
|
||||
|
||||
self.hideWizardModal = function() {
|
||||
$('.obico-auto-close').removeClass('active');
|
||||
$('#wizardModal').modal('hide');
|
||||
}
|
||||
|
||||
// Next feature in the slider on home screen
|
||||
self.nextFeature = function() {
|
||||
let container = $('.obico-features').last();
|
||||
let slidesCount = container.find('.obico-feature').length;
|
||||
let currentSlide = self.currentFeatureSlide();
|
||||
let nextSlide = currentSlide === slidesCount ? 1 : currentSlide + 1;
|
||||
|
||||
container.find('.obico-feature[data-number="'+ currentSlide +'"]').animate({
|
||||
left: '-100%'
|
||||
}, {duration: 500, queue: false});
|
||||
|
||||
container.find('.obico-feature[data-number="'+ nextSlide +'"]').animate({
|
||||
left: '0'
|
||||
},
|
||||
500,
|
||||
function() {
|
||||
let next = nextSlide === slidesCount ? 1 : nextSlide + 1;
|
||||
container.find('.obico-feature[data-number="'+ next +'"]').css('left', '100%');
|
||||
});
|
||||
|
||||
self.currentFeatureSlide(nextSlide);
|
||||
}
|
||||
|
||||
setInterval(self.nextFeature, 3000);
|
||||
}
|
||||
|
||||
/* view model class, parameters for constructor, container to bind to
|
||||
* Please see http://docs.octoprint.org/en/master/plugins/viewmodels.html#registering-custom-viewmodels for more details
|
||||
* and a full list of the available options.
|
||||
*/
|
||||
OCTOPRINT_VIEWMODELS.push({
|
||||
construct: ObicoWizardViewModel,
|
||||
// ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ...
|
||||
dependencies: ["settingsViewModel"],
|
||||
// Elements to bind to, e.g. #settings_plugin_obico, #tab_plugin_obico, ...
|
||||
elements: [
|
||||
"#wizard_plugin_obico",
|
||||
"#obico-wizard",
|
||||
]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
;
|
||||
|
||||
} catch (error) {
|
||||
log.error("Error in JS assets for plugin obico:", `${exc.message}
|
||||
${exc.stack || exc}`);
|
||||
}
|
||||
})();
|
||||
|
|
Binary file not shown.
|
@ -1,3 +1,2 @@
|
|||
2024-05-09 09:05:40,718 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
2024-05-09 11:16:37,888 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
2024-05-09 11:53:50,286 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
2024-05-10 15:15:10,819 - Logging in user shxadmiral from 172.24.0.1 via Remember Me cookie
|
||||
2024-05-10 16:39:22,057 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
2024-05-09 09:05:40,718 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
2024-05-09 11:16:37,888 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
||||
2024-05-09 11:53:50,286 - Logging in user shxadmiral from 172.24.0.1 via credentials
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,102 +1,98 @@
|
|||
2024-05-09 11:16:56,344 /usr/local/bin/python -m pip --disable-pip-version-check install file:///tmp/tmpfjd_ciah/OctoPrint-BambuPrinter-master.zip --no-cache-dir
|
||||
2024-05-09 11:16:59,154 > Processing /tmp/tmpfjd_ciah/OctoPrint-BambuPrinter-master.zip
|
||||
2024-05-09 11:16:59,155 > Preparing metadata (setup.py): started
|
||||
2024-05-09 11:16:59,155 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-09 11:16:59,155 > Requirement already satisfied: OctoPrint in /usr/local/lib/python3.10/site-packages (from OctoPrint-BambuPrinter==0.0.18) (1.10.0)
|
||||
2024-05-09 11:16:59,156 > Collecting paho-mqtt<2
|
||||
2024-05-09 11:16:59,156 > Downloading paho-mqtt-1.6.1.tar.gz (99 kB)
|
||||
2024-05-09 11:16:59,156 > ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.4/99.4 kB 13.2 MB/s eta 0:00:00
|
||||
2024-05-09 11:16:59,156 > Preparing metadata (setup.py): started
|
||||
2024-05-09 11:16:59,156 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-09 11:16:59,156 > Collecting python-dateutil
|
||||
2024-05-09 11:16:59,156 > Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
|
||||
2024-05-09 11:16:59,156 > ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 229.9/229.9 kB 103.5 MB/s eta 0:00:00
|
||||
2024-05-09 11:16:59,156 > Collecting pybambu>=1.0.1
|
||||
2024-05-09 11:16:59,156 > Downloading pybambu-1.0.1-py3-none-any.whl (25 kB)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: argon2-cffi>=23.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (23.1.0)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: sentry-sdk<2,>=1.40.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.45.0)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: flask<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.5)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: passlib<2,>=1.7.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.7.4)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: filetype<2,>=1.2.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-FirmwareCheck>=2021.10.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2021.10.11)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pathvalidate<3,>=2.5.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.5.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: frozendict<3,>=2.4.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.4.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: watchdog<3,>=2.3.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.3.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pylru<2,>=1.2.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-FileCheck>=2021.2.23 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.3.27)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Click<9,>=8.1.7 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (8.1.7)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: netifaces2<0.1,>=0.0.21 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.0.22)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Flask-Assets<3,>=2.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.1.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-PiSupport>=2023.10.10 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2023.10.10)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: zeroconf~=0.127 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.132.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: blinker<1.7.0,>=1.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.6.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: unidecode in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.3.8)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pytz in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Babel<2.13,>=2.12.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.12.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: zipstream-ng<2.0.0,>=1.7.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.7.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: wheel in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.43.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Flask-Login<0.7,>=0.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.6.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pyserial<4,>=3.5 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.5)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: future<1,>=0.18.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.18.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pkginfo<2,>=1.9.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.10.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: markdown<3.5,>=3.4.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.4.4)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: sarge==0.1.7.post1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.1.7.post1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: colorlog<7,>=6.7.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.8.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: emoji<3,>=2.10.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.11.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: feedparser<7,>=6.0.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.0.11)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: websocket-client==1.6.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.6.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: tornado<6.3,>=6.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: pydantic==1.10.12 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.10.12)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: Flask-Babel<4,>=3.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.1.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: werkzeug<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.3)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: requests<3,>=2.31.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.31.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: wrapt<1.16,>=1.15 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.15.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: PyYAML<7,>=6.0.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.0.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: psutil<6,>=5.9.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (5.9.8)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: class-doc<0.3,>=0.2.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.2.6)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: cachelib<0.11,>=0.10.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.10.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: regex in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.4.16)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: Flask-Limiter<4,>=3.5.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.6.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: semantic-version<3,>=2.10.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.10.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: netaddr<0.9,>=0.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.8.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: setuptools in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (65.5.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/site-packages (from pydantic==1.10.12->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.11.0)
|
||||
2024-05-09 11:16:59,158 > Collecting six>=1.5
|
||||
2024-05-09 11:16:59,158 > Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/site-packages (from argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (21.2.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: more-itertools>=5.0.0 in /usr/local/lib/python3.10/site-packages (from class-doc<0.3,>=0.2.6->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (10.2.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: sgmllib3k in /usr/local/lib/python3.10/site-packages (from feedparser<7,>=6.0.11->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.0.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: itsdangerous>=2.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: Jinja2>=3.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.1.3)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: webassets>=2.0 in /usr/local/lib/python3.10/site-packages (from Flask-Assets<3,>=2.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: rich<14,>=12 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (13.7.1)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: ordered-set<5,>4 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.1.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: limits>=2.8 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.11.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.7)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.1)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.2.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.3.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/site-packages (from werkzeug<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.1.5)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: async-timeout>=3.0.0 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.0.3)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: ifaddr>=0.1.7 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: importlib-resources>=1.3 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.4.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: packaging<25,>=21 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (24.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: deprecated>=1.2 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.14)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.17.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.0.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.10/site-packages (from argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.16.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: pycparser in /usr/local/lib/python3.10/site-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.22)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.1.2)
|
||||
2024-05-09 11:16:59,159 > Building wheels for collected packages: OctoPrint-BambuPrinter, paho-mqtt
|
||||
2024-05-09 11:16:59,159 > Building wheel for OctoPrint-BambuPrinter (setup.py): started
|
||||
2024-05-09 11:17:00,395 > Building wheel for OctoPrint-BambuPrinter (setup.py): finished with status 'done'
|
||||
2024-05-09 11:17:00,395 > Created wheel for OctoPrint-BambuPrinter: filename=OctoPrint_BambuPrinter-0.0.18-py2.py3-none-any.whl size=18496 sha256=7bf6712a8aa5981cb8e4b9952d9a85677b5a4d07c93db966fc7f5fc17e0487a4
|
||||
2024-05-09 11:17:00,395 > Stored in directory: /tmp/pip-ephem-wheel-cache-8w6q_vn0/wheels/5b/78/4d/4be6f51abf917047386f0f236b6f2307dd61a62f9738da7072
|
||||
2024-05-09 11:17:00,395 > Building wheel for paho-mqtt (setup.py): started
|
||||
2024-05-09 11:17:00,395 > Building wheel for paho-mqtt (setup.py): finished with status 'done'
|
||||
2024-05-09 11:17:00,395 > Created wheel for paho-mqtt: filename=paho_mqtt-1.6.1-py3-none-any.whl size=62119 sha256=709ff0cf8607da36ac8e384ff8f16332d05238a9950f06bb5ffe81164338e22f
|
||||
2024-05-09 11:17:00,395 > Stored in directory: /tmp/pip-ephem-wheel-cache-8w6q_vn0/wheels/8b/bb/0c/79444d1dee20324d442856979b5b519b48828b0bd3d05df84a
|
||||
2024-05-09 11:17:00,395 > Successfully built OctoPrint-BambuPrinter paho-mqtt
|
||||
2024-05-09 11:17:00,396 > Installing collected packages: paho-mqtt, six, pybambu, python-dateutil, OctoPrint-BambuPrinter
|
||||
2024-05-09 11:17:00,396 > Successfully installed OctoPrint-BambuPrinter-0.0.18 paho-mqtt-1.6.1 pybambu-1.0.1 python-dateutil-2.9.0.post0 six-1.16.0
|
||||
2024-05-09 11:17:00,396 ! WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
|
||||
2024-05-10 16:40:03,797 /usr/local/bin/python -m pip --disable-pip-version-check install file:///tmp/tmprmpq1j_h/OctoPrint-Obico-master.zip --no-cache-dir
|
||||
2024-05-10 16:40:06,959 > Processing /tmp/tmprmpq1j_h/OctoPrint-Obico-master.zip
|
||||
2024-05-10 16:40:06,959 > Preparing metadata (setup.py): started
|
||||
2024-05-10 16:40:06,959 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: OctoPrint>=1.5.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint-Obico==2.4.13) (1.10.0)
|
||||
2024-05-10 16:40:06,959 > Collecting backoff>=1.4.3
|
||||
2024-05-10 16:40:06,959 > Downloading backoff-2.2.1-py3-none-any.whl (15 kB)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: sentry-sdk>=1.5.12 in /usr/local/lib/python3.10/site-packages (from OctoPrint-Obico==2.4.13) (1.45.0)
|
||||
2024-05-10 16:40:06,959 > Collecting bson>=0.5.10
|
||||
2024-05-10 16:40:06,959 > Downloading bson-0.5.10.tar.gz (10 kB)
|
||||
2024-05-10 16:40:06,959 > Preparing metadata (setup.py): started
|
||||
2024-05-10 16:40:06,959 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: python-dateutil>=2.4.0 in /octoprint/plugins/lib/python3.10/site-packages (from bson>=0.5.10->OctoPrint-Obico==2.4.13) (2.9.0.post0)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: six>=1.9.0 in /octoprint/plugins/lib/python3.10/site-packages (from bson>=0.5.10->OctoPrint-Obico==2.4.13) (1.16.0)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: psutil<6,>=5.9.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (5.9.8)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: netifaces2<0.1,>=0.0.21 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.0.22)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: Flask-Login<0.7,>=0.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.6.3)
|
||||
2024-05-10 16:40:06,959 > Requirement already satisfied: sarge==0.1.7.post1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.1.7.post1)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: unidecode in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.3.8)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: requests<3,>=2.31.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.31.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: pytz in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2024.1)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: passlib<2,>=1.7.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.7.4)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: OctoPrint-PiSupport>=2023.10.10 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2023.10.10)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: frozendict<3,>=2.4.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.4.2)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: werkzeug<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.2.3)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: filetype<2,>=1.2.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.2.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: emoji<3,>=2.10.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.11.1)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: class-doc<0.3,>=0.2.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.2.6)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: Babel<2.13,>=2.12.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.12.1)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: tornado<6.3,>=6.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (6.2)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: Flask-Assets<3,>=2.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.1.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: cachelib<0.11,>=0.10.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.10.2)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: pkginfo<2,>=1.9.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.10.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: zeroconf~=0.127 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.132.2)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: wrapt<1.16,>=1.15 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.15.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: Flask-Limiter<4,>=3.5.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.6.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: pydantic==1.10.12 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.10.12)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: regex in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2024.4.16)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: OctoPrint-FileCheck>=2021.2.23 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2024.3.27)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: semantic-version<3,>=2.10.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.10.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: colorlog<7,>=6.7.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (6.8.2)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: netaddr<0.9,>=0.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.8.0)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: blinker<1.7.0,>=1.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.6.3)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: Click<9,>=8.1.7 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (8.1.7)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: flask<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.2.5)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: PyYAML<7,>=6.0.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (6.0.1)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: future<1,>=0.18.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.18.3)
|
||||
2024-05-10 16:40:06,960 > Requirement already satisfied: watchdog<3,>=2.3.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.3.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: feedparser<7,>=6.0.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (6.0.11)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: OctoPrint-FirmwareCheck>=2021.10.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2021.10.11)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: zipstream-ng<2.0.0,>=1.7.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.7.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: pylru<2,>=1.2.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.2.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: websocket-client==1.6.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.6.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: pyserial<4,>=3.5 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.5)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: wheel in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.43.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: pathvalidate<3,>=2.5.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.5.2)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: Flask-Babel<4,>=3.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.1.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: argon2-cffi>=23.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (23.1.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: markdown<3.5,>=3.4.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.4.4)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: setuptools in /usr/local/lib/python3.10/site-packages (from OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (65.5.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/site-packages (from pydantic==1.10.12->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (4.11.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: certifi in /usr/local/lib/python3.10/site-packages (from sentry-sdk>=1.5.12->OctoPrint-Obico==2.4.13) (2024.2.2)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: urllib3>=1.26.11 in /usr/local/lib/python3.10/site-packages (from sentry-sdk>=1.5.12->OctoPrint-Obico==2.4.13) (2.2.1)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/site-packages (from argon2-cffi>=23.1.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (21.2.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: more-itertools>=5.0.0 in /usr/local/lib/python3.10/site-packages (from class-doc<0.3,>=0.2.6->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (10.2.0)
|
||||
2024-05-10 16:40:06,961 > Requirement already satisfied: sgmllib3k in /usr/local/lib/python3.10/site-packages (from feedparser<7,>=6.0.11->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.0.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: itsdangerous>=2.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.2.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: Jinja2>=3.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.1.3)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: webassets>=2.0 in /usr/local/lib/python3.10/site-packages (from Flask-Assets<3,>=2.1.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: ordered-set<5,>4 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (4.1.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: limits>=2.8 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.11.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: rich<14,>=12 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (13.7.1)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.7)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.3.2)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/site-packages (from werkzeug<2.3,>=2.2.3->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.1.5)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: ifaddr>=0.1.7 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.2.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: async-timeout>=3.0.0 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (4.0.3)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: packaging<25,>=21 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (24.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: importlib-resources>=1.3 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (6.4.0)
|
||||
2024-05-10 16:40:06,962 > Requirement already satisfied: deprecated>=1.2 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.2.14)
|
||||
2024-05-10 16:40:06,963 > Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.17.2)
|
||||
2024-05-10 16:40:06,963 > Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (3.0.0)
|
||||
2024-05-10 16:40:06,963 > Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.10/site-packages (from argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (1.16.0)
|
||||
2024-05-10 16:40:06,963 > Requirement already satisfied: pycparser in /usr/local/lib/python3.10/site-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (2.22)
|
||||
2024-05-10 16:40:06,963 > Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint>=1.5.0->OctoPrint-Obico==2.4.13) (0.1.2)
|
||||
2024-05-10 16:40:06,963 > Building wheels for collected packages: OctoPrint-Obico, bson
|
||||
2024-05-10 16:40:06,963 > Building wheel for OctoPrint-Obico (setup.py): started
|
||||
2024-05-10 16:40:11,378 > Building wheel for OctoPrint-Obico (setup.py): finished with status 'done'
|
||||
2024-05-10 16:40:11,379 > Created wheel for OctoPrint-Obico: filename=OctoPrint_Obico-2.4.13-py3-none-any.whl size=18856209 sha256=cea3061db2b89ceeb4bef4f39b35d171e05c08350661c02cc02f94092d769e1a
|
||||
2024-05-10 16:40:11,379 > Stored in directory: /tmp/pip-ephem-wheel-cache-x3g1dhtt/wheels/b9/e5/05/b25ddc3158c7c9eb4c989e4619a00cb531e7a42a9e2ec34df0
|
||||
2024-05-10 16:40:11,379 > Building wheel for bson (setup.py): started
|
||||
2024-05-10 16:40:12,380 > Building wheel for bson (setup.py): finished with status 'done'
|
||||
2024-05-10 16:40:12,381 > Created wheel for bson: filename=bson-0.5.10-py3-none-any.whl size=11976 sha256=44285e8baaa903377372ba2e1b70e7c1837fe399619a4e55c5f5be3490fba58e
|
||||
2024-05-10 16:40:12,381 > Stored in directory: /tmp/pip-ephem-wheel-cache-x3g1dhtt/wheels/36/49/3b/8b33954dfae7a176009c4d721a45af56c8a9c1cdc3ee947945
|
||||
2024-05-10 16:40:12,381 > Successfully built OctoPrint-Obico bson
|
||||
2024-05-10 16:40:12,381 > Installing collected packages: backoff, bson, OctoPrint-Obico
|
||||
2024-05-10 16:40:12,381 > Successfully installed OctoPrint-Obico-2.4.13 backoff-2.2.1 bson-0.5.10
|
||||
2024-05-10 16:40:12,381 ! WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
2024-05-09 11:16:56,344 /usr/local/bin/python -m pip --disable-pip-version-check install file:///tmp/tmpfjd_ciah/OctoPrint-BambuPrinter-master.zip --no-cache-dir
|
||||
2024-05-09 11:16:59,154 > Processing /tmp/tmpfjd_ciah/OctoPrint-BambuPrinter-master.zip
|
||||
2024-05-09 11:16:59,155 > Preparing metadata (setup.py): started
|
||||
2024-05-09 11:16:59,155 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-09 11:16:59,155 > Requirement already satisfied: OctoPrint in /usr/local/lib/python3.10/site-packages (from OctoPrint-BambuPrinter==0.0.18) (1.10.0)
|
||||
2024-05-09 11:16:59,156 > Collecting paho-mqtt<2
|
||||
2024-05-09 11:16:59,156 > Downloading paho-mqtt-1.6.1.tar.gz (99 kB)
|
||||
2024-05-09 11:16:59,156 > ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.4/99.4 kB 13.2 MB/s eta 0:00:00
|
||||
2024-05-09 11:16:59,156 > Preparing metadata (setup.py): started
|
||||
2024-05-09 11:16:59,156 > Preparing metadata (setup.py): finished with status 'done'
|
||||
2024-05-09 11:16:59,156 > Collecting python-dateutil
|
||||
2024-05-09 11:16:59,156 > Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
|
||||
2024-05-09 11:16:59,156 > ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 229.9/229.9 kB 103.5 MB/s eta 0:00:00
|
||||
2024-05-09 11:16:59,156 > Collecting pybambu>=1.0.1
|
||||
2024-05-09 11:16:59,156 > Downloading pybambu-1.0.1-py3-none-any.whl (25 kB)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: argon2-cffi>=23.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (23.1.0)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: sentry-sdk<2,>=1.40.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.45.0)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: flask<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.5)
|
||||
2024-05-09 11:16:59,156 > Requirement already satisfied: passlib<2,>=1.7.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.7.4)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: filetype<2,>=1.2.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-FirmwareCheck>=2021.10.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2021.10.11)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pathvalidate<3,>=2.5.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.5.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: frozendict<3,>=2.4.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.4.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: watchdog<3,>=2.3.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.3.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pylru<2,>=1.2.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-FileCheck>=2021.2.23 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.3.27)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Click<9,>=8.1.7 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (8.1.7)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: netifaces2<0.1,>=0.0.21 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.0.22)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Flask-Assets<3,>=2.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.1.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: OctoPrint-PiSupport>=2023.10.10 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2023.10.10)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: zeroconf~=0.127 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.132.2)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: blinker<1.7.0,>=1.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.6.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: unidecode in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.3.8)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pytz in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Babel<2.13,>=2.12.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.12.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: zipstream-ng<2.0.0,>=1.7.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.7.1)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: wheel in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.43.0)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: Flask-Login<0.7,>=0.6.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.6.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pyserial<4,>=3.5 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.5)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: future<1,>=0.18.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.18.3)
|
||||
2024-05-09 11:16:59,157 > Requirement already satisfied: pkginfo<2,>=1.9.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.10.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: markdown<3.5,>=3.4.4 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.4.4)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: sarge==0.1.7.post1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.1.7.post1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: colorlog<7,>=6.7.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.8.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: emoji<3,>=2.10.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.11.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: feedparser<7,>=6.0.11 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.0.11)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: websocket-client==1.6.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.6.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: tornado<6.3,>=6.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: pydantic==1.10.12 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.10.12)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: Flask-Babel<4,>=3.1.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.1.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: werkzeug<2.3,>=2.2.3 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.3)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: requests<3,>=2.31.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.31.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: wrapt<1.16,>=1.15 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.15.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: PyYAML<7,>=6.0.1 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.0.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: psutil<6,>=5.9.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (5.9.8)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: class-doc<0.3,>=0.2.6 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.2.6)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: cachelib<0.11,>=0.10.2 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.10.2)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: regex in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.4.16)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: Flask-Limiter<4,>=3.5.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.6.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: semantic-version<3,>=2.10.0 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.10.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: netaddr<0.9,>=0.8 in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.8.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: setuptools in /usr/local/lib/python3.10/site-packages (from OctoPrint->OctoPrint-BambuPrinter==0.0.18) (65.5.1)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/site-packages (from pydantic==1.10.12->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.11.0)
|
||||
2024-05-09 11:16:59,158 > Collecting six>=1.5
|
||||
2024-05-09 11:16:59,158 > Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/site-packages (from argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (21.2.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: more-itertools>=5.0.0 in /usr/local/lib/python3.10/site-packages (from class-doc<0.3,>=0.2.6->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (10.2.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: sgmllib3k in /usr/local/lib/python3.10/site-packages (from feedparser<7,>=6.0.11->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.0.0)
|
||||
2024-05-09 11:16:59,158 > Requirement already satisfied: itsdangerous>=2.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: Jinja2>=3.0 in /usr/local/lib/python3.10/site-packages (from flask<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.1.3)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: webassets>=2.0 in /usr/local/lib/python3.10/site-packages (from Flask-Assets<3,>=2.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: rich<14,>=12 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (13.7.1)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: ordered-set<5,>4 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.1.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: limits>=2.8 in /usr/local/lib/python3.10/site-packages (from Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.11.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.7)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.2.1)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2024.2.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests<3,>=2.31.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.3.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/site-packages (from werkzeug<2.3,>=2.2.3->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.1.5)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: async-timeout>=3.0.0 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (4.0.3)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: ifaddr>=0.1.7 in /usr/local/lib/python3.10/site-packages (from zeroconf~=0.127->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.2.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: importlib-resources>=1.3 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (6.4.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: packaging<25,>=21 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (24.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: deprecated>=1.2 in /usr/local/lib/python3.10/site-packages (from limits>=2.8->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.2.14)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.17.2)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (3.0.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.10/site-packages (from argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (1.16.0)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: pycparser in /usr/local/lib/python3.10/site-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi>=23.1.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (2.22)
|
||||
2024-05-09 11:16:59,159 > Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich<14,>=12->Flask-Limiter<4,>=3.5.0->OctoPrint->OctoPrint-BambuPrinter==0.0.18) (0.1.2)
|
||||
2024-05-09 11:16:59,159 > Building wheels for collected packages: OctoPrint-BambuPrinter, paho-mqtt
|
||||
2024-05-09 11:16:59,159 > Building wheel for OctoPrint-BambuPrinter (setup.py): started
|
||||
2024-05-09 11:17:00,395 > Building wheel for OctoPrint-BambuPrinter (setup.py): finished with status 'done'
|
||||
2024-05-09 11:17:00,395 > Created wheel for OctoPrint-BambuPrinter: filename=OctoPrint_BambuPrinter-0.0.18-py2.py3-none-any.whl size=18496 sha256=7bf6712a8aa5981cb8e4b9952d9a85677b5a4d07c93db966fc7f5fc17e0487a4
|
||||
2024-05-09 11:17:00,395 > Stored in directory: /tmp/pip-ephem-wheel-cache-8w6q_vn0/wheels/5b/78/4d/4be6f51abf917047386f0f236b6f2307dd61a62f9738da7072
|
||||
2024-05-09 11:17:00,395 > Building wheel for paho-mqtt (setup.py): started
|
||||
2024-05-09 11:17:00,395 > Building wheel for paho-mqtt (setup.py): finished with status 'done'
|
||||
2024-05-09 11:17:00,395 > Created wheel for paho-mqtt: filename=paho_mqtt-1.6.1-py3-none-any.whl size=62119 sha256=709ff0cf8607da36ac8e384ff8f16332d05238a9950f06bb5ffe81164338e22f
|
||||
2024-05-09 11:17:00,395 > Stored in directory: /tmp/pip-ephem-wheel-cache-8w6q_vn0/wheels/8b/bb/0c/79444d1dee20324d442856979b5b519b48828b0bd3d05df84a
|
||||
2024-05-09 11:17:00,395 > Successfully built OctoPrint-BambuPrinter paho-mqtt
|
||||
2024-05-09 11:17:00,396 > Installing collected packages: paho-mqtt, six, pybambu, python-dateutil, OctoPrint-BambuPrinter
|
||||
2024-05-09 11:17:00,396 > Successfully installed OctoPrint-BambuPrinter-0.0.18 paho-mqtt-1.6.1 pybambu-1.0.1 python-dateutil-2.9.0.post0 six-1.16.0
|
||||
2024-05-09 11:17:00,396 ! WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
|
|
@ -1,2 +1 @@
|
|||
2024-05-09 16:39:11,261 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
||||
2024-05-09 16:57:55,435 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
||||
2024-05-10 16:47:11,547 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
2024-05-09 16:39:11,261 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
||||
2024-05-09 16:57:55,435 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
||||
2024-05-10 16:44:28,132 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
|
@ -0,0 +1 @@
|
|||
2024-05-10 16:45:37,231 - serial.log is currently not enabled, you can enable it via Settings > Serial Connection > Log communication to serial.log
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -4,10 +4,10 @@ axes:
|
|||
speed: 300
|
||||
x:
|
||||
inverted: false
|
||||
speed: 6000
|
||||
speed: 10000
|
||||
y:
|
||||
inverted: false
|
||||
speed: 6000
|
||||
speed: 10000
|
||||
z:
|
||||
inverted: false
|
||||
speed: 200
|
||||
|
@ -23,12 +23,12 @@ extruder:
|
|||
heatedBed: true
|
||||
heatedChamber: false
|
||||
id: _default
|
||||
model: Generic RepRap Printer
|
||||
name: DefaultHaha
|
||||
model: Bambu
|
||||
name: Default
|
||||
volume:
|
||||
custom_box: false
|
||||
depth: 200.0
|
||||
depth: 256.0
|
||||
formFactor: rectangular
|
||||
height: 200.0
|
||||
height: 256.0
|
||||
origin: lowerleft
|
||||
width: 200.0
|
||||
width: 256.0
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pip
|
|
@ -0,0 +1,661 @@
|
|||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
|
@ -0,0 +1,14 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: OctoPrint-Obico
|
||||
Version: 2.4.13
|
||||
Summary: Securely monitor and control your OctoPrint-connected printer from anywhere for free with Obico. Get unlimited live webcam streaming, full OctoPrint remote access, printer status notifications, and a free companion mobile app for iOS and Android. The best part? AI-powered failure detection watches your prints so you don’t have to.
|
||||
Home-page: https://www.obico.io/
|
||||
Author: The Obico team
|
||||
Author-email: admin@obico.io
|
||||
License: AGPLv3
|
||||
License-File: LICENSE
|
||||
Requires-Dist: OctoPrint >=1.5.0
|
||||
Requires-Dist: backoff >=1.4.3
|
||||
Requires-Dist: sentry-sdk >=1.5.12
|
||||
Requires-Dist: bson >=0.5.10
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
OctoPrint_Obico-2.4.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
OctoPrint_Obico-2.4.13.dist-info/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
||||
OctoPrint_Obico-2.4.13.dist-info/METADATA,sha256=Jg__BBsuWZLTHiWFEzObFsoXivKO9vYPyEMxRfa7k8c,656
|
||||
OctoPrint_Obico-2.4.13.dist-info/RECORD,,
|
||||
OctoPrint_Obico-2.4.13.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
OctoPrint_Obico-2.4.13.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
||||
OctoPrint_Obico-2.4.13.dist-info/direct_url.json,sha256=Krnddfup781JN62g8AQ4qCH7Pt97UqD0jS5DFmAu5Hs,81
|
||||
OctoPrint_Obico-2.4.13.dist-info/entry_points.txt,sha256=xMbYasybQD4I9Pw_GRDXp7vMo498a5Ua7NwaPrJpdvI,43
|
||||
OctoPrint_Obico-2.4.13.dist-info/top_level.txt,sha256=-SYHe5d2HrQK0mdsrbdqO1WjLVgC5J3Ia9L2IYhHS4w,16
|
||||
octoprint_obico/__init__.py,sha256=B1j-BqS2CReXj9aKlWVmkaR6WXHJkIbBgAU8NHcGwO0,23414
|
||||
octoprint_obico/__pycache__/__init__.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/client_conn.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/file_downloader.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/file_operations.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/gcode_hooks.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/gcode_preprocessor.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/janus.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/nozzlecam.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/pause_resume_sequence.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/plugin_apis.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/print_job_tracker.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/printer_discovery.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/remote_status.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/tunnel.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/utils.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/webcam_capture.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/webcam_stream.cpython-310.pyc,,
|
||||
octoprint_obico/__pycache__/ws.cpython-310.pyc,,
|
||||
octoprint_obico/bin/ffmpeg/run.sh,sha256=DR_h9Owuv3-0Eu3JzgS1sdaYUzt5WuP9FUftfNOlvMk,493
|
||||
octoprint_obico/bin/ffmpeg/test-video.mp4,sha256=cEbZ-Hbl6Gfn-KSM91c0SZeMlvvFv_4xGVBTU7jatfQ,26482
|
||||
octoprint_obico/bin/gst/bin/gst-launch-1.0,sha256=aw853FUbE01w1Dvjpr5va_cpdCKdYYapIni-5K2BQP0,79608
|
||||
octoprint_obico/bin/gst/etc/xdg/gstomx.conf,sha256=zCpWwQjexXeJz85CtiykIPYWO21Hxsur1tZA645AIgc,2755
|
||||
octoprint_obico/bin/gst/gst_memory_guard.sh,sha256=nTxA0bnsXDFaXE_0EOFgUmeCOEBEFO3p1plVOUpDaGg,254
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstcoreelements.so,sha256=9Jqr6zeEPae0f5kO1b1uslRsTURKfOO8BSRD3KlpjFU,1375760
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstjpeg.so,sha256=bqfGb1hdOWXE2i-6KW1WG08pQm6JWhLftqFwcAqXUm8,181028
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstmultipart.so,sha256=Em1uTeD7FV2sPu5rp0c6Wy8EM8rTCBX3fw7mv0MC20o,117768
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstomx.so,sha256=UVukJU6i8q9gj49idGMC7rOHASRUPfmcmYt1iYpOs3k,1184180
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstrtp.so,sha256=O_zLio8KyGXw7wsY-Yi7aosKsdRZvkMr_uPBLRmCf4I,3100552
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgsttcp.so,sha256=1bMRnjaw9C6rCeQBBg2MknFsAyryFGkAnA0mati1gEg,440248
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstudp.so,sha256=CxvTcQlgxGzkMwg61OaaDDXIuPF46PbS0r810RZx5Hw,284048
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstvideo4linux2.so,sha256=Uxy_n-B8CUxK-CTPbooU0CE_neKwWIUI1M0b0HPKJPE,1157628
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstvideoconvert.so,sha256=zHEIRN8caAslfmvdmmnIInQUeawaHUyB69-eJvyzED0,80380
|
||||
octoprint_obico/bin/gst/lib/gstreamer-1.0/libgstvideorate.so,sha256=5oQroextEjS_B0xnUiJteotYxK01LlxISgHxBii1lJs,121296
|
||||
octoprint_obico/bin/gst/lib/libgstallocators-1.0.so,sha256=iwwtyl9dts_Om5cl-s9oKFEdwWwNd2CYTL3Yxwhtu-4,32
|
||||
octoprint_obico/bin/gst/lib/libgstallocators-1.0.so.0,sha256=MMw5N49HoruP7uAuIekf_BzwDSxcj5dcC9Kotvsw2fg,45908
|
||||
octoprint_obico/bin/gst/lib/libgstapp-1.0.so,sha256=p-0hSvY6ajK6YpgkV-RDMe5h-TIlxwTnWZUiQ2uAazE,25
|
||||
octoprint_obico/bin/gst/lib/libgstapp-1.0.so.0,sha256=JkWcrdkV8boYPNTmelDlVKsX1aJi8xlrei2npbHIs8o,201012
|
||||
octoprint_obico/bin/gst/lib/libgstaudio-1.0.so,sha256=WfqEC6MwoKh33I5WsLnH-aFEiWnO3mi28UquY4mqqTU,27
|
||||
octoprint_obico/bin/gst/lib/libgstaudio-1.0.so.0,sha256=s_yBIvOVXEV0uxERBUHmrpjtfD221fREK23VOieFAhc,1429372
|
||||
octoprint_obico/bin/gst/lib/libgstbase-1.0.so,sha256=SHQz2YPk9qPKcUd7sDUTvm4Hr8BqPge5cqWaOlBoabY,26
|
||||
octoprint_obico/bin/gst/lib/libgstbase-1.0.so.0,sha256=SjjB0SuG9kteLjyk8nOoEMBmDLCGESFsB3BBHWwMC7A,1494316
|
||||
octoprint_obico/bin/gst/lib/libgstcheck-1.0.so,sha256=mUvgdcmZQVerUyE9-etNK9_SYI-cupd3FF8ZR8quS7M,27
|
||||
octoprint_obico/bin/gst/lib/libgstcheck-1.0.so.0,sha256=XegoEdiXulQyzcPvzpphuwsD-mqAaOGWWSD5RPE91kg,434516
|
||||
octoprint_obico/bin/gst/lib/libgstcontroller-1.0.so,sha256=1SQfvJwizZWHNNZeOVoEjxvBlRVNpeWNQ7IhFCYX2HE,32
|
||||
octoprint_obico/bin/gst/lib/libgstcontroller-1.0.so.0,sha256=9LZE6TH-n3JIbfdEJAMzEdzsUpCQXVJmttVJL0OqXvo,238100
|
||||
octoprint_obico/bin/gst/lib/libgstnet-1.0.so,sha256=lFS6jp-AEP5_lkmURpIW9VOOs5NSdGgqj35CCzdmrGo,25
|
||||
octoprint_obico/bin/gst/lib/libgstnet-1.0.so.0,sha256=s0KKaApEEIo6ckMIFeyRMpdaCqJ1s93qYxr-MBknWpM,297180
|
||||
octoprint_obico/bin/gst/lib/libgstpbutils-1.0.so,sha256=O-siP_64tnC58N23ljaAAkh_g5NqRqw4dSsd_GAnYvc,29
|
||||
octoprint_obico/bin/gst/lib/libgstpbutils-1.0.so.0,sha256=TpJMhj-imJw-p7yY1b8ljrm7ApZ_eaM6Qeoi3AMOai8,691332
|
||||
octoprint_obico/bin/gst/lib/libgstreamer-1.0.so,sha256=3mLfecAk1jrPT97qCeECtZbBZL6k_sCyInuUo_RTlAU,28
|
||||
octoprint_obico/bin/gst/lib/libgstreamer-1.0.so.0,sha256=skUWZXoc7AKwOcha53uZDqqKh9OJHyle9LXafqDMIFQ,4179768
|
||||
octoprint_obico/bin/gst/lib/libgstrtp-1.0.so,sha256=aWVeWInSJcpoe7TXgQrxamPTjAoWtSLDPnz-7zLDY8I,25
|
||||
octoprint_obico/bin/gst/lib/libgstrtp-1.0.so.0,sha256=9UPgFSh6ZOJ0xKmySmZTVKL27ewYp_cexSRRjY5mSUE,381620
|
||||
octoprint_obico/bin/gst/lib/libgsttag-1.0.so,sha256=fNaH_BL4hihqxJ6jRfc9m9KChZeosUYKCVCvbM7YxDc,25
|
||||
octoprint_obico/bin/gst/lib/libgsttag-1.0.so.0,sha256=LAHnLmTxOzrGU64xtbSHTdUrmojM_fDXqPPykTq6pLc,748320
|
||||
octoprint_obico/bin/gst/lib/libgstvideo-1.0.so,sha256=v-nq-tTjSHlFAPROh4_HdggE_MitkQve4M6OCf8tgmQ,27
|
||||
octoprint_obico/bin/gst/lib/libgstvideo-1.0.so.0,sha256=xr0TuAUPFTigiCCV2x-hdeuKJ6etHHU2pp1O5bfjieY,1796084
|
||||
octoprint_obico/bin/gst/run_gst.sh,sha256=wwTcXGuyYVUn7NvKhUbqWtz-ZmIyXPZQ1w2im3MiqIk,895
|
||||
octoprint_obico/bin/janus/.gitignore,sha256=-unY84bWeVaGfe3vfIlHYZmkol7p_-E1YKa_rnrmxAc,8
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/bin/janus,sha256=zFhKoGQaiRd7zumYArkXSZvMka6xpQV8joIn9UYqANQ,3034664
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/plugins/libjanus_streaming.la,sha256=cHyM7u5CtP99HUJRn__-Itef3BzBBOm7EG6XKL3StZ8,1072
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/plugins/libjanus_streaming.so,sha256=oIiGePBYiEB120ObSqZjtz105430SCZkCPqVeIhkzew,1517640
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/transports/libjanus_http.la,sha256=wxnKTTPxuX8St0G7IK4rhyZLx5q6NVo49agim9TW7V4,1018
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/transports/libjanus_http.so,sha256=B7fgBep7UGmlZ334L-rdXZf7a4-av50kLV3VHIc6Qhk,409792
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/transports/libjanus_websockets.la,sha256=5knbT_kUNnLSV7zc3Jvfkf-G7QjpXh4qpHy4ZupfUY8,1054
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/janus/transports/libjanus_websockets.so,sha256=OKmGhSoyWh_79dW7xKbxXZFmb9KuMxMMjeGKTPEHn5M,321072
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libconfig.so.9,sha256=G8Cb7jJixjSFAbH0u_JGPoHc4WCRuxlqJFPaGsueNpA,38568
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libjansson.so.4,sha256=AYNduM3fHRHQZULOwKJOROcpEh91zxEmWSSe50Y8dIA,46596
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libmicrohttpd.so.12,sha256=D6IC35IaKTMWzu4PjybAaMzrqWwFuOdmSaMBLRRewvw,112044
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libnice.so.10,sha256=nrJX2glhJDgGU1V8MHLwjTji7F6vv5fPQDu530q9E8g,1306664
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libsrtp2.so.1,sha256=BEpOUkw7tgd6d8-5CglTqApc6MbObLwXfnDEqKj71z4,85120
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libusrsctp.so.2,sha256=sIiCtZLWxRuhpXtAghlUgm61JVYJfdDCgzwII_pk1Us,1888916
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.10.32-bit/lib/libwebsockets.so.9,sha256=Ce4ZbZnGuD9JNKgIa4gk_A_7DzFDkVIlkcM42GoGT6k,118196
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/bin/janus,sha256=zFhKoGQaiRd7zumYArkXSZvMka6xpQV8joIn9UYqANQ,3034664
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/plugins/libjanus_streaming.la,sha256=cHyM7u5CtP99HUJRn__-Itef3BzBBOm7EG6XKL3StZ8,1072
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/plugins/libjanus_streaming.so,sha256=oIiGePBYiEB120ObSqZjtz105430SCZkCPqVeIhkzew,1517640
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/transports/libjanus_http.la,sha256=wxnKTTPxuX8St0G7IK4rhyZLx5q6NVo49agim9TW7V4,1018
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/transports/libjanus_http.so,sha256=B7fgBep7UGmlZ334L-rdXZf7a4-av50kLV3VHIc6Qhk,409792
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/transports/libjanus_websockets.la,sha256=5knbT_kUNnLSV7zc3Jvfkf-G7QjpXh4qpHy4ZupfUY8,1054
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/janus/transports/libjanus_websockets.so,sha256=OKmGhSoyWh_79dW7xKbxXZFmb9KuMxMMjeGKTPEHn5M,321072
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libconfig.so.9,sha256=G8Cb7jJixjSFAbH0u_JGPoHc4WCRuxlqJFPaGsueNpA,38568
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libjansson.so.4,sha256=AYNduM3fHRHQZULOwKJOROcpEh91zxEmWSSe50Y8dIA,46596
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libmicrohttpd.so.12,sha256=D6IC35IaKTMWzu4PjybAaMzrqWwFuOdmSaMBLRRewvw,112044
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libnice.so.10,sha256=nrJX2glhJDgGU1V8MHLwjTji7F6vv5fPQDu530q9E8g,1306664
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libsrtp2.so.1,sha256=BEpOUkw7tgd6d8-5CglTqApc6MbObLwXfnDEqKj71z4,85120
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libusrsctp.so.2,sha256=sIiCtZLWxRuhpXtAghlUgm61JVYJfdDCgzwII_pk1Us,1888916
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.32-bit/lib/libwebsockets.so.9,sha256=Ce4ZbZnGuD9JNKgIa4gk_A_7DzFDkVIlkcM42GoGT6k,118196
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/bin/janus,sha256=vGwONeR9wJpjf-ijwXcKyhqsZk7x8pzTV9xFfIFeV2A,3575192
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/plugins/libjanus_streaming.la,sha256=__k_XF1lt5M9EW4CEXpBYWbAMMdT5KMedaojnVQ6fiw,1110
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/plugins/libjanus_streaming.so,sha256=AjANNdurtSFHYKZcp3iUx2WhGzI65J5ANn143cGf8Io,27
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/plugins/libjanus_streaming.so.0,sha256=AjANNdurtSFHYKZcp3iUx2WhGzI65J5ANn143cGf8Io,27
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/plugins/libjanus_streaming.so.0.0.0,sha256=oyRv5pJ6Ysm34ZPfLOc6appkwkxVgO0Xa1H_MKoTUNM,1733792
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/transports/libjanus_websockets.la,sha256=R_lg--NL2sL_L37qbW6hvUDPEjOxUv429dKhrbpMXyc,1125
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/transports/libjanus_websockets.so,sha256=6gl6W5TUlrzabtlmGRbNMAbQr4d3_nnRI3_oc1LLTCg,28
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/transports/libjanus_websockets.so.0,sha256=6gl6W5TUlrzabtlmGRbNMAbQr4d3_nnRI3_oc1LLTCg,28
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/janus/transports/libjanus_websockets.so.0.0.0,sha256=H56UNpvnVUcgx5PKnUKr-OMwCamCPTHm6ly5v97gZv0,895648
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libconfig.so.9,sha256=nMmRCf4FH6c1xvjNFO15Ib5cgKpASWp0A7wFK5vWkzI,43528
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libev.so.4,sha256=vdgoelO2YyIZs9NW8xc3C_k0o25ImS0kTySp4bZzMO4,59168
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libgssdp-1.2.so.0,sha256=DtzO0O2OE249IchPXbtlnuXchr0Ky3pqGPxG0BcsDro,83816
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libgupnp-1.2.so.0,sha256=u7gjvO-pXUnLgoBWJFNtpEd2PZcDBBCTGzx9U1jbVfE,214888
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libgupnp-igd-1.0.so.4,sha256=UuejxcpSZCCKFyBmSXDEqPdB_0t0NY438b5nHAA2SR4,34664
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libnice.so.10,sha256=rrbCx8R8ICN1v3ISahY2c-nYTJghPzcMIrSITm06k-o,316376
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libsoup-2.4.so.1,sha256=wMsieL3EqAHVNGX9XlMzEBvsSYg_asU3PoQ295RQevE,653904
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libsrtp2.so.1,sha256=OTROS9SDXiiB02lKSeKAKd3PiDsq1U6YTpd5VBTFAQs,101576
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libusrsctp.so.1,sha256=E4j3UGVvuhB6TqZ1_FAw2T2OEeaAUZtHbTffLvKFs8E,807672
|
||||
octoprint_obico/bin/janus/precomplied/rpi.debian.11.64-bit/lib/libwebsockets.so.16,sha256=4_Ob7jKbIUajizGQM_QQJQmLB7Q_fmaSRn8ONpGv3U0,407968
|
||||
octoprint_obico/bin/janus/run.sh,sha256=gVLtK5_4SC1QDWD7R64JMzbX83hrkKGLNXqNq0Gcrss,740
|
||||
octoprint_obico/bin/janus/setup.sh,sha256=fs4fWfheMZT0k4Snk27AEIITk6GYhJJjQhHQquMarbA,3410
|
||||
octoprint_obico/bin/janus/templates/etc/janus/janus.plugin.streaming.jcfg.rtsp.template,sha256=SMvZsv28Bk_Yc59C7YV2M2FL3g0IPxQ5mbhZvdZBf24,8996
|
||||
octoprint_obico/bin/janus/templates/etc/janus/janus.plugin.streaming.jcfg.template,sha256=hxFT3VogKpb1j7s60hYYn9A1A9S-DddmtDAy6_vRHCI,9013
|
||||
octoprint_obico/bin/janus/templates/etc/janus/janus.transport.websockets.jcfg.template,sha256=wA2L6-NURLkRv-wogAFVlMYmPPPYQQ9IpvbX_uPy3EE,2666
|
||||
octoprint_obico/bin/utils.sh,sha256=b_yNehtWqhuXddMHtV9a2zB9TXKGdQaQDvUa4tbqHRg,446
|
||||
octoprint_obico/client_conn.py,sha256=unsPNxdU6LUC6Il_EA85g_x4B9xvPN4_6BMCBqUDr2g,4860
|
||||
octoprint_obico/file_downloader.py,sha256=TJa0EINsZGOa8a6VP3n_JKR8MtYMpNnTFLLfyYjFOJw,3103
|
||||
octoprint_obico/file_operations.py,sha256=dpDzY_HhFt63ydtgab1jhG_z82ESZUcQzmTscdruQ38,1182
|
||||
octoprint_obico/gcode_hooks.py,sha256=80_CAQX6xJzuYjqbTvQ5d4LhXkdguAIp58pVu2T_Mz0,2640
|
||||
octoprint_obico/gcode_preprocessor.py,sha256=kZVg52ujHO7fDB2LjnKKdy3zpSIQQMakKZpYhhmUyjo,2605
|
||||
octoprint_obico/janus.py,sha256=a3KxAmn_AoQ5E45a2DVDf0bk-jfQM977YZphSwCcmnk,7289
|
||||
octoprint_obico/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
octoprint_obico/lib/__pycache__/__init__.cpython-310.pyc,,
|
||||
octoprint_obico/lib/__pycache__/alert_queue.cpython-310.pyc,,
|
||||
octoprint_obico/lib/__pycache__/curlify.cpython-310.pyc,,
|
||||
octoprint_obico/lib/__pycache__/error_stats.cpython-310.pyc,,
|
||||
octoprint_obico/lib/alert_queue.py,sha256=MZJbBj5WLRcxzWTThW7LMkRJpv8yYBbrg0udH8Rkm_o,1222
|
||||
octoprint_obico/lib/curlify.py,sha256=DCMnidB0DrH5klQG2MkJVV8y1lOAntJ5vpaMYZa3KJ8,1094
|
||||
octoprint_obico/lib/error_stats.py,sha256=3Q_2P0I-wBXTMezpljKAPmIIHdr9Cn5WxER1HOZWIOY,2453
|
||||
octoprint_obico/nozzlecam.py,sha256=DTM0le7AtTrEdZJgKeFd5LNsh5_yCzb55cAIYGOBpFM,2706
|
||||
octoprint_obico/pause_resume_sequence.py,sha256=iUJsrcOOJNDh28l7AtPxvnIek1eODRk8hkVhUfcEFC0,5158
|
||||
octoprint_obico/plugin_apis.py,sha256=kuycjJWmVilK1d0j6V9oCXIlS3QVIyB8_7z9aTGyDbo,3841
|
||||
octoprint_obico/print_job_tracker.py,sha256=OnbEmGybTi6B8LQ2-jVC7mIbnMdD-i-oo-NfKdL2-yE,5711
|
||||
octoprint_obico/printer_discovery.py,sha256=GkccCzr2r0DXybniWyRSjvUoBkAChP_Eulds2VMva70,9977
|
||||
octoprint_obico/remote_status.py,sha256=iFweyyvK6TXq2rcNRtIOYP6Rg2KaIIbW_dKpGuTa_9E,629
|
||||
octoprint_obico/static/css/TheSpaghettiDetective.css,sha256=a1LU4SOONjXI3-ObLUuumvChW4Oz0Ou-XpG1VLTtBn8,83505
|
||||
octoprint_obico/static/css/main.css,sha256=XIk7tV1PoYy18f2fnuFTvwCUeHQJLgaWeThhMiv5Zyw,74578
|
||||
octoprint_obico/static/css/obico-button.css,sha256=XEFTOgIIuhbxUEaji-WemqI68AgQow-PZtqwVz4Of0o,3809
|
||||
octoprint_obico/static/css/obico-collapsable.css,sha256=Zsaf32UZ98MfG3pR2HMry9f1FQvZXO2egxH8g8pKOQg,2591
|
||||
octoprint_obico/static/css/obico-settings-choice.css,sha256=bWDVvgmXsg6n8EaYZf5onQe67abRLD2t7JWS_gPW-FI,4672
|
||||
octoprint_obico/static/css/obico-settings-page.css,sha256=5tIU0sIPrijxHOw4LD9b1ujN4aHB3sAjGxBMrWFO1aE,5311
|
||||
octoprint_obico/static/css/obico-setup-wizard.css,sha256=SDkpQaWZ2RklnA-dgqn-Xug1525FZMXF5FDUE4NpOeQ,48176
|
||||
octoprint_obico/static/css/obico-tabbable.css,sha256=NuFzy6cBQX3G-9uD8dX0NkwZzl6D_FzKzXRAtS3Thwo,8277
|
||||
octoprint_obico/static/css/obico.css,sha256=1fZmY226VHSG092SvZmNzxRVEVVjvWTsKe5fmfw5Z3I,83523
|
||||
octoprint_obico/static/css/variables.css,sha256=5dyr6yGVShQsQjzYsIsXq364iUS6X6-R65LDEsCgcOc,616
|
||||
octoprint_obico/static/img/app-qrcode.png,sha256=uh8f9liVUsWOiJLFU5INfrOg2cmDAMfuy_ckwwd92rE,52285
|
||||
octoprint_obico/static/img/app-store-btn.svg,sha256=vfckFdmZP_IboPM5uLx9musMEPVfsIdaFNWj4-7N7Mg,21168
|
||||
octoprint_obico/static/img/arrow-left-curved.svg,sha256=MEXKF4id_wVpoHOaBGwDC-capZSfQI8BoGt8317zl_g,1216
|
||||
octoprint_obico/static/img/arrow-right-gray.svg,sha256=mcm9m06dFcZh2n3EvWmWsHHFmVBhiDwtWBAa_QrUcnw,627
|
||||
octoprint_obico/static/img/arrow-right.svg,sha256=sjDduzJ8aMGdqc8iXEFbrmr72G3NXY2X7JfIKPzn8N4,950
|
||||
octoprint_obico/static/img/chat.svg,sha256=1bV9RqTkT4pfZKuu-vUZi_rYxEL9MPbfiZIq0L86pU8,1754
|
||||
octoprint_obico/static/img/checkmark-circled.svg,sha256=YDoExVDGtBj94nN2tHfBZhd93XELZrX-T6ul0nyrE-M,771
|
||||
octoprint_obico/static/img/checkmark-half-filled.svg,sha256=hROSDLfAQOm2k9dEJHJK-Liw6IWjZ-9ynRRIwLZ-gCo,456
|
||||
octoprint_obico/static/img/checkmark.svg,sha256=gBfxTpXPeRlQnYOmZA_lYm5ryyWyiKe0SjfloUcIbrA,195
|
||||
octoprint_obico/static/img/desktop-illustration.svg,sha256=alRk0L2vsdBiaFMgwmn2IaeJmBQrRm2J6DlVd9gDdkA,685
|
||||
octoprint_obico/static/img/discord.svg,sha256=PdP-zr9khid8nheOl58WyhPVTjvOFDrbXdHNsVyMKZM,2040
|
||||
octoprint_obico/static/img/features/icon-connection.svg,sha256=Uq45RlHSNEqNzbcNv909T6nl7KxF2nzH4YShfi-ZgS8,2640
|
||||
octoprint_obico/static/img/features/icon-fire.svg,sha256=b_zbnnyOp-zpbOqv5gwPirG98vXEcNrTbfwOxKRIojM,2210
|
||||
octoprint_obico/static/img/features/icon-money.svg,sha256=oNPyFwR9nbIEFxAO-vBICnGKloisGZUH5hhrqgn4lWc,3251
|
||||
octoprint_obico/static/img/features/icon-security.svg,sha256=OaTik2xAkokay2yEtQFW_nV5DQlIUoyTJfYq6AKucWU,2303
|
||||
octoprint_obico/static/img/google-play-btn.svg,sha256=H2Vvyoh9xyY_p9OpOgL18q2VMwZCAP_GXgbOi0uDPLw,18535
|
||||
octoprint_obico/static/img/logo-full.svg,sha256=zk1L-lzmfXCq1pCJjEb9B10LLbSu6CCAMsP7-LRw-9I,8274
|
||||
octoprint_obico/static/img/logo-square-bw.svg,sha256=08l9DBcjFXAYNqvbIXHxqQI6-5bVZHYmjb7WXQaB21Y,696
|
||||
octoprint_obico/static/img/logo-square.svg,sha256=1SfjXXEN06H5MElZkDLv5Jt4kNv82evaKCoWihU0PJY,1330
|
||||
octoprint_obico/static/img/mobile-setup-illustration.svg,sha256=gYhiv0KVRo2P77UpRUsZZZsZpbi9azuLib6HwYtWPMY,26514
|
||||
octoprint_obico/static/img/phone-illustration.svg,sha256=WbXGsH449-FSwwq-kgQE02Vg2yXFF-rg3iEkaHgNMCE,419
|
||||
octoprint_obico/static/img/phone-verification-illustration.svg,sha256=OwekIABlmfUG5nBpMNsATXyKAOwrMzRWvF3_OInV-Bw,10051
|
||||
octoprint_obico/static/img/toggle-arrow.svg,sha256=fI-VgKfjMWph3clVN9dFhe3WG670FNsB6L9wNbnhero,709
|
||||
octoprint_obico/static/js/ObicoSettings.js,sha256=vAO3ARllEjtQZpz0L22N01gsQzHJ7llqIzFD8WjgIIU,13821
|
||||
octoprint_obico/static/js/ObicoWizard.js,sha256=5JqeTNFB4ZBe7TnWeARyumzt-GG8uoZTReZvzJw2Ecw,10773
|
||||
octoprint_obico/static/less/main.less,sha256=z5kO5fq0d2uPaW26rpPls84A8OD8ZxTRVZ0axKS6Vj0,1039
|
||||
octoprint_obico/static/less/obico-button.less,sha256=XZDpcPLfcZ1PEMjZFEahyvenZZXzsTtoj0d8jy7xz44,1265
|
||||
octoprint_obico/static/less/obico-collapsable.less,sha256=lRLRq3pCaxxIyQ52-AD0kPBl7LvGRPvAA5YQ1mYcuB8,753
|
||||
octoprint_obico/static/less/obico-settings-choice.less,sha256=Io_QDZjeSG3-YEZfxW3GhlDEzlwXmEyf0Vwu8NPbNMk,1439
|
||||
octoprint_obico/static/less/obico-settings-page.less,sha256=j_O5fwR3fWF9GBIPxnnwOdbN-anupJPtE1NVzILcGGs,1592
|
||||
octoprint_obico/static/less/obico-setup-wizard.less,sha256=kRQCqVj4eklZBSGamZ8GIoCpYFfYS_Au-IcF_JyXpFc,14950
|
||||
octoprint_obico/static/less/obico-tabbable.less,sha256=gMvZEQ6vsqgpAE7VNPLqulyHfB5fwJBuCranGogT5Bc,2655
|
||||
octoprint_obico/static/less/variables.less,sha256=EntZggzPV51AfhIEKQeltQ3NOZ1vRNqZt72sz-qDHWc,285
|
||||
octoprint_obico/templates/obico_discovery.jinja2,sha256=mdatGI6_cQk2gaRGhzpkVQfIZTIO-4QUg-5dCfqm5PY,186
|
||||
octoprint_obico/templates/obico_settings.jinja2,sha256=c07QneDt911pMH7NF8wPALeZJkM58ReGTZgfK6EqUC4,27832
|
||||
octoprint_obico/templates/obico_wizard.jinja2,sha256=AsmtrdZZBqxUXLgCxYP8X5JnYmaLfxytEO8v3JTyR5U,16196
|
||||
octoprint_obico/tunnel.py,sha256=M4RlEJeEmOxhKJ3acXsDj25_hLkLGSpJ50znyF-_0PM,6174
|
||||
octoprint_obico/utils.py,sha256=RIk4ZcsncDVF8_RWDfRe5wv8DbpHJQv02lfTACu6lng,12549
|
||||
octoprint_obico/webcam_capture.py,sha256=jOMCayiIM_43MXNzTdNq_1t66JlMDaIM4gAuis-9zHM,6210
|
||||
octoprint_obico/webcam_stream.py,sha256=5eKL7e845wzMRj6eq7fo4M5KDogPdFVVUDU_GdiSVnQ,25778
|
||||
octoprint_obico/ws.py,sha256=r5n9aK-mYzFpUFEJVsIFOHeHYTazpAQwicVL_ItL9Xc,3843
|
|
@ -0,0 +1,5 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.43.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"archive_info": {}, "url": "file:///tmp/tmprmpq1j_h/OctoPrint-Obico-master.zip"}
|
|
@ -0,0 +1,2 @@
|
|||
[octoprint.plugin]
|
||||
obico = octoprint_obico
|
|
@ -0,0 +1 @@
|
|||
octoprint_obico
|
|
@ -0,0 +1 @@
|
|||
pip
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 litl, LLC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,419 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: backoff
|
||||
Version: 2.2.1
|
||||
Summary: Function decoration for backoff and retry
|
||||
Home-page: https://github.com/litl/backoff
|
||||
License: MIT
|
||||
Keywords: retry,backoff,decorators
|
||||
Author: Bob Green
|
||||
Author-email: rgreen@aquent.com
|
||||
Requires-Python: >=3.7,<4.0
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Topic :: Internet :: WWW/HTTP
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Utilities
|
||||
Project-URL: Repository, https://github.com/litl/backoff
|
||||
Description-Content-Type: text/x-rst
|
||||
|
||||
backoff
|
||||
=======
|
||||
|
||||
.. image:: https://travis-ci.org/litl/backoff.svg
|
||||
:target: https://travis-ci.org/litl/backoff
|
||||
.. image:: https://coveralls.io/repos/litl/backoff/badge.svg
|
||||
:target: https://coveralls.io/r/litl/backoff?branch=python-3
|
||||
.. image:: https://github.com/litl/backoff/workflows/CodeQL/badge.svg
|
||||
:target: https://github.com/litl/backoff/actions/workflows/codeql-analysis.yml
|
||||
.. image:: https://img.shields.io/pypi/v/backoff.svg
|
||||
:target: https://pypi.python.org/pypi/backoff
|
||||
.. image:: https://img.shields.io/github/license/litl/backoff
|
||||
:target: https://github.com/litl/backoff/blob/master/LICENSE
|
||||
|
||||
**Function decoration for backoff and retry**
|
||||
|
||||
This module provides function decorators which can be used to wrap a
|
||||
function such that it will be retried until some condition is met. It
|
||||
is meant to be of use when accessing unreliable resources with the
|
||||
potential for intermittent failures i.e. network resources and external
|
||||
APIs. Somewhat more generally, it may also be of use for dynamically
|
||||
polling resources for externally generated content.
|
||||
|
||||
Decorators support both regular functions for synchronous code and
|
||||
`asyncio <https://docs.python.org/3/library/asyncio.html>`__'s coroutines
|
||||
for asynchronous code.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Since Kenneth Reitz's `requests <http://python-requests.org>`_ module
|
||||
has become a defacto standard for synchronous HTTP clients in Python,
|
||||
networking examples below are written using it, but it is in no way required
|
||||
by the backoff module.
|
||||
|
||||
@backoff.on_exception
|
||||
---------------------
|
||||
|
||||
The ``on_exception`` decorator is used to retry when a specified exception
|
||||
is raised. Here's an example using exponential backoff when any
|
||||
``requests`` exception is raised:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
The decorator will also accept a tuple of exceptions for cases where
|
||||
the same backoff behavior is desired for more than one exception type:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
(requests.exceptions.Timeout,
|
||||
requests.exceptions.ConnectionError))
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
**Give Up Conditions**
|
||||
|
||||
Optional keyword arguments can specify conditions under which to give
|
||||
up.
|
||||
|
||||
The keyword argument ``max_time`` specifies the maximum amount
|
||||
of total time in seconds that can elapse before giving up.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
max_time=60)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
|
||||
Keyword argument ``max_tries`` specifies the maximum number of calls
|
||||
to make to the target function before giving up.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
max_tries=8,
|
||||
jitter=None)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
|
||||
In some cases the raised exception instance itself may need to be
|
||||
inspected in order to determine if it is a retryable condition. The
|
||||
``giveup`` keyword arg can be used to specify a function which accepts
|
||||
the exception and returns a truthy value if the exception should not
|
||||
be retried:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def fatal_code(e):
|
||||
return 400 <= e.response.status_code < 500
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
max_time=300,
|
||||
giveup=fatal_code)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
By default, when a give up event occurs, the exception in question is reraised
|
||||
and so code calling an `on_exception`-decorated function may still
|
||||
need to do exception handling. This behavior can optionally be disabled
|
||||
using the `raise_on_giveup` keyword argument.
|
||||
|
||||
In the code below, `requests.exceptions.RequestException` will not be raised
|
||||
when giveup occurs. Note that the decorated function will return `None` in this
|
||||
case, regardless of the logic in the `on_exception` handler.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def fatal_code(e):
|
||||
return 400 <= e.response.status_code < 500
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
max_time=300,
|
||||
raise_on_giveup=False,
|
||||
giveup=fatal_code)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
This is useful for non-mission critical code where you still wish to retry
|
||||
the code inside of `backoff.on_exception` but wish to proceed with execution
|
||||
even if all retries fail.
|
||||
|
||||
@backoff.on_predicate
|
||||
---------------------
|
||||
|
||||
The ``on_predicate`` decorator is used to retry when a particular
|
||||
condition is true of the return value of the target function. This may
|
||||
be useful when polling a resource for externally generated content.
|
||||
|
||||
Here's an example which uses a fibonacci sequence backoff when the
|
||||
return value of the target function is the empty list:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_predicate(backoff.fibo, lambda x: x == [], max_value=13)
|
||||
def poll_for_messages(queue):
|
||||
return queue.get()
|
||||
|
||||
Extra keyword arguments are passed when initializing the
|
||||
wait generator, so the ``max_value`` param above is passed as a keyword
|
||||
arg when initializing the fibo generator.
|
||||
|
||||
When not specified, the predicate param defaults to the falsey test,
|
||||
so the above can more concisely be written:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_predicate(backoff.fibo, max_value=13)
|
||||
def poll_for_message(queue):
|
||||
return queue.get()
|
||||
|
||||
More simply, a function which continues polling every second until it
|
||||
gets a non-falsey result could be defined like like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_predicate(backoff.constant, jitter=None, interval=1)
|
||||
def poll_for_message(queue):
|
||||
return queue.get()
|
||||
|
||||
The jitter is disabled in order to keep the polling frequency fixed.
|
||||
|
||||
@backoff.runtime
|
||||
----------------
|
||||
|
||||
You can also use the ``backoff.runtime`` generator to make use of the
|
||||
return value or thrown exception of the decorated method.
|
||||
|
||||
For example, to use the value in the ``Retry-After`` header of the response:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_predicate(
|
||||
backoff.runtime,
|
||||
predicate=lambda r: r.status_code == 429,
|
||||
value=lambda r: int(r.headers.get("Retry-After")),
|
||||
jitter=None,
|
||||
)
|
||||
def get_url():
|
||||
return requests.get(url)
|
||||
|
||||
Jitter
|
||||
------
|
||||
|
||||
A jitter algorithm can be supplied with the ``jitter`` keyword arg to
|
||||
either of the backoff decorators. This argument should be a function
|
||||
accepting the original unadulterated backoff value and returning it's
|
||||
jittered counterpart.
|
||||
|
||||
As of version 1.2, the default jitter function ``backoff.full_jitter``
|
||||
implements the 'Full Jitter' algorithm as defined in the AWS
|
||||
Architecture Blog's `Exponential Backoff And Jitter
|
||||
<https://www.awsarchitectureblog.com/2015/03/backoff.html>`_ post.
|
||||
Note that with this algorithm, the time yielded by the wait generator
|
||||
is actually the *maximum* amount of time to wait.
|
||||
|
||||
Previous versions of backoff defaulted to adding some random number of
|
||||
milliseconds (up to 1s) to the raw sleep value. If desired, this
|
||||
behavior is now available as ``backoff.random_jitter``.
|
||||
|
||||
Using multiple decorators
|
||||
-------------------------
|
||||
|
||||
The backoff decorators may also be combined to specify different
|
||||
backoff behavior for different cases:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_predicate(backoff.fibo, max_value=13)
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.HTTPError,
|
||||
max_time=60)
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.Timeout,
|
||||
max_time=300)
|
||||
def poll_for_message(queue):
|
||||
return queue.get()
|
||||
|
||||
|
||||
Runtime Configuration
|
||||
---------------------
|
||||
|
||||
The decorator functions ``on_exception`` and ``on_predicate`` are
|
||||
generally evaluated at import time. This is fine when the keyword args
|
||||
are passed as constant values, but suppose we want to consult a
|
||||
dictionary with configuration options that only become available at
|
||||
runtime. The relevant values are not available at import time. Instead,
|
||||
decorator functions can be passed callables which are evaluated at
|
||||
runtime to obtain the value:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def lookup_max_time():
|
||||
# pretend we have a global reference to 'app' here
|
||||
# and that it has a dictionary-like 'config' property
|
||||
return app.config["BACKOFF_MAX_TIME"]
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
ValueError,
|
||||
max_time=lookup_max_time)
|
||||
|
||||
Event handlers
|
||||
--------------
|
||||
|
||||
Both backoff decorators optionally accept event handler functions
|
||||
using the keyword arguments ``on_success``, ``on_backoff``, and ``on_giveup``.
|
||||
This may be useful in reporting statistics or performing other custom
|
||||
logging.
|
||||
|
||||
Handlers must be callables with a unary signature accepting a dict
|
||||
argument. This dict contains the details of the invocation. Valid keys
|
||||
include:
|
||||
|
||||
* *target*: reference to the function or method being invoked
|
||||
* *args*: positional arguments to func
|
||||
* *kwargs*: keyword arguments to func
|
||||
* *tries*: number of invocation tries so far
|
||||
* *elapsed*: elapsed time in seconds so far
|
||||
* *wait*: seconds to wait (``on_backoff`` handler only)
|
||||
* *value*: value triggering backoff (``on_predicate`` decorator only)
|
||||
|
||||
A handler which prints the details of the backoff event could be
|
||||
implemented like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def backoff_hdlr(details):
|
||||
print ("Backing off {wait:0.1f} seconds after {tries} tries "
|
||||
"calling function {target} with args {args} and kwargs "
|
||||
"{kwargs}".format(**details))
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
on_backoff=backoff_hdlr)
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
**Multiple handlers per event type**
|
||||
|
||||
In all cases, iterables of handler functions are also accepted, which
|
||||
are called in turn. For example, you might provide a simple list of
|
||||
handler functions as the value of the ``on_backoff`` keyword arg:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
on_backoff=[backoff_hdlr1, backoff_hdlr2])
|
||||
def get_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
**Getting exception info**
|
||||
|
||||
In the case of the ``on_exception`` decorator, all ``on_backoff`` and
|
||||
``on_giveup`` handlers are called from within the except block for the
|
||||
exception being handled. Therefore exception info is available to the
|
||||
handler functions via the python standard library, specifically
|
||||
``sys.exc_info()`` or the ``traceback`` module. The exception is also
|
||||
available at the *exception* key in the `details` dict passed to the
|
||||
handlers.
|
||||
|
||||
Asynchronous code
|
||||
-----------------
|
||||
|
||||
Backoff supports asynchronous execution in Python 3.5 and above.
|
||||
|
||||
To use backoff in asynchronous code based on
|
||||
`asyncio <https://docs.python.org/3/library/asyncio.html>`__
|
||||
you simply need to apply ``backoff.on_exception`` or ``backoff.on_predicate``
|
||||
to coroutines.
|
||||
You can also use coroutines for the ``on_success``, ``on_backoff``, and
|
||||
``on_giveup`` event handlers, with the interface otherwise being identical.
|
||||
|
||||
The following examples use `aiohttp <https://aiohttp.readthedocs.io/>`__
|
||||
asynchronous HTTP client/server library.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo, aiohttp.ClientError, max_time=60)
|
||||
async def get_url(url):
|
||||
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
||||
async with session.get(url) as response:
|
||||
return await response.text()
|
||||
|
||||
Logging configuration
|
||||
---------------------
|
||||
|
||||
By default, backoff and retry attempts are logged to the 'backoff'
|
||||
logger. By default, this logger is configured with a NullHandler, so
|
||||
there will be nothing output unless you configure a handler.
|
||||
Programmatically, this might be accomplished with something as simple
|
||||
as:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
logging.getLogger('backoff').addHandler(logging.StreamHandler())
|
||||
|
||||
The default logging level is INFO, which corresponds to logging
|
||||
anytime a retry event occurs. If you would instead like to log
|
||||
only when a giveup event occurs, set the logger level to ERROR.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
logging.getLogger('backoff').setLevel(logging.ERROR)
|
||||
|
||||
It is also possible to specify an alternate logger with the ``logger``
|
||||
keyword argument. If a string value is specified the logger will be
|
||||
looked up by name.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
logger='my_logger')
|
||||
# ...
|
||||
|
||||
It is also supported to specify a Logger (or LoggerAdapter) object
|
||||
directly.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
my_logger = logging.getLogger('my_logger')
|
||||
my_handler = logging.StreamHandler()
|
||||
my_logger.addHandler(my_handler)
|
||||
my_logger.setLevel(logging.ERROR)
|
||||
|
||||
@backoff.on_exception(backoff.expo,
|
||||
requests.exceptions.RequestException,
|
||||
logger=my_logger)
|
||||
# ...
|
||||
|
||||
Default logging can be disabled all together by specifying
|
||||
``logger=None``. In this case, if desired alternative logging behavior
|
||||
could be defined by using custom event handlers.
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
backoff-2.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
backoff-2.2.1.dist-info/LICENSE,sha256=KmtNX4hNTXob8E6n3xlEzxKzLjWnmobQoHWi0_QPuaw,1077
|
||||
backoff-2.2.1.dist-info/METADATA,sha256=Wgffksy-dcDJ4GaoqXyjc8XxrE0DQz3FbWwmrDqo-6U,14827
|
||||
backoff-2.2.1.dist-info/RECORD,,
|
||||
backoff-2.2.1.dist-info/WHEEL,sha256=gSF7fibx4crkLz_A-IKR6kcuq0jJ64KNCkG8_bcaEao,88
|
||||
backoff/__init__.py,sha256=Jl49Ur_5GTiySyaw8URBXlfClWn0H7Pk5P95m1awNZ8,898
|
||||
backoff/__pycache__/__init__.cpython-310.pyc,,
|
||||
backoff/__pycache__/_async.cpython-310.pyc,,
|
||||
backoff/__pycache__/_common.cpython-310.pyc,,
|
||||
backoff/__pycache__/_decorator.cpython-310.pyc,,
|
||||
backoff/__pycache__/_jitter.cpython-310.pyc,,
|
||||
backoff/__pycache__/_sync.cpython-310.pyc,,
|
||||
backoff/__pycache__/_typing.cpython-310.pyc,,
|
||||
backoff/__pycache__/_wait_gen.cpython-310.pyc,,
|
||||
backoff/__pycache__/types.cpython-310.pyc,,
|
||||
backoff/_async.py,sha256=ZvqmfxxQ2o-UjQUQin12Ojc4eXOXb43RWSQaPaqbALI,6775
|
||||
backoff/_common.py,sha256=8s3_5AJH8hiHd9GR2PdKqiaeE2sdEUoyf6cW9OCo1F8,3478
|
||||
backoff/_decorator.py,sha256=EuYHrg8rSPaKJ_KeZ99WEg9knrfyn_-ck12Cwfcb68U,9804
|
||||
backoff/_jitter.py,sha256=LjJShpjryk9sWBCWiz-3UX1DJCx6rebNJ5Bf3nPMlYQ,782
|
||||
backoff/_sync.py,sha256=DT_ktufPPb0nut9WCAKe5UE7sTYRl9f93PRPX6jP8ro,4214
|
||||
backoff/_typing.py,sha256=RrJ50kqdeNZvSmoMjNoAUpMCm44V8qreAVgGb-KMl-g,1328
|
||||
backoff/_wait_gen.py,sha256=U5AR3Isf4aZs2SC0x9PGI3Wh8JR7XGkV90SiU56wWvw,2396
|
||||
backoff/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
backoff/types.py,sha256=4DGG6Ltcz0wVfXrk0YBOnp_oPpcki4c0BOnodRhgoqg,73
|
|
@ -0,0 +1,4 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: poetry-core 1.2.0
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
|
@ -0,0 +1,30 @@
|
|||
# coding:utf-8
|
||||
"""
|
||||
Function decoration for backoff and retry
|
||||
|
||||
This module provides function decorators which can be used to wrap a
|
||||
function such that it will be retried until some condition is met. It
|
||||
is meant to be of use when accessing unreliable resources with the
|
||||
potential for intermittent failures i.e. network resources and external
|
||||
APIs. Somewhat more generally, it may also be of use for dynamically
|
||||
polling resources for externally generated content.
|
||||
|
||||
For examples and full documentation see the README at
|
||||
https://github.com/litl/backoff
|
||||
"""
|
||||
from backoff._decorator import on_exception, on_predicate
|
||||
from backoff._jitter import full_jitter, random_jitter
|
||||
from backoff._wait_gen import constant, expo, fibo, runtime
|
||||
|
||||
__all__ = [
|
||||
'on_predicate',
|
||||
'on_exception',
|
||||
'constant',
|
||||
'expo',
|
||||
'fibo',
|
||||
'runtime',
|
||||
'full_jitter',
|
||||
'random_jitter',
|
||||
]
|
||||
|
||||
__version__ = "2.2.1"
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,188 @@
|
|||
# coding:utf-8
|
||||
import datetime
|
||||
import functools
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
|
||||
from backoff._common import (_init_wait_gen, _maybe_call, _next_wait)
|
||||
|
||||
|
||||
def _ensure_coroutine(coro_or_func):
|
||||
if asyncio.iscoroutinefunction(coro_or_func):
|
||||
return coro_or_func
|
||||
else:
|
||||
@functools.wraps(coro_or_func)
|
||||
async def f(*args, **kwargs):
|
||||
return coro_or_func(*args, **kwargs)
|
||||
return f
|
||||
|
||||
|
||||
def _ensure_coroutines(coros_or_funcs):
|
||||
return [_ensure_coroutine(f) for f in coros_or_funcs]
|
||||
|
||||
|
||||
async def _call_handlers(handlers,
|
||||
*,
|
||||
target, args, kwargs, tries, elapsed,
|
||||
**extra):
|
||||
details = {
|
||||
'target': target,
|
||||
'args': args,
|
||||
'kwargs': kwargs,
|
||||
'tries': tries,
|
||||
'elapsed': elapsed,
|
||||
}
|
||||
details.update(extra)
|
||||
for handler in handlers:
|
||||
await handler(details)
|
||||
|
||||
|
||||
def retry_predicate(target, wait_gen, predicate,
|
||||
*,
|
||||
max_tries, max_time, jitter,
|
||||
on_success, on_backoff, on_giveup,
|
||||
wait_gen_kwargs):
|
||||
on_success = _ensure_coroutines(on_success)
|
||||
on_backoff = _ensure_coroutines(on_backoff)
|
||||
on_giveup = _ensure_coroutines(on_giveup)
|
||||
|
||||
# Easy to implement, please report if you need this.
|
||||
assert not asyncio.iscoroutinefunction(max_tries)
|
||||
assert not asyncio.iscoroutinefunction(jitter)
|
||||
|
||||
assert asyncio.iscoroutinefunction(target)
|
||||
|
||||
@functools.wraps(target)
|
||||
async def retry(*args, **kwargs):
|
||||
|
||||
# update variables from outer function args
|
||||
max_tries_value = _maybe_call(max_tries)
|
||||
max_time_value = _maybe_call(max_time)
|
||||
|
||||
tries = 0
|
||||
start = datetime.datetime.now()
|
||||
wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
|
||||
while True:
|
||||
tries += 1
|
||||
elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
|
||||
details = {
|
||||
"target": target,
|
||||
"args": args,
|
||||
"kwargs": kwargs,
|
||||
"tries": tries,
|
||||
"elapsed": elapsed,
|
||||
}
|
||||
|
||||
ret = await target(*args, **kwargs)
|
||||
if predicate(ret):
|
||||
max_tries_exceeded = (tries == max_tries_value)
|
||||
max_time_exceeded = (max_time_value is not None and
|
||||
elapsed >= max_time_value)
|
||||
|
||||
if max_tries_exceeded or max_time_exceeded:
|
||||
await _call_handlers(on_giveup, **details, value=ret)
|
||||
break
|
||||
|
||||
try:
|
||||
seconds = _next_wait(wait, ret, jitter, elapsed,
|
||||
max_time_value)
|
||||
except StopIteration:
|
||||
await _call_handlers(on_giveup, **details, value=ret)
|
||||
break
|
||||
|
||||
await _call_handlers(on_backoff, **details, value=ret,
|
||||
wait=seconds)
|
||||
|
||||
# Note: there is no convenient way to pass explicit event
|
||||
# loop to decorator, so here we assume that either default
|
||||
# thread event loop is set and correct (it mostly is
|
||||
# by default), or Python >= 3.5.3 or Python >= 3.6 is used
|
||||
# where loop.get_event_loop() in coroutine guaranteed to
|
||||
# return correct value.
|
||||
# See for details:
|
||||
# <https://groups.google.com/forum/#!topic/python-tulip/yF9C-rFpiKk>
|
||||
# <https://bugs.python.org/issue28613>
|
||||
await asyncio.sleep(seconds)
|
||||
continue
|
||||
else:
|
||||
await _call_handlers(on_success, **details, value=ret)
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
return retry
|
||||
|
||||
|
||||
def retry_exception(target, wait_gen, exception,
|
||||
*,
|
||||
max_tries, max_time, jitter, giveup,
|
||||
on_success, on_backoff, on_giveup, raise_on_giveup,
|
||||
wait_gen_kwargs):
|
||||
on_success = _ensure_coroutines(on_success)
|
||||
on_backoff = _ensure_coroutines(on_backoff)
|
||||
on_giveup = _ensure_coroutines(on_giveup)
|
||||
giveup = _ensure_coroutine(giveup)
|
||||
|
||||
# Easy to implement, please report if you need this.
|
||||
assert not asyncio.iscoroutinefunction(max_tries)
|
||||
assert not asyncio.iscoroutinefunction(jitter)
|
||||
|
||||
@functools.wraps(target)
|
||||
async def retry(*args, **kwargs):
|
||||
|
||||
max_tries_value = _maybe_call(max_tries)
|
||||
max_time_value = _maybe_call(max_time)
|
||||
|
||||
tries = 0
|
||||
start = datetime.datetime.now()
|
||||
wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
|
||||
while True:
|
||||
tries += 1
|
||||
elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
|
||||
details = {
|
||||
"target": target,
|
||||
"args": args,
|
||||
"kwargs": kwargs,
|
||||
"tries": tries,
|
||||
"elapsed": elapsed,
|
||||
}
|
||||
|
||||
try:
|
||||
ret = await target(*args, **kwargs)
|
||||
except exception as e:
|
||||
giveup_result = await giveup(e)
|
||||
max_tries_exceeded = (tries == max_tries_value)
|
||||
max_time_exceeded = (max_time_value is not None and
|
||||
elapsed >= max_time_value)
|
||||
|
||||
if giveup_result or max_tries_exceeded or max_time_exceeded:
|
||||
await _call_handlers(on_giveup, **details, exception=e)
|
||||
if raise_on_giveup:
|
||||
raise
|
||||
return None
|
||||
|
||||
try:
|
||||
seconds = _next_wait(wait, e, jitter, elapsed,
|
||||
max_time_value)
|
||||
except StopIteration:
|
||||
await _call_handlers(on_giveup, **details, exception=e)
|
||||
raise e
|
||||
|
||||
await _call_handlers(on_backoff, **details, wait=seconds,
|
||||
exception=e)
|
||||
|
||||
# Note: there is no convenient way to pass explicit event
|
||||
# loop to decorator, so here we assume that either default
|
||||
# thread event loop is set and correct (it mostly is
|
||||
# by default), or Python >= 3.5.3 or Python >= 3.6 is used
|
||||
# where loop.get_event_loop() in coroutine guaranteed to
|
||||
# return correct value.
|
||||
# See for details:
|
||||
# <https://groups.google.com/forum/#!topic/python-tulip/yF9C-rFpiKk>
|
||||
# <https://bugs.python.org/issue28613>
|
||||
await asyncio.sleep(seconds)
|
||||
else:
|
||||
await _call_handlers(on_success, **details)
|
||||
|
||||
return ret
|
||||
return retry
|
|
@ -0,0 +1,120 @@
|
|||
# coding:utf-8
|
||||
|
||||
import functools
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
import warnings
|
||||
|
||||
|
||||
# Use module-specific logger with a default null handler.
|
||||
_logger = logging.getLogger('backoff')
|
||||
_logger.addHandler(logging.NullHandler()) # pragma: no cover
|
||||
_logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
# Evaluate arg that can be either a fixed value or a callable.
|
||||
def _maybe_call(f, *args, **kwargs):
|
||||
if callable(f):
|
||||
try:
|
||||
return f(*args, **kwargs)
|
||||
except TypeError:
|
||||
return f
|
||||
else:
|
||||
return f
|
||||
|
||||
|
||||
def _init_wait_gen(wait_gen, wait_gen_kwargs):
|
||||
kwargs = {k: _maybe_call(v) for k, v in wait_gen_kwargs.items()}
|
||||
initialized = wait_gen(**kwargs)
|
||||
initialized.send(None) # Initialize with an empty send
|
||||
return initialized
|
||||
|
||||
|
||||
def _next_wait(wait, send_value, jitter, elapsed, max_time):
|
||||
value = wait.send(send_value)
|
||||
try:
|
||||
if jitter is not None:
|
||||
seconds = jitter(value)
|
||||
else:
|
||||
seconds = value
|
||||
except TypeError:
|
||||
warnings.warn(
|
||||
"Nullary jitter function signature is deprecated. Use "
|
||||
"unary signature accepting a wait value in seconds and "
|
||||
"returning a jittered version of it.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
seconds = value + jitter()
|
||||
|
||||
# don't sleep longer than remaining allotted max_time
|
||||
if max_time is not None:
|
||||
seconds = min(seconds, max_time - elapsed)
|
||||
|
||||
return seconds
|
||||
|
||||
|
||||
def _prepare_logger(logger):
|
||||
if isinstance(logger, str):
|
||||
logger = logging.getLogger(logger)
|
||||
return logger
|
||||
|
||||
|
||||
# Configure handler list with user specified handler and optionally
|
||||
# with a default handler bound to the specified logger.
|
||||
def _config_handlers(
|
||||
user_handlers, *, default_handler=None, logger=None, log_level=None
|
||||
):
|
||||
handlers = []
|
||||
if logger is not None:
|
||||
assert log_level is not None, "Log level is not specified"
|
||||
# bind the specified logger to the default log handler
|
||||
log_handler = functools.partial(
|
||||
default_handler, logger=logger, log_level=log_level
|
||||
)
|
||||
handlers.append(log_handler)
|
||||
|
||||
if user_handlers is None:
|
||||
return handlers
|
||||
|
||||
# user specified handlers can either be an iterable of handlers
|
||||
# or a single handler. either way append them to the list.
|
||||
if hasattr(user_handlers, '__iter__'):
|
||||
# add all handlers in the iterable
|
||||
handlers += list(user_handlers)
|
||||
else:
|
||||
# append a single handler
|
||||
handlers.append(user_handlers)
|
||||
|
||||
return handlers
|
||||
|
||||
|
||||
# Default backoff handler
|
||||
def _log_backoff(details, logger, log_level):
|
||||
msg = "Backing off %s(...) for %.1fs (%s)"
|
||||
log_args = [details['target'].__name__, details['wait']]
|
||||
|
||||
exc_typ, exc, _ = sys.exc_info()
|
||||
if exc is not None:
|
||||
exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
|
||||
log_args.append(exc_fmt.rstrip("\n"))
|
||||
else:
|
||||
log_args.append(details['value'])
|
||||
logger.log(log_level, msg, *log_args)
|
||||
|
||||
|
||||
# Default giveup handler
|
||||
def _log_giveup(details, logger, log_level):
|
||||
msg = "Giving up %s(...) after %d tries (%s)"
|
||||
log_args = [details['target'].__name__, details['tries']]
|
||||
|
||||
exc_typ, exc, _ = sys.exc_info()
|
||||
if exc is not None:
|
||||
exc_fmt = traceback.format_exception_only(exc_typ, exc)[-1]
|
||||
log_args.append(exc_fmt.rstrip("\n"))
|
||||
else:
|
||||
log_args.append(details['value'])
|
||||
|
||||
logger.log(log_level, msg, *log_args)
|
|
@ -0,0 +1,222 @@
|
|||
# coding:utf-8
|
||||
import asyncio
|
||||
import logging
|
||||
import operator
|
||||
from typing import Any, Callable, Iterable, Optional, Type, Union
|
||||
|
||||
from backoff._common import (
|
||||
_prepare_logger,
|
||||
_config_handlers,
|
||||
_log_backoff,
|
||||
_log_giveup
|
||||
)
|
||||
from backoff._jitter import full_jitter
|
||||
from backoff import _async, _sync
|
||||
from backoff._typing import (
|
||||
_CallableT,
|
||||
_Handler,
|
||||
_Jitterer,
|
||||
_MaybeCallable,
|
||||
_MaybeLogger,
|
||||
_MaybeSequence,
|
||||
_Predicate,
|
||||
_WaitGenerator,
|
||||
)
|
||||
|
||||
|
||||
def on_predicate(wait_gen: _WaitGenerator,
|
||||
predicate: _Predicate[Any] = operator.not_,
|
||||
*,
|
||||
max_tries: Optional[_MaybeCallable[int]] = None,
|
||||
max_time: Optional[_MaybeCallable[float]] = None,
|
||||
jitter: Union[_Jitterer, None] = full_jitter,
|
||||
on_success: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
on_backoff: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
on_giveup: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
logger: _MaybeLogger = 'backoff',
|
||||
backoff_log_level: int = logging.INFO,
|
||||
giveup_log_level: int = logging.ERROR,
|
||||
**wait_gen_kwargs: Any) -> Callable[[_CallableT], _CallableT]:
|
||||
"""Returns decorator for backoff and retry triggered by predicate.
|
||||
|
||||
Args:
|
||||
wait_gen: A generator yielding successive wait times in
|
||||
seconds.
|
||||
predicate: A function which when called on the return value of
|
||||
the target function will trigger backoff when considered
|
||||
truthily. If not specified, the default behavior is to
|
||||
backoff on falsey return values.
|
||||
max_tries: The maximum number of attempts to make before giving
|
||||
up. In the case of failure, the result of the last attempt
|
||||
will be returned. The default value of None means there
|
||||
is no limit to the number of tries. If a callable is passed,
|
||||
it will be evaluated at runtime and its return value used.
|
||||
max_time: The maximum total amount of time to try for before
|
||||
giving up. If this time expires, the result of the last
|
||||
attempt will be returned. If a callable is passed, it will
|
||||
be evaluated at runtime and its return value used.
|
||||
jitter: A function of the value yielded by wait_gen returning
|
||||
the actual time to wait. This distributes wait times
|
||||
stochastically in order to avoid timing collisions across
|
||||
concurrent clients. Wait times are jittered by default
|
||||
using the full_jitter function. Jittering may be disabled
|
||||
altogether by passing jitter=None.
|
||||
on_success: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event of success. The
|
||||
parameter is a dict containing details about the invocation.
|
||||
on_backoff: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event of a backoff. The
|
||||
parameter is a dict containing details about the invocation.
|
||||
on_giveup: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event that max_tries
|
||||
is exceeded. The parameter is a dict containing details
|
||||
about the invocation.
|
||||
logger: Name of logger or Logger object to log to. Defaults to
|
||||
'backoff'.
|
||||
backoff_log_level: log level for the backoff event. Defaults to "INFO"
|
||||
giveup_log_level: log level for the give up event. Defaults to "ERROR"
|
||||
**wait_gen_kwargs: Any additional keyword args specified will be
|
||||
passed to wait_gen when it is initialized. Any callable
|
||||
args will first be evaluated and their return values passed.
|
||||
This is useful for runtime configuration.
|
||||
"""
|
||||
def decorate(target):
|
||||
nonlocal logger, on_success, on_backoff, on_giveup
|
||||
|
||||
logger = _prepare_logger(logger)
|
||||
on_success = _config_handlers(on_success)
|
||||
on_backoff = _config_handlers(
|
||||
on_backoff,
|
||||
default_handler=_log_backoff,
|
||||
logger=logger,
|
||||
log_level=backoff_log_level
|
||||
)
|
||||
on_giveup = _config_handlers(
|
||||
on_giveup,
|
||||
default_handler=_log_giveup,
|
||||
logger=logger,
|
||||
log_level=giveup_log_level
|
||||
)
|
||||
|
||||
if asyncio.iscoroutinefunction(target):
|
||||
retry = _async.retry_predicate
|
||||
else:
|
||||
retry = _sync.retry_predicate
|
||||
|
||||
return retry(
|
||||
target,
|
||||
wait_gen,
|
||||
predicate,
|
||||
max_tries=max_tries,
|
||||
max_time=max_time,
|
||||
jitter=jitter,
|
||||
on_success=on_success,
|
||||
on_backoff=on_backoff,
|
||||
on_giveup=on_giveup,
|
||||
wait_gen_kwargs=wait_gen_kwargs
|
||||
)
|
||||
|
||||
# Return a function which decorates a target with a retry loop.
|
||||
return decorate
|
||||
|
||||
|
||||
def on_exception(wait_gen: _WaitGenerator,
|
||||
exception: _MaybeSequence[Type[Exception]],
|
||||
*,
|
||||
max_tries: Optional[_MaybeCallable[int]] = None,
|
||||
max_time: Optional[_MaybeCallable[float]] = None,
|
||||
jitter: Union[_Jitterer, None] = full_jitter,
|
||||
giveup: _Predicate[Exception] = lambda e: False,
|
||||
on_success: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
on_backoff: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
on_giveup: Union[_Handler, Iterable[_Handler], None] = None,
|
||||
raise_on_giveup: bool = True,
|
||||
logger: _MaybeLogger = 'backoff',
|
||||
backoff_log_level: int = logging.INFO,
|
||||
giveup_log_level: int = logging.ERROR,
|
||||
**wait_gen_kwargs: Any) -> Callable[[_CallableT], _CallableT]:
|
||||
"""Returns decorator for backoff and retry triggered by exception.
|
||||
|
||||
Args:
|
||||
wait_gen: A generator yielding successive wait times in
|
||||
seconds.
|
||||
exception: An exception type (or tuple of types) which triggers
|
||||
backoff.
|
||||
max_tries: The maximum number of attempts to make before giving
|
||||
up. Once exhausted, the exception will be allowed to escape.
|
||||
The default value of None means there is no limit to the
|
||||
number of tries. If a callable is passed, it will be
|
||||
evaluated at runtime and its return value used.
|
||||
max_time: The maximum total amount of time to try for before
|
||||
giving up. Once expired, the exception will be allowed to
|
||||
escape. If a callable is passed, it will be
|
||||
evaluated at runtime and its return value used.
|
||||
jitter: A function of the value yielded by wait_gen returning
|
||||
the actual time to wait. This distributes wait times
|
||||
stochastically in order to avoid timing collisions across
|
||||
concurrent clients. Wait times are jittered by default
|
||||
using the full_jitter function. Jittering may be disabled
|
||||
altogether by passing jitter=None.
|
||||
giveup: Function accepting an exception instance and
|
||||
returning whether or not to give up. Optional. The default
|
||||
is to always continue.
|
||||
on_success: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event of success. The
|
||||
parameter is a dict containing details about the invocation.
|
||||
on_backoff: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event of a backoff. The
|
||||
parameter is a dict containing details about the invocation.
|
||||
on_giveup: Callable (or iterable of callables) with a unary
|
||||
signature to be called in the event that max_tries
|
||||
is exceeded. The parameter is a dict containing details
|
||||
about the invocation.
|
||||
raise_on_giveup: Boolean indicating whether the registered exceptions
|
||||
should be raised on giveup. Defaults to `True`
|
||||
logger: Name or Logger object to log to. Defaults to 'backoff'.
|
||||
backoff_log_level: log level for the backoff event. Defaults to "INFO"
|
||||
giveup_log_level: log level for the give up event. Defaults to "ERROR"
|
||||
**wait_gen_kwargs: Any additional keyword args specified will be
|
||||
passed to wait_gen when it is initialized. Any callable
|
||||
args will first be evaluated and their return values passed.
|
||||
This is useful for runtime configuration.
|
||||
"""
|
||||
def decorate(target):
|
||||
nonlocal logger, on_success, on_backoff, on_giveup
|
||||
|
||||
logger = _prepare_logger(logger)
|
||||
on_success = _config_handlers(on_success)
|
||||
on_backoff = _config_handlers(
|
||||
on_backoff,
|
||||
default_handler=_log_backoff,
|
||||
logger=logger,
|
||||
log_level=backoff_log_level,
|
||||
)
|
||||
on_giveup = _config_handlers(
|
||||
on_giveup,
|
||||
default_handler=_log_giveup,
|
||||
logger=logger,
|
||||
log_level=giveup_log_level,
|
||||
)
|
||||
|
||||
if asyncio.iscoroutinefunction(target):
|
||||
retry = _async.retry_exception
|
||||
else:
|
||||
retry = _sync.retry_exception
|
||||
|
||||
return retry(
|
||||
target,
|
||||
wait_gen,
|
||||
exception,
|
||||
max_tries=max_tries,
|
||||
max_time=max_time,
|
||||
jitter=jitter,
|
||||
giveup=giveup,
|
||||
on_success=on_success,
|
||||
on_backoff=on_backoff,
|
||||
on_giveup=on_giveup,
|
||||
raise_on_giveup=raise_on_giveup,
|
||||
wait_gen_kwargs=wait_gen_kwargs
|
||||
)
|
||||
|
||||
# Return a function which decorates a target with a retry loop.
|
||||
return decorate
|
|
@ -0,0 +1,28 @@
|
|||
# coding:utf-8
|
||||
|
||||
import random
|
||||
|
||||
|
||||
def random_jitter(value: float) -> float:
|
||||
"""Jitter the value a random number of milliseconds.
|
||||
|
||||
This adds up to 1 second of additional time to the original value.
|
||||
Prior to backoff version 1.2 this was the default jitter behavior.
|
||||
|
||||
Args:
|
||||
value: The unadulterated backoff value.
|
||||
"""
|
||||
return value + random.random()
|
||||
|
||||
|
||||
def full_jitter(value: float) -> float:
|
||||
"""Jitter the value across the full range (0 to value).
|
||||
|
||||
This corresponds to the "Full Jitter" algorithm specified in the
|
||||
AWS blog's post on the performance of various jitter algorithms.
|
||||
(http://www.awsarchitectureblog.com/2015/03/backoff.html)
|
||||
|
||||
Args:
|
||||
value: The unadulterated backoff value.
|
||||
"""
|
||||
return random.uniform(0, value)
|
|
@ -0,0 +1,132 @@
|
|||
# coding:utf-8
|
||||
import datetime
|
||||
import functools
|
||||
import time
|
||||
from datetime import timedelta
|
||||
|
||||
from backoff._common import (_init_wait_gen, _maybe_call, _next_wait)
|
||||
|
||||
|
||||
def _call_handlers(hdlrs, target, args, kwargs, tries, elapsed, **extra):
|
||||
details = {
|
||||
'target': target,
|
||||
'args': args,
|
||||
'kwargs': kwargs,
|
||||
'tries': tries,
|
||||
'elapsed': elapsed,
|
||||
}
|
||||
details.update(extra)
|
||||
for hdlr in hdlrs:
|
||||
hdlr(details)
|
||||
|
||||
|
||||
def retry_predicate(target, wait_gen, predicate,
|
||||
*,
|
||||
max_tries, max_time, jitter,
|
||||
on_success, on_backoff, on_giveup,
|
||||
wait_gen_kwargs):
|
||||
|
||||
@functools.wraps(target)
|
||||
def retry(*args, **kwargs):
|
||||
max_tries_value = _maybe_call(max_tries)
|
||||
max_time_value = _maybe_call(max_time)
|
||||
|
||||
tries = 0
|
||||
start = datetime.datetime.now()
|
||||
wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
|
||||
while True:
|
||||
tries += 1
|
||||
elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
|
||||
details = {
|
||||
"target": target,
|
||||
"args": args,
|
||||
"kwargs": kwargs,
|
||||
"tries": tries,
|
||||
"elapsed": elapsed,
|
||||
}
|
||||
|
||||
ret = target(*args, **kwargs)
|
||||
if predicate(ret):
|
||||
max_tries_exceeded = (tries == max_tries_value)
|
||||
max_time_exceeded = (max_time_value is not None and
|
||||
elapsed >= max_time_value)
|
||||
|
||||
if max_tries_exceeded or max_time_exceeded:
|
||||
_call_handlers(on_giveup, **details, value=ret)
|
||||
break
|
||||
|
||||
try:
|
||||
seconds = _next_wait(wait, ret, jitter, elapsed,
|
||||
max_time_value)
|
||||
except StopIteration:
|
||||
_call_handlers(on_giveup, **details)
|
||||
break
|
||||
|
||||
_call_handlers(on_backoff, **details,
|
||||
value=ret, wait=seconds)
|
||||
|
||||
time.sleep(seconds)
|
||||
continue
|
||||
else:
|
||||
_call_handlers(on_success, **details, value=ret)
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
return retry
|
||||
|
||||
|
||||
def retry_exception(target, wait_gen, exception,
|
||||
*,
|
||||
max_tries, max_time, jitter, giveup,
|
||||
on_success, on_backoff, on_giveup, raise_on_giveup,
|
||||
wait_gen_kwargs):
|
||||
|
||||
@functools.wraps(target)
|
||||
def retry(*args, **kwargs):
|
||||
max_tries_value = _maybe_call(max_tries)
|
||||
max_time_value = _maybe_call(max_time)
|
||||
|
||||
tries = 0
|
||||
start = datetime.datetime.now()
|
||||
wait = _init_wait_gen(wait_gen, wait_gen_kwargs)
|
||||
while True:
|
||||
tries += 1
|
||||
elapsed = timedelta.total_seconds(datetime.datetime.now() - start)
|
||||
details = {
|
||||
"target": target,
|
||||
"args": args,
|
||||
"kwargs": kwargs,
|
||||
"tries": tries,
|
||||
"elapsed": elapsed,
|
||||
}
|
||||
|
||||
try:
|
||||
ret = target(*args, **kwargs)
|
||||
except exception as e:
|
||||
max_tries_exceeded = (tries == max_tries_value)
|
||||
max_time_exceeded = (max_time_value is not None and
|
||||
elapsed >= max_time_value)
|
||||
|
||||
if giveup(e) or max_tries_exceeded or max_time_exceeded:
|
||||
_call_handlers(on_giveup, **details, exception=e)
|
||||
if raise_on_giveup:
|
||||
raise
|
||||
return None
|
||||
|
||||
try:
|
||||
seconds = _next_wait(wait, e, jitter, elapsed,
|
||||
max_time_value)
|
||||
except StopIteration:
|
||||
_call_handlers(on_giveup, **details, exception=e)
|
||||
raise e
|
||||
|
||||
_call_handlers(on_backoff, **details, wait=seconds,
|
||||
exception=e)
|
||||
|
||||
time.sleep(seconds)
|
||||
else:
|
||||
_call_handlers(on_success, **details)
|
||||
|
||||
return ret
|
||||
return retry
|
|
@ -0,0 +1,44 @@
|
|||
# coding:utf-8
|
||||
import logging
|
||||
import sys
|
||||
from typing import (Any, Callable, Coroutine, Dict, Generator, Sequence, Tuple,
|
||||
TypeVar, Union)
|
||||
|
||||
if sys.version_info >= (3, 8): # pragma: no cover
|
||||
from typing import TypedDict
|
||||
else: # pragma: no cover
|
||||
# use typing_extensions if installed but don't require it
|
||||
try:
|
||||
from typing_extensions import TypedDict
|
||||
except ImportError:
|
||||
class TypedDict(dict):
|
||||
def __init_subclass__(cls, **kwargs: Any) -> None:
|
||||
return super().__init_subclass__()
|
||||
|
||||
|
||||
class _Details(TypedDict):
|
||||
target: Callable[..., Any]
|
||||
args: Tuple[Any, ...]
|
||||
kwargs: Dict[str, Any]
|
||||
tries: int
|
||||
elapsed: float
|
||||
|
||||
|
||||
class Details(_Details, total=False):
|
||||
wait: float # present in the on_backoff handler case for either decorator
|
||||
value: Any # present in the on_predicate decorator case
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
_CallableT = TypeVar('_CallableT', bound=Callable[..., Any])
|
||||
_Handler = Union[
|
||||
Callable[[Details], None],
|
||||
Callable[[Details], Coroutine[Any, Any, None]],
|
||||
]
|
||||
_Jitterer = Callable[[float], float]
|
||||
_MaybeCallable = Union[T, Callable[[], T]]
|
||||
_MaybeLogger = Union[str, logging.Logger, None]
|
||||
_MaybeSequence = Union[T, Sequence[T]]
|
||||
_Predicate = Callable[[T], bool]
|
||||
_WaitGenerator = Callable[..., Generator[float, None, None]]
|
|
@ -0,0 +1,89 @@
|
|||
# coding:utf-8
|
||||
|
||||
import itertools
|
||||
from typing import Any, Callable, Generator, Iterable, Optional, Union
|
||||
|
||||
|
||||
def expo(
|
||||
base: float = 2,
|
||||
factor: float = 1,
|
||||
max_value: Optional[float] = None
|
||||
) -> Generator[float, Any, None]:
|
||||
|
||||
"""Generator for exponential decay.
|
||||
|
||||
Args:
|
||||
base: The mathematical base of the exponentiation operation
|
||||
factor: Factor to multiply the exponentiation by.
|
||||
max_value: The maximum value to yield. Once the value in the
|
||||
true exponential sequence exceeds this, the value
|
||||
of max_value will forever after be yielded.
|
||||
"""
|
||||
# Advance past initial .send() call
|
||||
yield # type: ignore[misc]
|
||||
n = 0
|
||||
while True:
|
||||
a = factor * base ** n
|
||||
if max_value is None or a < max_value:
|
||||
yield a
|
||||
n += 1
|
||||
else:
|
||||
yield max_value
|
||||
|
||||
|
||||
def fibo(max_value: Optional[int] = None) -> Generator[int, None, None]:
|
||||
"""Generator for fibonaccial decay.
|
||||
|
||||
Args:
|
||||
max_value: The maximum value to yield. Once the value in the
|
||||
true fibonacci sequence exceeds this, the value
|
||||
of max_value will forever after be yielded.
|
||||
"""
|
||||
# Advance past initial .send() call
|
||||
yield # type: ignore[misc]
|
||||
|
||||
a = 1
|
||||
b = 1
|
||||
while True:
|
||||
if max_value is None or a < max_value:
|
||||
yield a
|
||||
a, b = b, a + b
|
||||
else:
|
||||
yield max_value
|
||||
|
||||
|
||||
def constant(
|
||||
interval: Union[int, Iterable[float]] = 1
|
||||
) -> Generator[float, None, None]:
|
||||
"""Generator for constant intervals.
|
||||
|
||||
Args:
|
||||
interval: A constant value to yield or an iterable of such values.
|
||||
"""
|
||||
# Advance past initial .send() call
|
||||
yield # type: ignore[misc]
|
||||
|
||||
try:
|
||||
itr = iter(interval) # type: ignore
|
||||
except TypeError:
|
||||
itr = itertools.repeat(interval) # type: ignore
|
||||
|
||||
for val in itr:
|
||||
yield val
|
||||
|
||||
|
||||
def runtime(
|
||||
*,
|
||||
value: Callable[[Any], float]
|
||||
) -> Generator[float, None, None]:
|
||||
"""Generator that is based on parsing the return value or thrown
|
||||
exception of the decorated method
|
||||
|
||||
Args:
|
||||
value: a callable which takes as input the decorated
|
||||
function's return value or thrown exception and
|
||||
determines how long to wait
|
||||
"""
|
||||
ret_or_exc = yield # type: ignore[misc]
|
||||
while True:
|
||||
ret_or_exc = yield value(ret_or_exc)
|
|
@ -0,0 +1,6 @@
|
|||
# coding:utf-8
|
||||
from ._typing import Details
|
||||
|
||||
__all__ = [
|
||||
'Details'
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
pip
|
|
@ -0,0 +1,20 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: bson
|
||||
Version: 0.5.10
|
||||
Summary: BSON codec for Python
|
||||
Home-page: http://github.com/py-bson/bson
|
||||
Author: Ayun Park
|
||||
Author-email: iamparkayun@gmail.com
|
||||
License: BSD
|
||||
Keywords: BSON codec
|
||||
Platform: Any
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Requires-Dist: python-dateutil >=2.4.0
|
||||
Requires-Dist: six >=1.9.0
|
||||
|
||||
Independent BSON codec for Python that doesn't depend on MongoDB.
|
|
@ -0,0 +1,17 @@
|
|||
bson-0.5.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
bson-0.5.10.dist-info/METADATA,sha256=uz-I5Pr5KTouXYuojELN-DIpxwYS91BnJq3qkSsXDEc,657
|
||||
bson-0.5.10.dist-info/RECORD,,
|
||||
bson-0.5.10.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
||||
bson-0.5.10.dist-info/top_level.txt,sha256=SndJcRKceJ1z6Wujx0zp_fVam-mKGGJYI7vJvCLNK4o,5
|
||||
bson/__init__.py,sha256=sumv2aJaj2UZKfWvDPKZ2rfSiatYWpZdZw9w-4OE6ac,2264
|
||||
bson/__pycache__/__init__.cpython-310.pyc,,
|
||||
bson/__pycache__/codec.cpython-310.pyc,,
|
||||
bson/__pycache__/network.cpython-310.pyc,,
|
||||
bson/__pycache__/objectid.cpython-310.pyc,,
|
||||
bson/__pycache__/py3compat.cpython-310.pyc,,
|
||||
bson/__pycache__/tz_util.cpython-310.pyc,,
|
||||
bson/codec.py,sha256=UlQ9jZhajCF-Yx9R3-GdS_2X0AYvGDJzzIUaXyeJAI0,12976
|
||||
bson/network.py,sha256=7_V25J42d-mUOvHOlEOx6QYwP5wmQRoyqcO0kfs4Gls,1569
|
||||
bson/objectid.py,sha256=AObuQF2dEOrgtJSatD2aHkcTip2fgoVFMTjbPOqSsSk,10004
|
||||
bson/py3compat.py,sha256=uRu5fXc9lx9toavXYcKUf5FXN3R26mtNi4PkZQTCcTc,2276
|
||||
bson/tz_util.py,sha256=Zy_bA8x2YWrTbIx08HQYYJVghKKwChcCkO4VSBwaNVU,1518
|
|
@ -0,0 +1,5 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.43.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1 @@
|
|||
bson
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/python -OOOO
|
||||
# vim: set fileencoding=utf8 shiftwidth=4 tabstop=4 textwidth=80 foldmethod=marker :
|
||||
# Copyright (c) 2010, Kou Man Tong. All rights reserved.
|
||||
# For licensing, see LICENSE file included in the package.
|
||||
"""
|
||||
BSON serialization and deserialization logic.
|
||||
Specifications taken from: http://bsonspec.org/#/specification
|
||||
The following types are unsupported, because for data exchange purposes, they're
|
||||
over-engineered:
|
||||
0x06 (Undefined)
|
||||
0x0b (Regex - Exactly which flavor do you want? Better let higher level
|
||||
programmers make that decision.)
|
||||
0x0c (DBPointer)
|
||||
0x0d (JavaScript code)
|
||||
0x0e (Symbol)
|
||||
0x0f (JS w/ scope)
|
||||
0x11 (MongoDB-specific timestamp)
|
||||
|
||||
For binaries, only the default 0x0 type is supported.
|
||||
"""
|
||||
|
||||
from .codec import *
|
||||
from .objectid import ObjectId
|
||||
|
||||
__all__ = ["loads", "dumps"]
|
||||
|
||||
|
||||
def dumps(obj, generator=None, on_unknown=None):
|
||||
"""
|
||||
Given a dict, outputs a BSON string.
|
||||
|
||||
generator is an optional function which accepts the dictionary/array being
|
||||
encoded, the current DFS traversal stack, and outputs an iterator indicating
|
||||
the correct encoding order for keys.
|
||||
"""
|
||||
if isinstance(obj, BSONCoding):
|
||||
return encode_object(obj, [],
|
||||
generator_func=generator, on_unknown=on_unknown)
|
||||
return encode_document(obj, [],
|
||||
generator_func=generator, on_unknown=on_unknown)
|
||||
|
||||
|
||||
def loads(data):
|
||||
"""
|
||||
Given a BSON string, outputs a dict.
|
||||
"""
|
||||
return decode_document(data, 0)[1]
|
||||
|
||||
|
||||
def patch_socket():
|
||||
"""
|
||||
Patches the Python socket class such that sockets can send and receive BSON
|
||||
objects atomically.
|
||||
|
||||
This adds the following functions to socket:
|
||||
|
||||
recvbytes(bytes_needed, sock_buf = None) - reads bytes_needed bytes
|
||||
atomically. Returns None if socket closed.
|
||||
|
||||
recvobj() - reads a BSON document from the socket atomically and returns
|
||||
the deserialized dictionary. Returns None if socket closed.
|
||||
|
||||
sendobj(obj) - sends a BSON document to the socket atomically.
|
||||
"""
|
||||
from socket import socket
|
||||
from .network import recvbytes, recvobj, sendobj
|
||||
socket.recvbytes = recvbytes
|
||||
socket.recvobj = recvobj
|
||||
socket.sendobj = sendobj
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,400 @@
|
|||
#!/usr/bin/python -OOOO
|
||||
# vim: set fileencoding=utf8 shiftwidth=4 tabstop=4 textwidth=80 foldmethod=marker :
|
||||
# Copyright (c) 2010, Kou Man Tong. All rights reserved.
|
||||
# Copyright (c) 2015, Ayun Park. All rights reserved.
|
||||
# For licensing, see LICENSE file included in the package.
|
||||
"""
|
||||
Base codec functions for bson.
|
||||
"""
|
||||
import struct
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from uuid import UUID
|
||||
from decimal import Decimal
|
||||
try:
|
||||
from io import BytesIO as StringIO
|
||||
except ImportError:
|
||||
from cStringIO import StringIO
|
||||
|
||||
import calendar
|
||||
from dateutil.tz import tzutc
|
||||
from binascii import b2a_hex
|
||||
|
||||
from six import integer_types, iterkeys, text_type, PY3
|
||||
from six.moves import xrange
|
||||
|
||||
|
||||
utc = tzutc()
|
||||
|
||||
class MissingClassDefinition(ValueError):
|
||||
def __init__(self, class_name):
|
||||
super(MissingClassDefinition,
|
||||
self).__init__("No class definition for class %s" % (class_name,))
|
||||
|
||||
|
||||
class UnknownSerializerError(ValueError):
|
||||
def __init__(self, key, value):
|
||||
super(UnknownSerializerError,
|
||||
self).__init__("Unable to serialize: key '%s' value: %s type: %s" % (key,value, type(value)))
|
||||
|
||||
|
||||
class MissingTimezoneWarning(RuntimeWarning):
|
||||
def __init__(self, *args):
|
||||
args = list(args)
|
||||
if len(args) < 1:
|
||||
args.append("Input datetime object has no tzinfo, assuming UTC.")
|
||||
super(MissingTimezoneWarning, self).__init__(*args)
|
||||
|
||||
|
||||
class TraversalStep(object):
|
||||
def __init__(self, parent, key):
|
||||
self.parent = parent
|
||||
self.key = key
|
||||
|
||||
|
||||
class BSONCoding(object):
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def bson_encode(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def bson_init(self, raw_values):
|
||||
pass
|
||||
|
||||
|
||||
classes = {}
|
||||
|
||||
|
||||
def import_class(cls):
|
||||
if not issubclass(cls, BSONCoding):
|
||||
return
|
||||
|
||||
global classes
|
||||
classes[cls.__name__] = cls
|
||||
|
||||
|
||||
def import_classes(*args):
|
||||
for cls in args:
|
||||
import_class(cls)
|
||||
|
||||
|
||||
def import_classes_from_modules(*args):
|
||||
for module in args:
|
||||
for item in module.__dict__:
|
||||
if hasattr(item, "__new__") and hasattr(item, "__name__"):
|
||||
import_class(item)
|
||||
|
||||
|
||||
def encode_object(obj, traversal_stack, generator_func, on_unknown=None):
|
||||
values = obj.bson_encode()
|
||||
class_name = obj.__class__.__name__
|
||||
values["$$__CLASS_NAME__$$"] = class_name
|
||||
return encode_document(values, traversal_stack, obj,
|
||||
generator_func, on_unknown)
|
||||
|
||||
|
||||
def encode_object_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown):
|
||||
return b"\x03" + encode_cstring(name) + \
|
||||
encode_object(value, traversal_stack,
|
||||
generator_func=generator_func, on_unknown=on_unknown)
|
||||
|
||||
|
||||
class _EmptyClass(object):
|
||||
pass
|
||||
|
||||
|
||||
def decode_object(raw_values):
|
||||
global classes
|
||||
class_name = raw_values["$$__CLASS_NAME__$$"]
|
||||
try:
|
||||
cls = classes[class_name]
|
||||
except KeyError:
|
||||
raise MissingClassDefinition(class_name)
|
||||
|
||||
retval = _EmptyClass()
|
||||
retval.__class__ = cls
|
||||
alt_retval = retval.bson_init(raw_values)
|
||||
return alt_retval or retval
|
||||
|
||||
|
||||
def encode_string(value):
|
||||
value = value.encode("utf-8")
|
||||
length = len(value)
|
||||
return struct.pack("<i%dsb" % (length,), length + 1, value, 0)
|
||||
|
||||
|
||||
def encode_cstring(value):
|
||||
if not isinstance(value, bytes):
|
||||
value = text_type(value).encode("utf-8")
|
||||
if b"\x00" in value:
|
||||
raise ValueError("Element names may not include NUL bytes.")
|
||||
# A NUL byte is used to delimit our string, accepting one would cause
|
||||
# our string to terminate early.
|
||||
return value + b"\x00"
|
||||
|
||||
|
||||
def encode_binary(value, binary_subtype=0):
|
||||
length = len(value)
|
||||
return struct.pack("<ib", length, binary_subtype) + value
|
||||
|
||||
|
||||
def encode_double(value):
|
||||
return struct.pack("<d", value)
|
||||
|
||||
|
||||
ELEMENT_TYPES = {
|
||||
0x01: "double",
|
||||
0x02: "string",
|
||||
0x03: "document",
|
||||
0x04: "array",
|
||||
0x05: "binary",
|
||||
0x07: "object_id",
|
||||
0x08: "boolean",
|
||||
0x09: "UTCdatetime",
|
||||
0x0A: "none",
|
||||
0x10: "int32",
|
||||
0x11: "uint64",
|
||||
0x12: "int64"
|
||||
}
|
||||
|
||||
|
||||
def encode_double_element(name, value):
|
||||
return b"\x01" + encode_cstring(name) + encode_double(value)
|
||||
|
||||
|
||||
def encode_string_element(name, value):
|
||||
return b"\x02" + encode_cstring(name) + encode_string(value)
|
||||
|
||||
|
||||
def _is_string(value):
|
||||
if isinstance(value, text_type):
|
||||
return True
|
||||
elif isinstance(value, str) or isinstance(value, bytes):
|
||||
try:
|
||||
unicode(value, errors='strict')
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def encode_value(name, value, buf, traversal_stack,
|
||||
generator_func, on_unknown=None):
|
||||
if isinstance(value, bool):
|
||||
buf.write(encode_boolean_element(name, value))
|
||||
elif isinstance(value, integer_types):
|
||||
if value < -0x80000000 or 0x7FFFFFFFFFFFFFFF >= value > 0x7fffffff:
|
||||
buf.write(encode_int64_element(name, value))
|
||||
elif value > 0x7FFFFFFFFFFFFFFF:
|
||||
if value > 0xFFFFFFFFFFFFFFFF:
|
||||
raise Exception("BSON format supports only int value < %s" % 0xFFFFFFFFFFFFFFFF)
|
||||
buf.write(encode_uint64_element(name, value))
|
||||
else:
|
||||
buf.write(encode_int32_element(name, value))
|
||||
elif isinstance(value, float):
|
||||
buf.write(encode_double_element(name, value))
|
||||
elif _is_string(value):
|
||||
buf.write(encode_string_element(name, value))
|
||||
elif isinstance(value, str) or isinstance(value, bytes):
|
||||
buf.write(encode_binary_element(name, value))
|
||||
elif isinstance(value, UUID):
|
||||
buf.write(encode_binary_element(name, value.bytes, binary_subtype=4))
|
||||
elif isinstance(value, datetime):
|
||||
buf.write(encode_utc_datetime_element(name, value))
|
||||
elif value is None:
|
||||
buf.write(encode_none_element(name, value))
|
||||
elif isinstance(value, dict):
|
||||
buf.write(encode_document_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown))
|
||||
elif isinstance(value, list) or isinstance(value, tuple):
|
||||
buf.write(encode_array_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown))
|
||||
elif isinstance(value, BSONCoding):
|
||||
buf.write(encode_object_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown))
|
||||
elif isinstance(value, Decimal):
|
||||
buf.write(encode_double_element(name, float(value)))
|
||||
else:
|
||||
if on_unknown is not None:
|
||||
encode_value(name, on_unknown(value), buf, traversal_stack,
|
||||
generator_func, on_unknown)
|
||||
else:
|
||||
raise UnknownSerializerError(name, value)
|
||||
|
||||
|
||||
def encode_document(obj, traversal_stack, traversal_parent=None,
|
||||
generator_func=None, on_unknown=None):
|
||||
buf = StringIO()
|
||||
key_iter = iterkeys(obj)
|
||||
if generator_func is not None:
|
||||
key_iter = generator_func(obj, traversal_stack)
|
||||
for name in key_iter:
|
||||
value = obj[name]
|
||||
traversal_stack.append(TraversalStep(traversal_parent or obj, name))
|
||||
encode_value(name, value, buf, traversal_stack,
|
||||
generator_func, on_unknown)
|
||||
traversal_stack.pop()
|
||||
e_list = buf.getvalue()
|
||||
e_list_length = len(e_list)
|
||||
return struct.pack("<i%dsb" % (e_list_length,),
|
||||
e_list_length + 4 + 1, e_list, 0)
|
||||
|
||||
|
||||
def encode_array(array, traversal_stack, traversal_parent=None,
|
||||
generator_func=None, on_unknown=None):
|
||||
buf = StringIO()
|
||||
for i in xrange(0, len(array)):
|
||||
value = array[i]
|
||||
traversal_stack.append(TraversalStep(traversal_parent or array, i))
|
||||
encode_value(str(i), value, buf, traversal_stack,
|
||||
generator_func, on_unknown)
|
||||
traversal_stack.pop()
|
||||
e_list = buf.getvalue()
|
||||
e_list_length = len(e_list)
|
||||
return struct.pack("<i%dsb" % (e_list_length,),
|
||||
e_list_length + 4 + 1, e_list, 0)
|
||||
|
||||
|
||||
def decode_binary_subtype(value, binary_subtype):
|
||||
if binary_subtype in [0x03, 0x04]: # legacy UUID, UUID
|
||||
return UUID(bytes=value)
|
||||
return value
|
||||
|
||||
|
||||
def decode_document(data, base, as_array=False):
|
||||
# Create all the struct formats we might use.
|
||||
double_struct = struct.Struct("<d")
|
||||
int_struct = struct.Struct("<i")
|
||||
char_struct = struct.Struct("<b")
|
||||
long_struct = struct.Struct("<q")
|
||||
uint64_struct = struct.Struct("<Q")
|
||||
int_char_struct = struct.Struct("<ib")
|
||||
|
||||
length = struct.unpack("<i", data[base:base + 4])[0]
|
||||
end_point = base + length
|
||||
if data[end_point - 1] not in ('\0', 0):
|
||||
raise ValueError('missing null-terminator in document')
|
||||
base += 4
|
||||
retval = [] if as_array else {}
|
||||
decode_name = not as_array
|
||||
|
||||
while base < end_point - 1:
|
||||
|
||||
element_type = char_struct.unpack(data[base:base + 1])[0]
|
||||
|
||||
if PY3:
|
||||
ll = data.index(0, base + 1) + 1
|
||||
else:
|
||||
ll = data.index("\x00", base + 1) + 1
|
||||
if decode_name:
|
||||
name = data[base + 1:ll - 1]
|
||||
try:
|
||||
name = name.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
else:
|
||||
name = None
|
||||
base = ll
|
||||
|
||||
if element_type == 0x01: # double
|
||||
value = double_struct.unpack(data[base: base + 8])[0]
|
||||
base += 8
|
||||
elif element_type == 0x02: # string
|
||||
length = int_struct.unpack(data[base:base + 4])[0]
|
||||
value = data[base + 4: base + 4 + length - 1]
|
||||
value = value.decode("utf-8")
|
||||
base += 4 + length
|
||||
elif element_type == 0x03: # document
|
||||
base, value = decode_document(data, base)
|
||||
elif element_type == 0x04: # array
|
||||
base, value = decode_document(data, base, as_array=True)
|
||||
elif element_type == 0x05: # binary
|
||||
length, binary_subtype = int_char_struct.unpack(
|
||||
data[base:base + 5])
|
||||
value = data[base + 5:base + 5 + length]
|
||||
value = decode_binary_subtype(value, binary_subtype)
|
||||
base += 5 + length
|
||||
elif element_type == 0x07: # object_id
|
||||
value = b2a_hex(data[base:base + 12])
|
||||
base += 12
|
||||
elif element_type == 0x08: # boolean
|
||||
value = bool(char_struct.unpack(data[base:base + 1])[0])
|
||||
base += 1
|
||||
elif element_type == 0x09: # UTCdatetime
|
||||
value = datetime.fromtimestamp(
|
||||
long_struct.unpack(data[base:base + 8])[0] / 1000.0, utc)
|
||||
base += 8
|
||||
elif element_type == 0x0A: # none
|
||||
value = None
|
||||
elif element_type == 0x10: # int32
|
||||
value = int_struct.unpack(data[base:base + 4])[0]
|
||||
base += 4
|
||||
elif element_type == 0x11: # uint64
|
||||
value = uint64_struct.unpack(data[base:base + 8])[0]
|
||||
base += 8
|
||||
elif element_type == 0x12: # int64
|
||||
value = long_struct.unpack(data[base:base + 8])[0]
|
||||
base += 8
|
||||
|
||||
if as_array:
|
||||
retval.append(value)
|
||||
else:
|
||||
retval[name] = value
|
||||
if "$$__CLASS_NAME__$$" in retval:
|
||||
retval = decode_object(retval)
|
||||
return end_point, retval
|
||||
|
||||
|
||||
def encode_document_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown):
|
||||
return b"\x03" + encode_cstring(name) + \
|
||||
encode_document(value, traversal_stack,
|
||||
generator_func=generator_func, on_unknown=on_unknown)
|
||||
|
||||
|
||||
def encode_array_element(name, value, traversal_stack,
|
||||
generator_func, on_unknown):
|
||||
return b"\x04" + encode_cstring(name) + \
|
||||
encode_array(value, traversal_stack,
|
||||
generator_func=generator_func, on_unknown=on_unknown)
|
||||
|
||||
|
||||
def encode_binary_element(name, value, binary_subtype=0):
|
||||
return b"\x05" + encode_cstring(name) + encode_binary(value, binary_subtype=binary_subtype)
|
||||
|
||||
|
||||
def encode_boolean_element(name, value):
|
||||
return b"\x08" + encode_cstring(name) + struct.pack("<b", value)
|
||||
|
||||
|
||||
def encode_utc_datetime_element(name, value):
|
||||
if value.tzinfo is None:
|
||||
warnings.warn(MissingTimezoneWarning(), None, 4)
|
||||
value = int(round(calendar.timegm(value.utctimetuple()) * 1000 +
|
||||
(value.microsecond / 1000.0)))
|
||||
return b"\x09" + encode_cstring(name) + struct.pack("<q", value)
|
||||
|
||||
|
||||
def encode_none_element(name, value):
|
||||
return b"\x0a" + encode_cstring(name)
|
||||
|
||||
|
||||
def encode_int32_element(name, value):
|
||||
value = struct.pack("<i", value)
|
||||
return b"\x10" + encode_cstring(name) + value
|
||||
|
||||
|
||||
def encode_uint64_element(name, value):
|
||||
return b"\x11" + encode_cstring(name) + struct.pack("<Q", value)
|
||||
|
||||
|
||||
def encode_int64_element(name, value):
|
||||
return b"\x12" + encode_cstring(name) + struct.pack("<q", value)
|
||||
|
||||
|
||||
def encode_object_id_element(name, value):
|
||||
return b"\x07" + encode_cstring(name) + value
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
from struct import unpack
|
||||
|
||||
from six import BytesIO, b
|
||||
|
||||
from . import dumps, loads
|
||||
|
||||
|
||||
def _bintoint(data):
|
||||
return unpack("<i", data)[0]
|
||||
|
||||
|
||||
def sendobj(self, obj):
|
||||
"""
|
||||
Atomically send a BSON message.
|
||||
"""
|
||||
data = dumps(obj)
|
||||
self.sendall(data)
|
||||
|
||||
|
||||
def recvobj(self):
|
||||
"""
|
||||
Atomic read of a BSON message.
|
||||
|
||||
This function either returns a dict, None, or raises a socket error.
|
||||
|
||||
If the return value is None, it means the socket is closed by the other side.
|
||||
"""
|
||||
sock_buf = self.recvbytes(4)
|
||||
if sock_buf is None:
|
||||
return None
|
||||
|
||||
message_length = _bintoint(sock_buf.getvalue())
|
||||
sock_buf = self.recvbytes(message_length - 4, sock_buf)
|
||||
if sock_buf is None:
|
||||
return None
|
||||
|
||||
retval = loads(sock_buf.getvalue())
|
||||
return retval
|
||||
|
||||
|
||||
def recvbytes(self, bytes_needed, sock_buf = None):
|
||||
"""
|
||||
Atomic read of bytes_needed bytes.
|
||||
|
||||
This function either returns exactly the nmber of bytes requested in a
|
||||
StringIO buffer, None, or raises a socket error.
|
||||
|
||||
If the return value is None, it means the socket is closed by the other side.
|
||||
"""
|
||||
if sock_buf is None:
|
||||
sock_buf = BytesIO()
|
||||
bytes_count = 0
|
||||
while bytes_count < bytes_needed:
|
||||
chunk = self.recv(min(bytes_needed - bytes_count, 32768))
|
||||
part_count = len(chunk)
|
||||
|
||||
if type(chunk) == str:
|
||||
chunk = b(chunk)
|
||||
|
||||
if part_count < 1:
|
||||
return None
|
||||
|
||||
bytes_count += part_count
|
||||
sock_buf.write(chunk)
|
||||
|
||||
return sock_buf
|
|
@ -0,0 +1,309 @@
|
|||
# Copyright 2009-2015 MongoDB, Inc.
|
||||
# Modifications copyright (C) 2018 Gabriel Leopoldino
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Tools for working with MongoDB `ObjectIds
|
||||
<http://dochub.mongodb.org/core/objectids>`_.
|
||||
"""
|
||||
|
||||
import binascii
|
||||
import calendar
|
||||
import datetime
|
||||
import os
|
||||
import random
|
||||
import socket
|
||||
import struct
|
||||
import threading
|
||||
import time
|
||||
|
||||
from bson.py3compat import PY3, bytes_from_hex, string_type, text_type
|
||||
from bson.tz_util import utc
|
||||
|
||||
|
||||
# fnv_1a_24 adaptation taken from MongoDB Python Driver at https://github.com/mongodb/mongo-python-driver/commit/61850357a0e0eeec1a30e1adc0bbf7ebee807358
|
||||
if PY3:
|
||||
_ord = lambda x: x
|
||||
else:
|
||||
_ord = ord
|
||||
# http://isthe.com/chongo/tech/comp/fnv/index.html#FNV-1a
|
||||
def _fnv_1a_24(data, _ord=_ord):
|
||||
"""FNV-1a 24 bit hash"""
|
||||
# http://www.isthe.com/chongo/tech/comp/fnv/index.html#xor-fold
|
||||
# Start with FNV-1a 32 bit.
|
||||
hash_size = 2 ** 32
|
||||
fnv_32_prime = 16777619
|
||||
fnv_1a_hash = 2166136261 # 32-bit FNV-1 offset basis
|
||||
for elt in data:
|
||||
fnv_1a_hash = fnv_1a_hash ^ _ord(elt)
|
||||
fnv_1a_hash = (fnv_1a_hash * fnv_32_prime) % hash_size
|
||||
# xor-fold the result to 24 bit.
|
||||
return (fnv_1a_hash >> 24) ^ (fnv_1a_hash & 0xffffff)
|
||||
|
||||
def _machine_bytes():
|
||||
"""Get the machine portion of an ObjectId.
|
||||
"""
|
||||
# gethostname() returns a unicode string in python 3.x
|
||||
# We only need 3 bytes, and _fnv_1a_24 returns a 24 bit integer.
|
||||
# Remove the padding byte.
|
||||
return struct.pack("<I", _fnv_1a_24(socket.gethostname().encode()))[:3]
|
||||
|
||||
|
||||
class InvalidId(ValueError):
|
||||
"""Raised when trying to create an ObjectId from invalid data.
|
||||
"""
|
||||
|
||||
def _raise_invalid_id(oid):
|
||||
raise InvalidId(
|
||||
"%r is not a valid ObjectId, it must be a 12-byte input"
|
||||
" or a 24-character hex string" % oid)
|
||||
|
||||
|
||||
class ObjectId(object):
|
||||
"""A MongoDB ObjectId.
|
||||
"""
|
||||
|
||||
_inc = random.randint(0, 0xFFFFFF)
|
||||
_inc_lock = threading.Lock()
|
||||
|
||||
_machine_bytes = _machine_bytes()
|
||||
|
||||
__slots__ = ('__id')
|
||||
|
||||
_type_marker = 7
|
||||
|
||||
def __init__(self, oid=None):
|
||||
"""Initialize a new ObjectId.
|
||||
|
||||
An ObjectId is a 12-byte unique identifier consisting of:
|
||||
|
||||
- a 4-byte value representing the seconds since the Unix epoch,
|
||||
- a 3-byte machine identifier,
|
||||
- a 2-byte process id, and
|
||||
- a 3-byte counter, starting with a random value.
|
||||
|
||||
By default, ``ObjectId()`` creates a new unique identifier. The
|
||||
optional parameter `oid` can be an :class:`ObjectId`, or any 12
|
||||
:class:`bytes` or, in Python 2, any 12-character :class:`str`.
|
||||
|
||||
For example, the 12 bytes b'foo-bar-quux' do not follow the ObjectId
|
||||
specification but they are acceptable input::
|
||||
|
||||
>>> ObjectId(b'foo-bar-quux')
|
||||
ObjectId('666f6f2d6261722d71757578')
|
||||
|
||||
`oid` can also be a :class:`unicode` or :class:`str` of 24 hex digits::
|
||||
|
||||
>>> ObjectId('0123456789ab0123456789ab')
|
||||
ObjectId('0123456789ab0123456789ab')
|
||||
>>>
|
||||
>>> # A u-prefixed unicode literal:
|
||||
>>> ObjectId(u'0123456789ab0123456789ab')
|
||||
ObjectId('0123456789ab0123456789ab')
|
||||
|
||||
Raises :class:`~bson.errors.InvalidId` if `oid` is not 12 bytes nor
|
||||
24 hex digits, or :class:`TypeError` if `oid` is not an accepted type.
|
||||
|
||||
:Parameters:
|
||||
- `oid` (optional): a valid ObjectId.
|
||||
|
||||
.. mongodoc:: objectids
|
||||
"""
|
||||
if oid is None:
|
||||
self.__generate()
|
||||
elif isinstance(oid, bytes) and len(oid) == 12:
|
||||
self.__id = oid
|
||||
else:
|
||||
self.__validate(oid)
|
||||
|
||||
@classmethod
|
||||
def from_datetime(cls, generation_time):
|
||||
"""Create a dummy ObjectId instance with a specific generation time.
|
||||
|
||||
This method is useful for doing range queries on a field
|
||||
containing :class:`ObjectId` instances.
|
||||
|
||||
.. warning::
|
||||
It is not safe to insert a document containing an ObjectId
|
||||
generated using this method. This method deliberately
|
||||
eliminates the uniqueness guarantee that ObjectIds
|
||||
generally provide. ObjectIds generated with this method
|
||||
should be used exclusively in queries.
|
||||
|
||||
`generation_time` will be converted to UTC. Naive datetime
|
||||
instances will be treated as though they already contain UTC.
|
||||
|
||||
An example using this helper to get documents where ``"_id"``
|
||||
was generated before January 1, 2010 would be:
|
||||
|
||||
>>> gen_time = datetime.datetime(2010, 1, 1)
|
||||
>>> dummy_id = ObjectId.from_datetime(gen_time)
|
||||
>>> result = collection.find({"_id": {"$lt": dummy_id}})
|
||||
|
||||
:Parameters:
|
||||
- `generation_time`: :class:`~datetime.datetime` to be used
|
||||
as the generation time for the resulting ObjectId.
|
||||
"""
|
||||
if generation_time.utcoffset() is not None:
|
||||
generation_time = generation_time - generation_time.utcoffset()
|
||||
timestamp = calendar.timegm(generation_time.timetuple())
|
||||
oid = struct.pack(
|
||||
">i", int(timestamp)) + b"\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
return cls(oid)
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, oid):
|
||||
"""Checks if a `oid` string is valid or not.
|
||||
|
||||
:Parameters:
|
||||
- `oid`: the object id to validate
|
||||
|
||||
.. versionadded:: 2.3
|
||||
"""
|
||||
if not oid:
|
||||
return False
|
||||
|
||||
try:
|
||||
ObjectId(oid)
|
||||
return True
|
||||
except (InvalidId, TypeError):
|
||||
return False
|
||||
|
||||
def __generate(self):
|
||||
"""Generate a new value for this ObjectId.
|
||||
"""
|
||||
|
||||
# 4 bytes current time
|
||||
oid = struct.pack(">i", int(time.time()))
|
||||
|
||||
# 3 bytes machine
|
||||
oid += ObjectId._machine_bytes
|
||||
|
||||
# 2 bytes pid
|
||||
oid += struct.pack(">H", os.getpid() % 0xFFFF)
|
||||
|
||||
# 3 bytes inc
|
||||
with ObjectId._inc_lock:
|
||||
oid += struct.pack(">i", ObjectId._inc)[1:4]
|
||||
ObjectId._inc = (ObjectId._inc + 1) % 0xFFFFFF
|
||||
|
||||
self.__id = oid
|
||||
|
||||
def __validate(self, oid):
|
||||
"""Validate and use the given id for this ObjectId.
|
||||
|
||||
Raises TypeError if id is not an instance of
|
||||
(:class:`basestring` (:class:`str` or :class:`bytes`
|
||||
in python 3), ObjectId) and InvalidId if it is not a
|
||||
valid ObjectId.
|
||||
|
||||
:Parameters:
|
||||
- `oid`: a valid ObjectId
|
||||
"""
|
||||
if isinstance(oid, ObjectId):
|
||||
self.__id = oid.binary
|
||||
# bytes or unicode in python 2, str in python 3
|
||||
elif isinstance(oid, string_type):
|
||||
if len(oid) == 24:
|
||||
try:
|
||||
self.__id = bytes_from_hex(oid)
|
||||
except (TypeError, ValueError):
|
||||
_raise_invalid_id(oid)
|
||||
else:
|
||||
_raise_invalid_id(oid)
|
||||
else:
|
||||
raise TypeError("id must be an instance of (bytes, %s, ObjectId), "
|
||||
"not %s" % (text_type.__name__, type(oid)))
|
||||
|
||||
@property
|
||||
def binary(self):
|
||||
"""12-byte binary representation of this ObjectId.
|
||||
"""
|
||||
return self.__id
|
||||
|
||||
@property
|
||||
def generation_time(self):
|
||||
"""A :class:`datetime.datetime` instance representing the time of
|
||||
generation for this :class:`ObjectId`.
|
||||
|
||||
The :class:`datetime.datetime` is timezone aware, and
|
||||
represents the generation time in UTC. It is precise to the
|
||||
second.
|
||||
"""
|
||||
timestamp = struct.unpack(">i", self.__id[0:4])[0]
|
||||
return datetime.datetime.fromtimestamp(timestamp, utc)
|
||||
|
||||
def __getstate__(self):
|
||||
"""return value of object for pickling.
|
||||
needed explicitly because __slots__() defined.
|
||||
"""
|
||||
return self.__id
|
||||
|
||||
def __setstate__(self, value):
|
||||
"""explicit state set from pickling
|
||||
"""
|
||||
# Provide backwards compatability with OIDs
|
||||
# pickled with pymongo-1.9 or older.
|
||||
if isinstance(value, dict):
|
||||
oid = value["_ObjectId__id"]
|
||||
else:
|
||||
oid = value
|
||||
# ObjectIds pickled in python 2.x used `str` for __id.
|
||||
# In python 3.x this has to be converted to `bytes`
|
||||
# by encoding latin-1.
|
||||
if PY3 and isinstance(oid, text_type):
|
||||
self.__id = oid.encode('latin-1')
|
||||
else:
|
||||
self.__id = oid
|
||||
|
||||
def __str__(self):
|
||||
if PY3:
|
||||
return binascii.hexlify(self.__id).decode()
|
||||
return binascii.hexlify(self.__id)
|
||||
|
||||
def __repr__(self):
|
||||
return "ObjectId('%s')" % (str(self),)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id == other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id != other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id < other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id <= other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id > other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, ObjectId):
|
||||
return self.__id >= other.binary
|
||||
return NotImplemented
|
||||
|
||||
def __hash__(self):
|
||||
"""Get a hash value for this :class:`ObjectId`."""
|
||||
return hash(self.__id)
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright 2009-2015 MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
||||
# may not use this file except in compliance with the License. You
|
||||
# may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# permissions and limitations under the License.
|
||||
|
||||
"""Utility functions and definitions for python3 compatibility."""
|
||||
|
||||
import sys
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
import codecs
|
||||
import _thread as thread
|
||||
from io import BytesIO as StringIO
|
||||
MAXSIZE = sys.maxsize
|
||||
|
||||
imap = map
|
||||
|
||||
def b(s):
|
||||
# BSON and socket operations deal in binary data. In
|
||||
# python 3 that means instances of `bytes`. In python
|
||||
# 2.6 and 2.7 you can create an alias for `bytes` using
|
||||
# the b prefix (e.g. b'foo').
|
||||
# See http://python3porting.com/problems.html#nicer-solutions
|
||||
return codecs.latin_1_encode(s)[0]
|
||||
|
||||
def bytes_from_hex(h):
|
||||
return bytes.fromhex(h)
|
||||
|
||||
def iteritems(d):
|
||||
return iter(d.items())
|
||||
|
||||
def itervalues(d):
|
||||
return iter(d.values())
|
||||
|
||||
def reraise(exctype, value, trace=None):
|
||||
raise exctype(str(value)).with_traceback(trace)
|
||||
|
||||
def _unicode(s):
|
||||
return s
|
||||
|
||||
text_type = str
|
||||
string_type = str
|
||||
integer_types = int
|
||||
else:
|
||||
import thread
|
||||
|
||||
from itertools import imap
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
MAXSIZE = sys.maxint
|
||||
|
||||
def b(s):
|
||||
# See comments above. In python 2.x b('foo') is just 'foo'.
|
||||
return s
|
||||
|
||||
def bytes_from_hex(h):
|
||||
return h.decode('hex')
|
||||
|
||||
def iteritems(d):
|
||||
return d.iteritems()
|
||||
|
||||
def itervalues(d):
|
||||
return d.itervalues()
|
||||
|
||||
# "raise x, y, z" raises SyntaxError in Python 3
|
||||
exec("""def reraise(exctype, value, trace=None):
|
||||
raise exctype, str(value), trace
|
||||
""")
|
||||
|
||||
_unicode = unicode
|
||||
|
||||
string_type = basestring
|
||||
text_type = unicode
|
||||
integer_types = (int, long)
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2010-2015 MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Timezone related utilities for BSON."""
|
||||
|
||||
from datetime import (timedelta,
|
||||
tzinfo)
|
||||
|
||||
ZERO = timedelta(0)
|
||||
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset timezone, in minutes east from UTC.
|
||||
|
||||
Implementation based from the Python `standard library documentation
|
||||
<http://docs.python.org/library/datetime.html#tzinfo-objects>`_.
|
||||
Defining __getinitargs__ enables pickling / copying.
|
||||
"""
|
||||
|
||||
def __init__(self, offset, name):
|
||||
if isinstance(offset, timedelta):
|
||||
self.__offset = offset
|
||||
else:
|
||||
self.__offset = timedelta(minutes=offset)
|
||||
self.__name = name
|
||||
|
||||
def __getinitargs__(self):
|
||||
return self.__offset, self.__name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
|
||||
utc = FixedOffset(0, "UTC")
|
||||
"""Fixed offset timezone representing UTC."""
|
|
@ -0,0 +1,567 @@
|
|||
# coding=utf-8
|
||||
from __future__ import absolute_import
|
||||
import bson
|
||||
import logging
|
||||
import threading
|
||||
import sarge
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import requests
|
||||
import backoff
|
||||
from collections import deque
|
||||
|
||||
from octoprint_obico.nozzlecam import NozzleCam
|
||||
try:
|
||||
import queue
|
||||
except ImportError:
|
||||
import Queue as queue
|
||||
|
||||
from .ws import WebSocketClient, WebSocketConnectionException
|
||||
from .pause_resume_sequence import PauseResumeGCodeSequence
|
||||
from .utils import (
|
||||
ExpoBackoff, SentryWrapper, pi_version,
|
||||
OctoPrintSettingsUpdater, run_in_thread,
|
||||
server_request, migrate_tsd_settings, octoprint_webcam_settings)
|
||||
from .lib.error_stats import error_stats
|
||||
from .lib import alert_queue
|
||||
from .print_job_tracker import PrintJobTracker
|
||||
from .janus import JanusConn
|
||||
from .remote_status import RemoteStatus
|
||||
from .webcam_capture import JpegPoster, capture_jpeg
|
||||
from .file_downloader import FileDownloader
|
||||
from .tunnel import LocalTunnel
|
||||
from . import plugin_apis
|
||||
from .client_conn import ClientConn
|
||||
import zlib
|
||||
from .printer_discovery import PrinterDiscovery
|
||||
from .gcode_hooks import GCodeHooks
|
||||
from .gcode_preprocessor import GcodePreProcessorWrapper
|
||||
from .file_operations import FileOperations
|
||||
|
||||
import octoprint.plugin
|
||||
|
||||
__python_version__ = 3 if sys.version_info >= (3, 0) else 2
|
||||
|
||||
_logger = logging.getLogger('octoprint.plugins.obico')
|
||||
|
||||
POST_STATUS_INTERVAL_SECONDS = 50.0
|
||||
|
||||
DEFAULT_LINKED_PRINTER = {'is_pro': False}
|
||||
|
||||
_print_job_tracker = PrintJobTracker()
|
||||
|
||||
|
||||
|
||||
class ObicoPlugin(
|
||||
octoprint.plugin.SettingsPlugin,
|
||||
octoprint.plugin.StartupPlugin,
|
||||
octoprint.plugin.ShutdownPlugin,
|
||||
octoprint.plugin.EventHandlerPlugin,
|
||||
octoprint.plugin.AssetPlugin,
|
||||
octoprint.plugin.SimpleApiPlugin,
|
||||
octoprint.plugin.BlueprintPlugin,
|
||||
octoprint.plugin.TemplatePlugin,):
|
||||
|
||||
def __init__(self):
|
||||
global _print_job_tracker
|
||||
|
||||
self.shutting_down = False
|
||||
self.ss = None
|
||||
self.status_posted_to_server_ts = 0
|
||||
self.message_queue_to_server = queue.Queue(maxsize=1000)
|
||||
self.status_update_booster = 0 # update status at higher frequency when self.status_update_booster > 0
|
||||
self.status_update_lock = threading.RLock()
|
||||
self.remote_status = RemoteStatus()
|
||||
self.pause_resume_sequence = PauseResumeGCodeSequence()
|
||||
self.gcode_hooks = GCodeHooks(self, _print_job_tracker)
|
||||
self.gcode_preprocessor = GcodePreProcessorWrapper(self)
|
||||
self.octoprint_settings_updater = OctoPrintSettingsUpdater(self)
|
||||
self.jpeg_poster = JpegPoster(self)
|
||||
self.file_downloader = FileDownloader(self, _print_job_tracker)
|
||||
self.linked_printer = DEFAULT_LINKED_PRINTER
|
||||
self.local_tunnel = None
|
||||
self.janus = JanusConn(self)
|
||||
self.client_conn = ClientConn(self)
|
||||
self.discovery = None
|
||||
self.bailed_because_tsd_plugin_running = False
|
||||
self.printer_events_posted = dict()
|
||||
self.file_operations = FileOperations(self)
|
||||
self.nozzlecam = NozzleCam(self)
|
||||
|
||||
|
||||
# ~~ Custom event registration
|
||||
|
||||
def register_custom_events(*args, **kwargs):
|
||||
return ["command"]
|
||||
|
||||
# ~~ SettingsPlugin mixin
|
||||
|
||||
def get_settings_defaults(self):
|
||||
|
||||
return dict(
|
||||
endpoint_prefix='https://app.obico.io',
|
||||
disable_video_streaming=False,
|
||||
pi_cam_resolution='medium',
|
||||
sentry_opt='out',
|
||||
video_streaming_compatible_mode='auto',
|
||||
)
|
||||
|
||||
def on_settings_save(self, data):
|
||||
octoprint.plugin.SettingsPlugin.on_settings_save(self, data)
|
||||
alert_queue.add_alert({
|
||||
'level': 'warning',
|
||||
'cause': 'restart_required',
|
||||
'text': 'Settings saved! If you are in the setup wizard, restart OctoPrint after the setup is done. Otherwise, restart OctoPrint now for the changes to take effect.',
|
||||
'buttons': ['never', 'ok']
|
||||
}, self)
|
||||
|
||||
# ~~ AssetPlugin mixin
|
||||
|
||||
def get_assets(self):
|
||||
# Define your plugin's asset files to automatically include in the
|
||||
# core UI here.
|
||||
return dict(
|
||||
js=["js/ObicoSettings.js", "js/ObicoWizard.js"],
|
||||
css=["css/main.css"],
|
||||
less=["less/main.less"]
|
||||
)
|
||||
|
||||
# ~~ Softwareupdate hook
|
||||
|
||||
def get_update_information(self):
|
||||
# Define the configuration for your plugin to use with the Software Update
|
||||
# Plugin here. See https://github.com/foosel/OctoPrint/wiki/Plugin:-Software-Update
|
||||
# for details.
|
||||
return dict(
|
||||
obico=dict(
|
||||
displayName="Obico for OctoPrint",
|
||||
displayVersion=self._plugin_version,
|
||||
|
||||
# version check: github repository
|
||||
type="github_release",
|
||||
user="TheSpaghettiDetective",
|
||||
repo="OctoPrint-Obico",
|
||||
current=self._plugin_version,
|
||||
|
||||
# update method: pip
|
||||
pip="https://github.com/TheSpaghettiDetective/OctoPrint-Obico/archive/{target_version}.zip"
|
||||
)
|
||||
)
|
||||
# ~~ plugin APIs
|
||||
|
||||
def get_api_commands(self):
|
||||
return plugin_apis.get_api_commands()
|
||||
|
||||
def is_api_adminonly(self):
|
||||
return True
|
||||
|
||||
def on_api_command(self, command, data):
|
||||
return plugin_apis.on_api_command(self, command, data)
|
||||
|
||||
# ~~ Eventhandler mixin
|
||||
|
||||
def on_event(self, event, payload):
|
||||
global _print_job_tracker
|
||||
|
||||
self.boost_status_update()
|
||||
|
||||
try:
|
||||
if event == 'FirmwareData':
|
||||
self.octoprint_settings_updater.update_firmware(payload)
|
||||
self.post_update_to_server()
|
||||
elif event == 'SettingsUpdated':
|
||||
self.octoprint_settings_updater.update_settings()
|
||||
self.post_update_to_server()
|
||||
elif event == 'Error':
|
||||
event_data = {'event_title': 'OctoPrint Error', 'event_text': payload.get('error', 'Unknown Error'), 'event_class': 'ERROR', 'event_type': 'PRINTER_ERROR'}
|
||||
self.passthru_printer_event_to_client(event_data)
|
||||
self.post_printer_event_to_server(event_data, attach_snapshot=True, spam_tolerance_seconds=60*30)
|
||||
elif event.startswith("Print") or event in (
|
||||
'plugin_pi_support_throttle_state',
|
||||
):
|
||||
event_payload = _print_job_tracker.on_event(self, event, payload)
|
||||
if event_payload:
|
||||
self.post_update_to_server(data=event_payload)
|
||||
elif event == 'FilamentChange':
|
||||
run_in_thread(self.post_filament_change_event)
|
||||
except Exception as e:
|
||||
self.sentry.captureException()
|
||||
# ~~Shutdown Plugin
|
||||
|
||||
def on_shutdown(self):
|
||||
self.shutting_down = True
|
||||
if self.ss is not None:
|
||||
self.ss.close()
|
||||
if self.janus:
|
||||
self.janus.shutdown()
|
||||
if self.client_conn:
|
||||
self.client_conn.close()
|
||||
|
||||
|
||||
# ~~Startup Plugin
|
||||
|
||||
def on_startup(self, host, port):
|
||||
if 'thespaghettidetective' in self._plugin_manager.plugins and self._plugin_manager.plugins.get('thespaghettidetective').enabled:
|
||||
self.bailed_because_tsd_plugin_running = True
|
||||
alert_queue.add_alert({
|
||||
'level': 'error',
|
||||
'cause': 'bailed_because_tsd_plugin_running',
|
||||
'title': 'Plugin Conflicts',
|
||||
'text': 'The Obico plugin failed to start because "Access Anywhere - The Spaghetti Detective" plugin is still installed and enabled. Please remove or disable "Access Anywhere - The Spaghetti Detective" plugin and restart OctoPrint.',
|
||||
'info_url': 'https://www.obico.io/docs/user-guides/move-from-tsd-to-obico-in-octoprint',
|
||||
'buttons': ['more_info', 'ok']
|
||||
}, self, post_to_server=True)
|
||||
|
||||
# TODO: remove once all TSD users have migrated
|
||||
migrate_tsd_settings(self)
|
||||
|
||||
self.octoprint_port = port if port else self._settings.getInt(["server", "port"])
|
||||
|
||||
def on_after_startup(self):
|
||||
if self.bailed_because_tsd_plugin_running:
|
||||
return
|
||||
|
||||
main_thread = threading.Thread(target=self.main_loop)
|
||||
main_thread.daemon = True
|
||||
main_thread.start()
|
||||
|
||||
# Private methods
|
||||
|
||||
def auth_headers(self, auth_token=None):
|
||||
return {"Authorization": "Token " + self.auth_token(auth_token)}
|
||||
|
||||
def main_loop(self):
|
||||
global _print_job_tracker
|
||||
self.sentry = SentryWrapper(self)
|
||||
|
||||
if not self.is_configured() and self.canonical_endpoint_prefix():
|
||||
self.discovery = PrinterDiscovery(plugin=self)
|
||||
self.discovery.start_and_block()
|
||||
self.discovery = None
|
||||
|
||||
self.linked_printer = self.wait_for_auth_token().get('printer', DEFAULT_LINKED_PRINTER)
|
||||
|
||||
self.sentry.init_context()
|
||||
_logger.info('Linked printer: {}'.format(self.linked_printer))
|
||||
_logger.debug('Plugin settings: {}'.format(self._settings.get_all_data()))
|
||||
|
||||
# Notify plugin UI about the server connection status change
|
||||
self._plugin_manager.send_plugin_message(self._identifier, {'plugin_updated': True})
|
||||
|
||||
# Janus may take a while to start, or fail to start. Put it in thread to make sure it does not block
|
||||
janus_thread = threading.Thread(target=self.janus.start)
|
||||
janus_thread.daemon = True
|
||||
janus_thread.start()
|
||||
|
||||
url = 'http://{}:{}'.format('127.0.0.1', self.octoprint_port)
|
||||
self.local_tunnel = LocalTunnel(
|
||||
base_url=url,
|
||||
on_http_response=self.send_ws_msg_to_server,
|
||||
on_ws_message=self.send_ws_msg_to_server,
|
||||
data_dir=self.get_plugin_data_folder(),
|
||||
sentry=self.sentry)
|
||||
|
||||
jpeg_post_thread = threading.Thread(target=self.jpeg_poster.pic_post_loop)
|
||||
jpeg_post_thread.daemon = True
|
||||
jpeg_post_thread.start()
|
||||
|
||||
status_update_to_client_thread = threading.Thread(target=self.status_update_to_client_loop)
|
||||
status_update_to_client_thread.daemon = True
|
||||
status_update_to_client_thread.start()
|
||||
|
||||
message_to_server_thread = threading.Thread(target=self.message_to_server_loop)
|
||||
message_to_server_thread.daemon = True
|
||||
message_to_server_thread.start()
|
||||
|
||||
self.nozzlecam.create_nozzlecam_config()
|
||||
|
||||
while True:
|
||||
try:
|
||||
interval_in_seconds = POST_STATUS_INTERVAL_SECONDS
|
||||
if self.status_update_booster > 0:
|
||||
interval_in_seconds /= 5
|
||||
|
||||
if self.status_posted_to_server_ts < time.time() - interval_in_seconds:
|
||||
self.post_update_to_server()
|
||||
|
||||
except Exception as e:
|
||||
self.sentry.captureException()
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
def message_to_server_loop(self):
|
||||
|
||||
def on_server_ws_close(ws, close_status_code):
|
||||
if self.ss and self.ss.ws and self.ss.ws == ws:
|
||||
self._plugin_manager.send_plugin_message(self._identifier, {'plugin_updated': True})
|
||||
self.local_tunnel.close_all_octoprint_ws()
|
||||
self.ss = None
|
||||
|
||||
if close_status_code == 4321:
|
||||
alert_queue.add_alert({
|
||||
'level': 'error',
|
||||
'cause': 'shared_auth_token',
|
||||
'text': 'The same authentication token is being used by another printer. To ensure the security and correct function of your printer, please relink your printer immediately.',
|
||||
'info_url': 'https://obico.io/docs/user-guides/warnings/shared-auth-token-error/',
|
||||
'buttons': ['more_info', 'never', 'ok']
|
||||
}, self)
|
||||
_logger.error('Shared auth_token detected. Shutting down.')
|
||||
self.on_shutdown()
|
||||
|
||||
def on_server_ws_open(ws):
|
||||
if self.ss and self.ss.ws and self.ss.ws == ws:
|
||||
self._plugin_manager.send_plugin_message(self._identifier, {'plugin_updated': True})
|
||||
self.post_update_to_server() # Make sure an update is sent asap so that the server can rely on the availability of essential info such as agent.version
|
||||
|
||||
server_ws_backoff = ExpoBackoff(300)
|
||||
while self.shutting_down is False:
|
||||
try:
|
||||
(data, as_binary) = self.message_queue_to_server.get()
|
||||
|
||||
if not self.is_configured():
|
||||
_logger.warning("Plugin not configured. Not sending message to server...")
|
||||
continue
|
||||
|
||||
if not self.linked_printer.get('id'): # id is present only when auth_token is validated by the server
|
||||
_logger.warning("auth_token is not validated. Not sending message to server...")
|
||||
continue
|
||||
|
||||
error_stats.attempt('server')
|
||||
|
||||
if not self.ss or not self.ss.connected():
|
||||
self.ss = WebSocketClient(self.canonical_ws_prefix() + "/ws/dev/", token=self.auth_token(), on_ws_msg=self.process_server_msg, on_ws_close=on_server_ws_close, on_ws_open=on_server_ws_open)
|
||||
|
||||
if as_binary:
|
||||
raw = bson.dumps(data)
|
||||
_logger.debug("Sending binary ({} bytes) to server".format(len(raw)))
|
||||
else:
|
||||
_logger.debug("Sending to server: \n{}".format(data))
|
||||
if __python_version__ == 3:
|
||||
raw = json.dumps(data, default=str)
|
||||
else:
|
||||
raw = json.dumps(data, encoding='iso-8859-1', default=str)
|
||||
self.ss.send(raw, as_binary=as_binary)
|
||||
server_ws_backoff.reset()
|
||||
except WebSocketConnectionException as e:
|
||||
_logger.warning(e)
|
||||
error_stats.add_connection_error('server', self)
|
||||
if self.ss:
|
||||
self.ss.close()
|
||||
server_ws_backoff.more(e)
|
||||
except Exception as e:
|
||||
self.sentry.captureException()
|
||||
error_stats.add_connection_error('server', self)
|
||||
if self.ss:
|
||||
self.ss.close()
|
||||
server_ws_backoff.more(e)
|
||||
|
||||
def post_update_to_server(self, data=None):
|
||||
if not data:
|
||||
data = _print_job_tracker.status(self)
|
||||
self.send_ws_msg_to_server(data)
|
||||
self.status_posted_to_server_ts = time.time()
|
||||
|
||||
def send_ws_msg_to_server(self, data, as_binary=False):
|
||||
try:
|
||||
self.message_queue_to_server.put_nowait((data, as_binary))
|
||||
except queue.Full:
|
||||
_logger.warning("Server message queue is full, msg dropped")
|
||||
|
||||
def process_server_msg(self, ws, raw_data):
|
||||
global _print_job_tracker
|
||||
try:
|
||||
# raw_data can be both json or bson
|
||||
# no py2 compat way to properly detect type here
|
||||
# (w/o patching ws lib)
|
||||
try:
|
||||
msg = json.loads(raw_data)
|
||||
_logger.debug('Received: ' + raw_data)
|
||||
except ValueError:
|
||||
msg = bson.loads(raw_data)
|
||||
_logger.debug(
|
||||
'received binary message ({} bytes)'.format(len(raw_data)))
|
||||
|
||||
need_status_boost = False
|
||||
for command in msg.get('commands', []):
|
||||
self._event_bus.fire(octoprint.events.Events.PLUGIN_OBICO_COMMAND, command)
|
||||
|
||||
if command["cmd"] == "pause":
|
||||
self.pause_resume_sequence.prepare_to_pause(
|
||||
self._printer,
|
||||
self._printer_profile_manager.get_current_or_default(),
|
||||
**command.get('args'))
|
||||
self._printer.pause_print()
|
||||
|
||||
if command["cmd"] == 'cancel':
|
||||
self._printer.cancel_print()
|
||||
|
||||
if command["cmd"] == 'resume':
|
||||
self._printer.resume_print()
|
||||
|
||||
if command["cmd"] == 'print':
|
||||
self.start_print(**command.get('args'))
|
||||
|
||||
if msg.get('passthru'):
|
||||
self.client_conn.on_message_to_plugin(msg.get('passthru'))
|
||||
need_status_boost = True
|
||||
|
||||
if msg.get('janus') and self.janus:
|
||||
self.janus.pass_to_janus(msg.get('janus'))
|
||||
|
||||
if msg.get('remote_status'):
|
||||
self.remote_status.update(msg.get('remote_status'))
|
||||
need_status_boost = True
|
||||
if self.remote_status['viewing']:
|
||||
self.jpeg_poster.need_viewing_boost.set()
|
||||
|
||||
if msg.get('http.tunnel') and self.local_tunnel:
|
||||
kwargs = msg.get('http.tunnel')
|
||||
tunnel_thread = threading.Thread(
|
||||
target=self.local_tunnel.send_http_to_local,
|
||||
kwargs=kwargs)
|
||||
tunnel_thread.is_daemon = True
|
||||
tunnel_thread.start()
|
||||
|
||||
if msg.get('http.tunnelv2') and self.local_tunnel:
|
||||
kwargs = msg.get('http.tunnelv2')
|
||||
tunnel_thread = threading.Thread(
|
||||
target=self.local_tunnel.send_http_to_local_v2,
|
||||
kwargs=kwargs)
|
||||
tunnel_thread.is_daemon = True
|
||||
tunnel_thread.start()
|
||||
|
||||
if msg.get('ws.tunnel') and self.local_tunnel:
|
||||
kwargs = msg.get('ws.tunnel')
|
||||
kwargs['type_'] = kwargs.pop('type')
|
||||
self.local_tunnel.send_ws_to_local(**kwargs)
|
||||
|
||||
if need_status_boost:
|
||||
self.boost_status_update()
|
||||
except:
|
||||
self.sentry.captureException()
|
||||
|
||||
def status_update_to_client_loop(self):
|
||||
while self.shutting_down is False:
|
||||
interval = 0.75 if self.status_update_booster > 0 else 2
|
||||
time.sleep(interval)
|
||||
self.post_printer_status_to_client()
|
||||
with self.status_update_lock:
|
||||
self.status_update_booster -= 1
|
||||
|
||||
def post_printer_status_to_client(self):
|
||||
status = _print_job_tracker.status(self, status_only=True)
|
||||
# Backward compatibility: mobile apps 1.66 or earlier expects {octoprint_data: ...}
|
||||
status_data = status.get('status', {})
|
||||
status = {'status': status_data, 'octoprint_data': status_data}
|
||||
|
||||
self.client_conn.send_msg_to_client(status)
|
||||
|
||||
def boost_status_update(self):
|
||||
self.post_printer_status_to_client()
|
||||
with self.status_update_lock:
|
||||
self.status_update_booster = 20
|
||||
|
||||
def post_printer_event_to_server(self, event_data, attach_snapshot=False, spam_tolerance_seconds=60*60*24*1000):
|
||||
event_title = event_data['event_title']
|
||||
|
||||
last_sent = self.printer_events_posted.get(event_title, 0)
|
||||
if time.time() < last_sent + spam_tolerance_seconds:
|
||||
return
|
||||
|
||||
self.printer_events_posted[event_title] = time.time()
|
||||
|
||||
files = None
|
||||
if attach_snapshot:
|
||||
try:
|
||||
files = {'snapshot': capture_jpeg(self)}
|
||||
except Exception as e:
|
||||
_logger.warning('Failed to capture jpeg - ' + str(e))
|
||||
pass
|
||||
resp = server_request('POST', '/api/v1/octo/printer_events/', self, timeout=60, files=files, data=event_data, headers=self.auth_headers())
|
||||
|
||||
def post_filament_change_event(self):
|
||||
event_text = '<div><i>Printer:</i> {}</div><div><i>G-Code:</i> {}</div>'.format(
|
||||
self.linked_printer.get('name', 'Unknown printer'),
|
||||
self._printer.get_current_data().get('job', {}).get('file', {}).get('name', 'Unknown G-Code or not printing')
|
||||
)
|
||||
event_data = dict(event_title = 'Filament Change Required', event_text = event_text, event_class = 'WARNING', event_type = 'FILAMENT_CHANGE', notify='true')
|
||||
self.post_printer_event_to_server(event_data,attach_snapshot=True, spam_tolerance_seconds=60*10) # Allow to nudge the user for filament change every 10 minutes
|
||||
|
||||
def passthru_printer_event_to_client(self, event_data):
|
||||
self.send_ws_msg_to_server({'passthru': {'printer_event': event_data}})
|
||||
|
||||
# ~~ helper methods
|
||||
|
||||
def canonical_endpoint_prefix(self):
|
||||
if not self._settings.get(["endpoint_prefix"]):
|
||||
return None
|
||||
|
||||
endpoint_prefix = self._settings.get(["endpoint_prefix"]).strip()
|
||||
if endpoint_prefix.endswith('/'):
|
||||
endpoint_prefix = endpoint_prefix[:-1]
|
||||
return endpoint_prefix
|
||||
|
||||
def canonical_ws_prefix(self):
|
||||
return re.sub(r'^http', 'ws', self.canonical_endpoint_prefix())
|
||||
|
||||
def auth_token(self, token=None):
|
||||
t = token if token is not None else self._settings.get(["auth_token"])
|
||||
return t.strip() if t else ''
|
||||
|
||||
def is_configured(self):
|
||||
return self._settings.get(["endpoint_prefix"]) and self._settings.get(["auth_token"])
|
||||
|
||||
def tsd_api_status(self, auth_token=None):
|
||||
return server_request('GET', '/api/v1/octo/printer/', self, headers=self.auth_headers(auth_token=self.auth_token(auth_token)))
|
||||
|
||||
@backoff.on_predicate(backoff.expo, max_value=1200)
|
||||
def wait_for_auth_token(self):
|
||||
while not self.is_configured():
|
||||
time.sleep(1)
|
||||
|
||||
resp = self.tsd_api_status()
|
||||
if resp and resp.ok:
|
||||
return resp.json()
|
||||
else:
|
||||
return None # Triggers a backoff
|
||||
|
||||
@octoprint.plugin.BlueprintPlugin.route('/grab-discovery-secret', methods=['get', 'options'])
|
||||
def grab_discovery_secret(self):
|
||||
if self.discovery:
|
||||
return self.discovery.id_for_secret()
|
||||
|
||||
def is_blueprint_protected(self):
|
||||
# !! HEADSUP bluprint endpoints does not require authentication
|
||||
return False
|
||||
|
||||
def is_pro_user(self):
|
||||
return self.linked_printer.get('is_pro')
|
||||
|
||||
# If you want your plugin to be registered within OctoPrint under a different name than what you defined in setup.py
|
||||
# ("OctoPrint-PluginSkeleton"), you may define that here. Same goes for the other metadata derived from setup.py that
|
||||
# can be overwritten via __plugin_xyz__ control properties. See the documentation for that.
|
||||
__plugin_name__ = "Obico for OctoPrint"
|
||||
__plugin_author__ = "The Obico team"
|
||||
__plugin_url__ = "https://www.obico.io/"
|
||||
__plugin_description__ = "Securely monitor and control your OctoPrint-connected printer from anywhere for free with Obico. Get unlimited live webcam streaming, full OctoPrint remote access, printer status notifications, and a free companion mobile app for iOS and Android. The best part? AI-powered failure detection watches your prints so you don’t have to."
|
||||
__plugin_license__ = "AGPLv3"
|
||||
__plugin_pythoncompat__ = ">=2.7,<4"
|
||||
|
||||
|
||||
def __plugin_load__():
|
||||
global __plugin_implementation__
|
||||
__plugin_implementation__ = ObicoPlugin()
|
||||
|
||||
global __plugin_hooks__
|
||||
__plugin_hooks__ = {
|
||||
"octoprint.comm.protocol.gcode.queuing": __plugin_implementation__.gcode_hooks.queuing_gcode,
|
||||
"octoprint.comm.protocol.gcode.received": __plugin_implementation__.gcode_hooks.received_gcode,
|
||||
"octoprint.comm.protocol.gcode.sent": __plugin_implementation__.gcode_hooks.sent_gcode,
|
||||
"octoprint.filemanager.preprocessor": __plugin_implementation__.gcode_preprocessor.gcode_preprocessor,
|
||||
"octoprint.comm.protocol.scripts": (__plugin_implementation__.pause_resume_sequence.script_hook, 100000),
|
||||
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information,
|
||||
"octoprint.events.register_custom_events": __plugin_implementation__.register_custom_events,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue