Skip to content

Instantly share code, notes, and snippets.

@jimfoltz
Last active July 4, 2025 12:46
Show Gist options
  • Save jimfoltz/ee791c1bdd30ce137bc23cce826096da to your computer and use it in GitHub Desktop.
Save jimfoltz/ee791c1bdd30ce137bc23cce826096da to your computer and use it in GitHub Desktop.
A local server for TiddlyWiki5 that allows saving wiki.
require 'webrick'
require 'fileutils'
BIND_ADDRESS = "127.0.0.1"
PORT = 8080
BACKUP_DIR = 'bak'
if ARGV.length != 0
root = ARGV.first.gsub('\\', '/')
else
root = '.'
end
module WEBrick
module HTTPServlet
class FileHandler
alias do_PUT do_GET
end
class DefaultFileHandler
def do_PUT(req, res)
file = "#{@config[:DocumentRoot]}#{req.path}"
res.body = ''
unless Dir.exist? BACKUP_DIR
Dir.mkdir BACKUP_DIR
end
FileUtils.cp(file, "#{BACKUP_DIR}/#{File.basename(file, '.html')}.#{Time.now.to_i.to_s}.html")
File.open(file, "w+") {|f| f.puts(req.body)}
end
def do_OPTIONS(req, res)
res['Allow'] = "GET,HEAD,OPTIONS,PUT"
res['dav'] = 'anything' # TW looks for a 'dav' header, and ignores any value
end
end
end
end
server = WEBrick::HTTPServer.new({:Port => PORT, :DocumentRoot => root, :BindAddress => BIND_ADDRESS})
# ctrl-c handler
trap "INT" do
puts "Shutting down..."
server.shutdown
end
puts "Serving on http://#{BIND_ADDRESS}:#{PORT}"
server.start
@jimfoltz
Copy link
Author

May I suggest printing the url the user needs to open? It is more convenient, and less confusing for newer users.

BIND_ADDRESS = "127.0.0.1" # localhost
PORT = 8000

server = WEBrick::HTTPServer.new({:Port => PORT, :DocumentRoot => root, :BindAddress => BIND_ADDRESS})

puts "Serving on http://#{BIND_ADDRESS}:#{PORT}"

Done - thanks.

@barrettondricka
Copy link

barrettondricka commented Jun 19, 2025

Backups are heavy on storage, because empty wikis are 2.4MB and they backup after every small edit. With heavy usage you get to a GB in about a month.

My solutions is to backup randomly every ~5th save. Of course you could use a simple counter, but I trust my luck more.

RANDOM_BACKUP_PERIOD = 5

module WEBrick
   module HTTPServlet
      class DefaultFileHandler
         def do_PUT(req, res)
            # ...
            if rand(0...RANDOM_BACKUP_PERIOD).zero? # backup
              FileUtils.cp(file, "#{BACKUP_DIR}/#{File.basename(file, '.html')}.#{Time.now.to_i.to_s}.html")
            end
            # ...
# ...

I will just leave it here for anyone who needs it, no pressure to the maintainer.

@jimfoltz
Copy link
Author

jimfoltz commented Jul 4, 2025

Backups are heavy on storage, because empty wikis are 2.4MB and they backup after every small edit. With heavy usage you get to a GB in about a month.

Thanks and I agree. There are too many backup strategies to included here. At some point maybe this should be moved to a repo so contributions can be properly considered.

I have an idea to write a server that uses the put saver to save the entire file, but then parses the json store and saves each tiddler individually. That might make sense if users want to use git as a backup and history strategy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment