main
alex 2024-05-10 22:40:13 +02:00
parent 19844be327
commit 8027dc3716
542 changed files with 44549 additions and 6688 deletions

1
bambu-go2rtc Submodule

@ -0,0 +1 @@
Subproject commit a6418dc619af7cef6a1d2573bd32c9f4dc9d7006

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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": "",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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}`);
}
})();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/>.

View File

@ -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 dont 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

View File

@ -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

View File

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.43.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -0,0 +1 @@
{"archive_info": {}, "url": "file:///tmp/tmprmpq1j_h/OctoPrint-Obico-master.zip"}

View File

@ -0,0 +1,2 @@
[octoprint.plugin]
obico = octoprint_obico

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: poetry-core 1.2.0
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -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"

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]]

View File

@ -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)

View File

@ -0,0 +1,6 @@
# coding:utf-8
from ._typing import Details
__all__ = [
'Details'
]

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.43.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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."""

View File

@ -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 dont 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,
}

Some files were not shown because too many files have changed in this diff Show More