raldone01

joined 2 years ago
[–] [email protected] 1 points 1 day ago* (last edited 1 day ago)

I don't think the promise chain is really needed here.

I used this script:

import Axios from 'axios'
import OldFS from 'fs'
import { PromiseChain } from '@feather-ink/ts-utils'

const fs = OldFS.promises

const image = process.argv[2]
const destination = `http://${process.argv[3]}/vfs/ota`
const now = process.argv[4] === 'now'
const once = process.argv[4] === 'once'

async function triggerUpdate(): Promise<void> {
  console.log('Uploading new binary')
  const file = await fs.readFile(image)

  await Axios({
    method: 'POST',
    url: destination,
    headers: {
      'Content-Type': 'application/octet-stream',
      'Content-Length': file.byteLength
    },
    data: file
  })
  console.log('Finished uploading')
}

(async () => {
  const updateChain = new PromiseChain()
  console.log(`Watching file '${image}' for changes\nWill upload to '${destination}'!`)
  if (once) {
    await triggerUpdate()
    return
  }
  if (now)
    await updateChain.enqueue(triggerUpdate)
  OldFS.watch(image, async (eventType) => {
    if (eventType !== 'change')
      return
    let succ = false
    do {
      try {
        console.log('Change detected')
        await updateChain.enqueue(triggerUpdate)
        succ = true
      } catch (e) {
        console.error(e)
        console.log('Retrying upload')
      }
    } while (!succ)
    console.log('Upload finished')
  })
})()

Relevent code on the esp:

You can ignore my cpp stuff and just put this in the handler of the stock webserver.

auto ota = vfs->addHandler(makeDirectory("ota"));
        {
          ota->addHandler(makeDirect([](auto &con) {
            if (con.req->method != HTTP_POST)
              return HandlerReturn::UNHANDLED;

            // https://github.com/espressif/esp-idf/tree/master/examples/system/ota/native_ota_example/main
            // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/ota.html
            auto updatePartition = esp_ota_get_next_update_partition(nullptr);
            if (updatePartition == nullptr)
              return sendError(con,500, "No free ota partition found!");
            esp_ota_handle_t otaHandle;
            auto err = esp_ota_begin(updatePartition, con.req->content_len, &otaHandle);
            if (err != ESP_OK)
              return sendError(con, 500, std::string{"Can't start ota update: "} + esp_err_to_name(err), true);

            int receivedBytes = 0;
            do {
              auto end = httpd_req_recv(con.req, buf.data(), buf.size());
              // ESP_LOGE(TAG, "Received %d", receivedBytes);
              // hexDump("RECV:", buf.data(), end);
              if (end <= 0) {
                esp_ota_abort(otaHandle);
                return sendError(con, 500, "Error receiving", true);
              }
              err = esp_ota_write(otaHandle, buf.data(), end);
              if (err != ESP_OK) {
                esp_ota_abort(otaHandle);
                return sendError(con, 500, std::string{"Error writing: "} + esp_err_to_name(err), true);
              }
              receivedBytes += end;
            } while (receivedBytes < con.req->content_len);

            err = esp_ota_end(otaHandle);
            if (err != ESP_OK)
              return sendError(con, 500, std::string{"Failed to end: "} + esp_err_to_name(err), true);

            err = esp_ota_set_boot_partition(updatePartition);
            if (err != ESP_OK)
              return sendError(con, 500, std::string{"esp_ota_set_boot_partition failed: "} + esp_err_to_name(err), true);
            auto ret = sendOK(con);
            FactoryResetServiceCon().reboot(1000 / portTICK_PERIOD_MS);
            return ret;
          }));
        }

I also used a custom partition table for 2 partitions so that when my program crashes it can just go back to boot the previous version.

Here it is for reference:

partitions.csv

# Name,   Type, SubType, Offset,  Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs,      data, nvs,     0x011000, 0x006000,
otadata,  data, ota,     0x017000, 0x002000,
phy_init, data, phy,     0x019000, 0x001000,
ota_0,    app,  ota_0,   0x020000, 0x1F0000,
ota_1,    app,  ota_1,   0x210000, 0x1F0000,

Note: This partition table is for a special model of the ESP32 though.

Also another disclaimer: This code does not represent my current coding abilities and may be outdated - it worked well though.

[–] [email protected] 1 points 1 day ago

Hahahah. Awesome. Have fun! You just need a simple webserver. The builtin one will do and then you use the ota functions of the ESP IDF.

[–] [email protected] 3 points 1 day ago* (last edited 1 day ago) (3 children)

Back in school my friends all flashed their mcus with 4-8MB images over serial with 115200 baud. I set up ota updates over wifi. They were all fascinated by my speedy flashes. However when I offered to help them set it up, not one was interested because their setup was working as is and slow flashing is not a "bad" thing since it gave them an excuse to do other things.

