Skip to content

Commit

Permalink
Merge branch 'master' into tgregory/distribute-cron-tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
tgregory-block authored Aug 20, 2024
2 parents ac51633 + 2fd9460 commit 0461ab6
Show file tree
Hide file tree
Showing 95 changed files with 1,588 additions and 587 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<img src="https://github.com/cashapp/misk/raw/master/misk.png" width="300">

[<img src="https://img.shields.io/maven-central/v/com.squareup.misk/misk.svg?label=latest%20release"/>](http://search.maven.org/#search%7Cga%7C1%7Ccom.squareup.misk)
[<img src="https://img.shields.io/maven-central/v/com.squareup.misk/misk.svg?label=latest%20release"/>](http://search.maven.org/#search%7Cga%7C1%7Ccom.squareup.misk) [![Mutable.ai Auto Wiki](https://img.shields.io/badge/Auto_Wiki-Mutable.ai-blue)](https://wiki.mutable.ai/cashapp/misk)

* Releases
* See most recent [public build][snap]
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ tempest2Testing = { module = "app.cash.tempest:tempest2-testing" }
tempest2TestingDocker = { module = "app.cash.tempest:tempest2-testing-docker" }
tempest2TestingInternal = { module = "app.cash.tempest:tempest2-testing-internal" }
tempest2TestingJvm = { module = "app.cash.tempest:tempest2-testing-jvm" }
tempestBom = { module = "app.cash.tempest:tempest-bom", version = "2024.03.25.180845-91fd675" }
tempestBom = { module = "app.cash.tempest:tempest-bom", version = "2024.08.07.002316-64f40ef" }
tempestTesting = { module = "app.cash.tempest:tempest-testing" }
tempestTestingDocker = { module = "app.cash.tempest:tempest-testing-docker" }
tempestTestingInternal = { module = "app.cash.tempest:tempest-testing-internal" }
Expand Down
26 changes: 21 additions & 5 deletions misk-admin/api/misk-admin.api
Original file line number Diff line number Diff line change
Expand Up @@ -931,17 +931,19 @@ public class misk/web/metadata/guice/GitHubSourceUrlProvider : misk/web/metadata
}

protected final class misk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()I
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public static synthetic fun copy$default (Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/Object;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Ljava/lang/Integer;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public static synthetic fun copy$default (Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public fun equals (Ljava/lang/Object;)Z
public final fun getClassName ()Ljava/lang/String;
public final fun getFunctionName ()Ljava/lang/String;
public final fun getLineNumber ()I
public final fun getInnerClassName ()Ljava/lang/String;
public final fun getLineNumber ()Ljava/lang/Integer;
public final fun getPackageName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand All @@ -965,6 +967,20 @@ public final class misk/web/metadata/guice/GuiceTabIndexAction : misk/web/action
public final class misk/web/metadata/guice/GuiceTabIndexAction$Companion {
}

public final class misk/web/metadata/servicegraph/ServiceGraphDashboardTabModule : misk/inject/KAbstractModule {
public fun <init> ()V
}

public final class misk/web/metadata/servicegraph/ServiceGraphTabIndexAction : misk/web/actions/WebAction {
public static final field Companion Lmisk/web/metadata/servicegraph/ServiceGraphTabIndexAction$Companion;
public static final field PATH Ljava/lang/String;
public fun <init> (Lmisk/web/v2/DashboardPageLayout;Lcom/google/inject/Provider;)V
public final fun get ()Ljava/lang/String;
}

public final class misk/web/metadata/servicegraph/ServiceGraphTabIndexAction$Companion {
}

public final class misk/web/metadata/webaction/WebActionsDashboardTabModule : misk/inject/KAbstractModule {
public fun <init> (Z)V
}
Expand Down
1 change: 1 addition & 0 deletions misk-admin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
api(project(":misk-actions"))
api(project(":misk-config"))
api(project(":misk-inject"))
api(project(":misk-service"))
api(libs.kotlinxHtml)
implementation(libs.kotlinLogging)
implementation(libs.moshiCore)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import misk.web.metadata.config.ConfigDashboardTabModule
import misk.web.metadata.config.ConfigMetadataAction
import misk.web.metadata.database.DatabaseDashboardTabModule
import misk.web.metadata.guice.GuiceDashboardTabModule
import misk.web.metadata.servicegraph.ServiceGraphDashboardTabModule
import misk.web.metadata.webaction.WebActionsDashboardTabModule
import misk.web.v2.NavbarModule

Expand Down Expand Up @@ -35,6 +36,7 @@ class AdminDashboardModule @JvmOverloads constructor(
install(ConfigDashboardTabModule(isDevelopment, configTabMode))
install(DatabaseDashboardTabModule(isDevelopment))
install(GuiceDashboardTabModule())
install(ServiceGraphDashboardTabModule())
install(WebActionsDashboardTabModule(isDevelopment))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,32 @@ import java.net.URLEncoder
*/

open class GitHubSourceUrlProvider @Inject constructor() : GuiceSourceUrlProvider {
private val sourceWithLineNumberRegex = """^([\w.]+)\.((?:\w+\$?)+)\.(\w+)\(.*:(\d+)\)$""".toRegex()
private val sourceWithLineNumberRegex = Regex("""^([\w.]+)\.((?:\w+\$?)+)\.(\w+)\(.*:(\d+)\)$""")
private val classRegex = Regex("""class\s+([a-zA-Z0-9_.$]+)""")
private val functionRegex = Regex("""(?:\w+\s+)?(?:\w+\s+)?(?:\w+\s+)?([a-zA-Z0-9_.$]+)\.([a-zA-Z0-9_.$]+)\(([^)]*)\)""")
protected data class SourceLocation(
val packageName: String,
val className: String,
val functionName: String,
val lineNumber: Int,
val innerClassName: String?,
val functionName: String?,
val lineNumber: Int?,
)
override fun urlForSource(source: String): String? {
val sourceLocation = maybeSourceLocation(source) ?: return null
return githubSearchUrl(sourceLocation)
}

protected open fun generateQuery(source: SourceLocation): String {
return """"package ${source.packageName}" ${source.className.replace('$', ' ')} ${source.functionName}"""
val sb = StringBuilder()
sb.append(""""package ${source.packageName}"""")
sb.append(" ${source.className}")
if (source.innerClassName != null) {
sb.append(" ${source.innerClassName}")
}
if (source.functionName != null) {
sb.append(" ${source.functionName}")
}
return sb.toString()
}

private fun githubSearchUrl(source: SourceLocation): String {
Expand All @@ -30,15 +42,54 @@ open class GitHubSourceUrlProvider @Inject constructor() : GuiceSourceUrlProvide
}

private fun maybeSourceLocation(source: String): SourceLocation? {
val matchResult = sourceWithLineNumberRegex.matchEntire(source)

return if (matchResult != null) {
// Extract the package, class, function names, and line number from the match groups
sourceWithLineNumberRegex.matchEntire(source)?.let {matchResult ->
val (packageName, className, functionName, lineNumberStr) = matchResult.destructured
val (innerClassName, outerClassName) = parseClass(className)
val lineNumber = lineNumberStr.toInt()
SourceLocation(packageName, className, functionName, lineNumber)
} else {
null
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = functionName,
lineNumber = lineNumber
)
}

classRegex.find(source)?.let { matchResult ->
val fullClassName = matchResult.groupValues[1]
val packageName = fullClassName.substringBeforeLast('.')
val className = fullClassName.substringAfterLast('.')
val (innerClassName, outerClassName) = parseClass(className)
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = null,
lineNumber = null
)
}

functionRegex.find(source)?.let {matchResult ->
val fullClassName = matchResult.groupValues[1]
val functionName = matchResult.groupValues[2].substringBefore('$')
val packageName = fullClassName.substringBeforeLast('.')
val className = fullClassName.substringAfterLast('.')
val (innerClassName, outerClassName) = parseClass(className)
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = functionName,
lineNumber = null
)
}

return null
}

private fun parseClass(className: String): Pair<String?, String> {
val innerClassName = if ('$' in className) className.substringAfter('$') else null
val outerClassName = if ('$' in className) className.substringBefore('$') else className
return Pair(innerClassName, outerClassName)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package misk.web.metadata.servicegraph

import misk.inject.KAbstractModule
import misk.web.WebActionModule
import misk.web.dashboard.AdminDashboard
import misk.web.dashboard.AdminDashboardAccess
import misk.web.dashboard.DashboardModule

class ServiceGraphDashboardTabModule: KAbstractModule() {
override fun configure() {
install(WebActionModule.create<ServiceGraphTabIndexAction>())
install(DashboardModule.createHotwireTab<AdminDashboard, AdminDashboardAccess>(
slug = "service-graph",
urlPathPrefix = ServiceGraphTabIndexAction.PATH,
menuCategory = "Container Admin",
menuLabel = "Service Graph",
))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package misk.web.metadata.servicegraph

import com.google.inject.Provider
import jakarta.inject.Inject
import jakarta.inject.Singleton
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.script
import kotlinx.html.unsafe
import misk.metadata.servicegraph.ServiceGraphMetadata
import misk.web.Get
import misk.web.ResponseContentType
import misk.web.actions.WebAction
import misk.web.dashboard.AdminDashboardAccess
import misk.web.mediatype.MediaTypes
import misk.web.metadata.toFormattedJson
import misk.web.v2.DashboardPageLayout
import wisp.moshi.adapter
import wisp.moshi.defaultKotlinMoshi

@Singleton
class ServiceGraphTabIndexAction @Inject constructor(
private val dashboardPageLayout: DashboardPageLayout,
private val serviceGraphMetadataProvider: Provider<ServiceGraphMetadata>,
) : WebAction {
@Get(PATH)
@ResponseContentType(MediaTypes.TEXT_HTML)
@AdminDashboardAccess
fun get(): String = dashboardPageLayout
.newBuilder()
.headBlock {
script {
src = "https://cdn.jsdelivr.net/npm/d3@7"
type = "text/javascript"
}
}
.build { _, _, _ ->
val metadataArray = defaultKotlinMoshi
.adapter<List<ServiceGraphMetadata.GraphPairs>>()
.toFormattedJson(serviceGraphMetadataProvider.get().graphVisual)

div("p-4 sm:p-6 lg:p-8") {

h1("text-3xl font-medium mb-8") {
+"""Service Graph"""
}

div("svg-container") { }

// JavaScript code in a block
script {
unsafe {
+"""
var metadata = $metadataArray;
var linkColor = "steelblue" // Define a single color for all links
drag = simulation => {
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
function linkArc(d) {
const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y);
return "M" + d.source.x + "," + d.source.y + "A" + r + "," + r + " 0 0,1 " + d.target.x + "," + d.target.y;
}
var width = 1600;
var height = 1000;
var margin = 500;
var nodes = Array.from(new Set(metadata.flatMap(l => [l.source, l.target])), id => ({id}));
var links = metadata.map(d => Object.create(d))
// Set initial positions for the nodes
nodes.forEach(node => {
node.x = Math.random() * width + margin;
node.y = Math.random() * height + margin;
});
var simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(200))
.force("charge", d3.forceManyBody().strength(-2000))
.force("x", d3.forceX().strength(0.1))
.force("y", d3.forceY().strength(0.1));
var svg = d3.select(".svg-container").append("svg")
.attr("viewBox", [-margin, -margin, width, height])
.attr("width", "100%")
.attr("height", "100%")
.attr("style", "max-width: 100%; height: auto; font: 18px sans-serif;");
// Defines arrows on the links
svg.append("defs").selectAll("marker")
.data(["link"])
.join("marker")
.attr("id", d => "arrow-" + d)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -0.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("fill", linkColor)
.attr("d", "M0,-5L10,0L0,5");
// Defines links between nodes
var link = svg.append("g")
.attr("fill", "none")
.attr("stroke-width", 2.5)
.selectAll("path")
.data(links)
.join("path")
.attr("stroke", linkColor)
.attr("marker-end", d => "url(#arrow-link)");
// Defines actual nodes
var node = svg.append("g")
.attr("fill", "currentColor")
.attr("stroke-linecap", "round")
.attr("stroke-linejoin", "round")
.selectAll("g")
.data(nodes)
.join("g")
.call(drag(simulation));
node.append("circle")
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("r", 4);
node.append("text")
.attr("x", 12)
.attr("y", "0.31em")
.text(d => d.id)
.clone(true).lower()
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", 3);
simulation.on("tick", () => {
link.attr("d", linkArc);
node.attr("transform", d => "translate(" + d.x + "," + d.y + ")");
});
Object.assign(svg.node(), {scales: {linkColor}});
""".trimIndent()
}
}
}
}

companion object {
const val PATH = "/_admin/service-graph/"
}
}
Loading

0 comments on commit 0461ab6

Please sign in to comment.