Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,166 @@ server.json

# TypeScript cache
*.tsbuildinfo

### Go ###
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

### Node Patch ###
# Serverless Webpack directories
.webpack/

# Optional stylelint cache

# SvelteKit build / generate output
.svelte-kit
8 changes: 8 additions & 0 deletions .idea/php.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
"name": "Client",
"type": "go",
"request": "launch",
"mode": "auto",
"mode": "debug",
"program": "${workspaceFolder}/client/cmd/client"
}

},
{
"name": "Server",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/server/cmd/server"
}
]
}
16 changes: 16 additions & 0 deletions .zed/debug.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Project-local debug tasks
//
// For more documentation on how to configure debug tasks,
// see: https://zed.dev/docs/debugger
[
{
"label": "Run server",
"adapter": "Delve",
"request": "launch",
"mode": "debug",
// For Delve, the program can be a package name
"program": "./server/cmd/server"
// "args": [],
// "buildFlags": [],
}
]
83 changes: 83 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Development

This document outlines development tools and practices used for FriendNet.

## Philosophy

These are the philosophies that guide FriendNet development.

### Independence

FriendNet's main guiding principle is independence. A client should only ever need a server to operate, and a server
should not need any external components to operate.

Some examples of this principle:
- Server binaries are statically-linked and do not depend on the existence of any global system libraries
- Servers store their state in a local SQLite database instead of an external database server
- Clients use STUN servers provided by the server, including the server itself

### Compatibility

When it comes to the protocol and its implementation, the main guiding principle is compatibility. The very first
release of the FriendNet client should be able to connect to the latest release of the server, and vice versa. In the
absence of support for any feature, clients and servers should gracefully degrade to simpler functionality. Users often
have very good reasons for not updating, and we should not force them to do so.

In short, **we do not break compatibility**.

### Wariness of Dependencies

For the actual source code, we try to be prudent about dependencies. External dependencies are a liability, and we
should resort to the Go standard library and our own code as much as possible. For example, we did not need the full
range of STUN functionality, so we implemented our own stripped-down STUN client and server. If a dependency is
desirable, consider whether we can vendor it. For example, the [ahocorasick](ahocorasick) implementation we use for
search filtering is vendored.

First-party dependencies like the `golang.org/x/` modules or the `@solid-primitives` are fine because they are official
extensions of libraries we already use.

Dependencies outside already-trusted groups must be considered with scrutiny. Updates must also be justified, not
applied blindly.

### Documentation

From the protocol to the source code, FriendNet must be documented thoroughly. We must not assume we will be the only
implementation of the protocol, and we want to make it as easy as possible for others to both use and adapt or implement
FriendNet. Documentation must also be [user-facing](website/docs) as much as possible.

### No CGo

We do not use CGo. It makes cross-compilation hard and static linking even harder. It also adds additional build
dependencies for maintainers and packagers. CGo is banned in this project with no exceptions.

## Client Development

Developing the client involves two separate components: the client daemon and the web UI. The client daemon is written
in Go and exposes its functionality over gRPC (or gRPC-Web) and ConnectRPC. The web UI is written in TypeScript using
Solid.js as its UI framework, and communicating with the client daemon via ConnectRPC.

Separating the client's logic with its UI has a few benefits:
- No need for a separate client implementation for headless use on a server (Soulseek, in contrast, requires a
[different client](https://github.com/slskd/slskd) for headless use)
- Clear separation of concerns
- Easier implementation of alternate UIs, both web and native
- Easier automation

### Web UI Development

If you are already running a client, you can connect to it using a development build of the web UI.

To start running the web UI in development mode, run `npm run dev` in the [webui](webui) directory. You should see a URL
show up in the terminal.

Copy the debug URL, then append the following to the end of it

`?token=<client RPC token>&rpc=<client RPC URL>`

where `<client RPC token>` is the token printed at client startup, and `<client RPC URL>` is the RPC URL printed at
client startup. Your final URL should look something like this:

`http://localhost:5173?token=Aan7RbpZavqMjz3mo1wXT38YGAkUqvDigyccyRb3iPI&rpc=http://127.0.0.1:20042`

This specifies the RPC URL and token required to communicate with the client daemon. You can now enjoy hot reloading
and all the other benefits of Solid.js and Vite's development tools.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
run-rpcclient \
server-docker \
server-docker-publish \
website \
release-artifacts

help:
Expand Down Expand Up @@ -103,6 +104,9 @@ server-docker:
server-docker-publish:
make server-docker && docker push git.termer.net/termer/friendnet-server:latest

website:
cd website && npm install && npm run build

release-artifacts:
rm -rf /tmp/fn-release
mkdir /tmp/fn-release
Expand Down
2 changes: 1 addition & 1 deletion adminui/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module friendnet.org/adminui

go 1.26.2
go 1.26.5
Loading