We are talking minutes vs seconds here.

The teachers were surprised by my quick progress and iterations. When I told them my "trick" the gave me bonus points but also were not interested in learning how to do ota which was very easy. A simple 20 minute first time setup would have saved sooo much time during the year.

[–] [email protected] 1 points 1 week ago* (last edited 1 week ago) (1 children)

Very interesting. I hope this passes as an actual Standart. I looked around but couldn't find information on how to enable it in the Webbrowser. It just says firefox is not supported.

Nevermind I found the extension will try it again.

[–] [email protected] 2 points 1 week ago (3 children)

I would love a if there was a standard websites would use to receive donations. An integrated browser addon that track what you visit and gives you a review before distributing funds after each month would be great. It should accumulate money to avoid transaction fees for tiny amounts.

[–] [email protected] 1 points 2 weeks ago (1 children)

I don't think a semicolon is semantically correct in this case. It suggest you want to add something. That's why it is used in programming. You are making statements.

Maybe we should use a . after return statements to signal the end of our statement stream.

[–] [email protected] 2 points 2 weeks ago* (last edited 2 weeks ago)

MacLeod is so great! Good pick.

I would probably go for Urban Conspiracy by Jules Gaia. https://music.youtube.com/watch?v=3_6ka9EV1i4

Maybe just alternate between these two.

[–] [email protected] 1 points 3 weeks ago
[–] [email protected] 1 points 3 weeks ago (2 children)

I don't see how this gives any insight into how your subscription price is being used for products relevant to you.

[–] [email protected] 5 points 3 weeks ago (4 children)

And there could be insight into whether the money is actually used for developing the relevant application.

[–] [email protected] 1 points 3 weeks ago

Seems like a fun feature. I have enabled it and will try Voyager for a bit see if I like it more than jerboa.

10
submitted 7 months ago* (last edited 7 months ago) by [email protected] to c/[email protected]
 

Hello,

I was playing around with rust and wondered if I could use const generics for toggling debug code on and off to avoid any runtime cost while still being able to toggle the DEBUG flag during runtime. I came up with a nifty solution that requires a single dynamic dispatch which many programs have anyways. It works by rewriting the vtable. It's a zero cost bool!

Is this technique worth it?

Probably not.

It's funny though.

Repo: https://github.com/raldone01/runtime_const_generics_rs/tree/v1.0.0

Full source code below:

use std::mem::transmute;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;

use replace_with::replace_with_or_abort;

trait GameObject {
  fn run(&mut self);
  fn set_debug(&mut self, flag: bool) -> &mut dyn GameObject;
}

trait GameObjectBoxExt {
  fn set_debug(self: Box<Self>, flag: bool) -> Box<dyn GameObject>;
}

impl GameObjectBoxExt for dyn GameObject {
  fn set_debug(self: Box<Self>, flag: bool) -> Box<dyn GameObject> {
    unsafe {
      let selv = Box::into_raw(self);
      let selv = (&mut *selv).set_debug(flag);
      return Box::from_raw(selv);
    }
  }
}

static ID_CNT: AtomicU32 = AtomicU32::new(0);

struct Node3D<const DEBUG: bool = false> {
  id: u32,
  cnt: u32,
}

impl Node3D {
  const TYPE_NAME: &str = "Node3D";
  fn new() -> Self {
    let id = ID_CNT.fetch_add(1, Ordering::Relaxed);
    let selv = Self { id, cnt: 0 };
    return selv;
  }
}

impl<const DEBUG: bool> GameObject for Node3D<DEBUG> {
  fn run(&mut self) {
    println!("Hello {} from {}@{}!", self.cnt, Node3D::TYPE_NAME, self.id);
    if DEBUG {
      println!("Debug {} from {}@{}!", self.cnt, Node3D::TYPE_NAME, self.id);
    }
    self.cnt += 1;
  }

  fn set_debug(&mut self, flag: bool) -> &mut dyn GameObject {
    unsafe {
      match flag {
        true => transmute::<_, &mut Node3D<true>>(self) as &mut dyn GameObject,
        false => transmute::<_, &mut Node3D<false>>(self) as &mut dyn GameObject,
      }
    }
  }
}

struct Node2D<const DEBUG: bool = false> {
  id: u32,
  cnt: u32,
}

impl Node2D {
  const TYPE_NAME: &str = "Node2D";
  fn new() -> Self {
    let id = ID_CNT.fetch_add(1, Ordering::Relaxed);
    let selv = Self { id, cnt: 0 };
    return selv;
  }
}

impl<const DEBUG: bool> GameObject for Node2D<DEBUG> {
  fn run(&mut self) {
    println!("Hello {} from {}@{}!", self.cnt, Node2D::TYPE_NAME, self.id);
    if DEBUG {
      println!("Debug {} from {}@{}!", self.cnt, Node2D::TYPE_NAME, self.id);
    }
    self.cnt += 1;
  }

  fn set_debug(&mut self, flag: bool) -> &mut dyn GameObject {
    unsafe {
      match flag {
        true => transmute::<_, &mut Node2D<true>>(self) as &mut dyn GameObject,
        false => transmute::<_, &mut Node2D<false>>(self) as &mut dyn GameObject,
      }
    }
  }
}

fn main() {
  let mut objects = Vec::new();
  for _ in 0..10 {
    objects.push(Box::new(Node3D::new()) as Box<dyn GameObject>);
    objects.push(Box::new(Node2D::new()) as Box<dyn GameObject>);
  }

  for o in 0..3 {
    for (i, object) in objects.iter_mut().enumerate() {
      let debug = (o + i) % 2 == 0;
      replace_with_or_abort(object, |object| object.set_debug(debug));
      object.run();
    }
  }
}

Note:

If anyone gets the following to work without unsafe, maybe by using the replace_with crate I would be very happy:

impl GameObjectBoxExt for dyn GameObject {
  fn set_debug(self: Box<Self>, flag: bool) -> Box<dyn GameObject> {
    unsafe {
      let selv = Box::into_raw(self);
      let selv = (&mut *selv).set_debug(flag);
      return Box::from_raw(selv);
    }
  }

I am curious to hear your thoughts.

296
submitted 7 months ago* (last edited 7 months ago) by [email protected] to c/[email protected]
 

Python allows programmers to pass additional arguments to functions via comments. Now armed with this knowledge head out and spread it to all code bases.

Feel free to use the code I wrote in your projects.

Link to the source code: https://github.com/raldone01/python_lessons_py/blob/v2.0.0/lesson_0_comments.ipynb

Image transcription:

# First we have to import comment_arguments from arglib
# Sadly arglib is not yet a standard library.
from arglib import comment_arguments


def add(*args, **kwargs):
    c_args, c_kwargs = comment_arguments()
    return sum([int(i) for i in args + c_args])


# Go ahead and change the comments.
# See how they are used as arguments.

result = add()  # 1, 2
print(result)
# comment arguments can be combined with normal function arguments
result = add(1, 2)  # 3, 4
print(result)

Output:

3
10

This is version v2.0.0 of the post: https://github.com/raldone01/python_lessons_py/tree/v2.0.0

Note:

v1.0.0 of the post can be found here: https://github.com/raldone01/python_lessons_py/tree/v1.0.0

Choosing lib as the name for my module was a bit devious. I did it because I thought if I am creating something cursed why not go all the way?

Regarding misinformation:

I thought simply posting this in programmer humor was enough. Anyways, the techniques shown here are not yet regarded best practice. Decide carefully if you want to apply the shown concepts in your own code bases.

 

I have not been able to correlate it to any event in steam. I watched the volume mixer to find out that it was steam. I tried to turn off all notifications but obviously I have missed something. There is no visual cue just this sound in the background.

I appreciate any hints.

 

I have a static ip (lets say 142.251.208.110).

I own the domain: website.tld

My registrar is godaddy.

If I want to change my nameserver godaddy won't allow me to enter a static ip. It wants a hostname. I observed that many use ns1.website.tld and ns2.website.tld.

I don't understand how this can work because ns1.website.tld would be served by my dns server which is not yet known by others.

Do I need a second domain like domains.tld where I use the registrars dns server for serving ns1.domains.tld which I can then use as the nameserver for website.tld?

I would like to avoid the registrars nameserver and avoid getting a second domain just for dns.

Thank you for your input.

 

I have two machines running docker. A (powerful) and B (tiny vps).

All my services are hosted at home on machine A. All dns records point to A. I want to point them to B and implement split horizon dns in my local network to still directly access A. Ideally A is no longer reachable from outside without going over B.

How can I forward requests on machine B to A over a tunnel like wireguard without loosing the source ip addresses?

I tried to get this working by creating two wireguard containers. I think I only need iptable rules on the WG container A but I am not sure. I am a bit confused about the iptable rules needed to get wireguard to properly forward the request through the tunnel.

What are your solutions for such a setup? Is there a better way to do this? I would also be glad for some keywords/existing solutions.

Additional info:

  • Ideally I would like to not leave docker.
  • Split horizon dns is no problem.
  • I have a static ipv6 and ipv4 on both machines.
  • I also have spare ipv6 subnets that I can use for intermediate routing.
  • I would like to avoid cloudflare.
view more: next ›